def base_taskname(taskname, packagename=None):
    """
    Extract the base name of the task.

    Many tasks in the `drizzlepac` have "compound" names such as
    'drizzlepac.sky'. This function will search for the presence of a dot
    in the input `taskname` and if found, it will return the string
    to the right of the right-most dot. If a dot is not found, it will return
    the input string.

    Parameters
    ----------
    taskname : str, None
        Full task name. If it is `None`, :py:func:`base_taskname` will
        return `None`\\ .

    packagename : str, None (Default = None)
        Package name. It is assumed that a compound task name is formed by
        concatenating `packagename` + '.' + `taskname`\\ . If `packagename`
        is not `None`, :py:func:`base_taskname` will check that the string
        to the left of the right-most dot matches `packagename` and will
        raise an `AssertionError` if the package name derived from the
        input `taskname` does not match the supplied `packagename`\\ . This
        is intended as a check for discrepancies that may arise
        during the development of the tasks. If `packagename` is `None`,
        no such check will be performed.

    Raises
    ------
    AssertionError
        Raised when package name derived from the input `taskname` does not
        match the supplied `packagename`

    """
    if not isinstance(taskname, str):
        return taskname
    indx = taskname.rfind('.')
    if indx >= 0:
        base_taskname = taskname[indx + 1:]
        pkg_name = taskname[:indx]
    else:
        base_taskname = taskname
        pkg_name = ''
    assert True if packagename is None else packagename == pkg_name
    return base_taskname


@classmethod
def pre_listener(cls):
    """
        Runs a function before a listener is triggered.
        """
    return cls.add_meta_deco({'type': 'pre_listener'})


def update_gasp_table(tt):
    """Modifies the following gasp table fields:
          1) rangeMaxPPEM changed to 65535
          2) rangeGaspBehavior changed to bit mask 0b1111 = 15"""
    if tt['gasp'].gaspRange != {(65535): 15}:
        tt['gasp'].gaspRange = {(65535): 15}
        return True
    else:
        return False


def exportFlatImage(fileName, layeredImage):
    """ Export the layered image to a unilayer image file """
    layeredImage.getFlattenLayers().save(fileName)


def _bs_classname(type_, context=None):
    """string formatting to make simple bootstrap classnames"""
    return '{}{}'.format(type_, ' {}-{}'.format(type_, context) if context
         is not None else '')


def _convert_reverse_sequence(builder, node, graph, err):
    """
    convert to CoreML Reverse Sequence Layer:
    https://github.com/apple/coremltools/blob/655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492/mlmodel/format/NeuralNetwork.proto#L3577
    """
    batch_axis = node.attrs.get('batch_axis', 1)
    time_axis = node.attrs.get('time_axis', 0)
    output_name = node.outputs[0]
    add_transpose = False
    if batch_axis > time_axis:
        output_name += '_before_reverse'
        batch_axis, time_axis = time_axis, batch_axis
        add_transpose = True
    builder.add_reverse_sequence(name=node.name, input_names=node.inputs,
        output_name=output_name, batch_axis=batch_axis, seq_axis=time_axis)
    if add_transpose:
        output_name_post = '_before_reverse'
        rank = builder._get_rank(node.inputs[0])
        if rank == -1:
            return err.unsupported_op_configuration(builder, node, graph,
                'Rank unknown for input')
        axes = list(range(rank))
        axes[batch_axis], axes[time_axis] = axes[time_axis], axes[batch_axis]
        builder.add_transpose(name=node.name + '_transpose', axes=axes,
            input_name=output_name, output_name=node.outputs[0])


def unban(email):
    """Remove an email address ban.

        This removes a specific or global email address ban, which would have
        been added with the `ban()` method.  If a ban is lifted which did not
        exist, this method does nothing.

        :param email: The text email address being unbanned or, if the string
            starts with a caret (^), the email address pattern to unban.
        :type email: str
        """


def arbitrage_factor_required(volume_EUR=9000, net_gain_EUR=100):
    """
    Return the arbitrage factor required in order to make a specified net gain
    through the changing of a specified volume.

    Kraken EUR to BTC fee:       1.6 %
    Kraken BTC withdraw fee:     0.0005 BTC (~4.36 EUR 2018-03-06T1851Z)
    LBC sell fee:                1 %
    TransferWise GBP to EUR fee: 0.35 % + 0.8 GBP (~0.90 EUR 2018-03-06T1851Z)
    """
    return (net_gain_EUR + 4.36 + 0.9) / volume_EUR + 1 + 0.016 + 0.01 + 0.0035


@staticmethod
def _symbol(rvs, crvs):
    """
        Returns X for all atoms.
        """
    return 'X'


def part_key(part):
    """Helper for MultisetPartitionTraverser.count_partitions that
    creates a key for ``part``, that only includes information which can
    affect the count for that part.  (Any irrelevant information just
    reduces the effectiveness of dynamic programming.)

    Notes
    =====

    This member function is a candidate for future exploration. There
    are likely symmetries that can be exploited to coalesce some
    ``part_key`` values, and thereby save space and improve
    performance.

    """
    rval = []
    for ps in part:
        rval.append(ps.u)
        rval.append(ps.v)
    return tuple(rval)


@staticmethod
def pad(input_sequence, length, pad_char):
    """
        Pad the given iterable, so that it is the correct length.

        :param input_sequence: Any iterable object
        :param length: The desired length of the output.
        :type length: int
        :param pad_char: The character or int to be added to short sequences
        :type pad_char: str or int
        :return: A sequence, of len `length`
        :rtype: []
        """
    if isinstance(input_sequence, str):
        input_sequence = list(input_sequence)
    if len(input_sequence) == length:
        return input_sequence
    elif len(input_sequence) > length:
        return input_sequence[:length]
    else:
        padding_len = length - len(input_sequence)
        padding = [pad_char] * padding_len
        return list(input_sequence) + list(padding)


def clk_cen_scl_slp(band, eclipse):
    """
    Return the detector clock, center, scale, and slope constants. These are
        empirically determined detector-space calibration parameters that help
        define the relationship between raw event data and its physical position
        on the detector.

    :param band: The band to return the constants for, either 'FUV' or 'NUV'.

    :type band: str

    :param eclipse: The eclipse number to return the constants for.

    :type eclipse: int

    :returns: tuple -- a tuple containing the x-clock, y-clock, x-center,
        y-center, x-scale, y-scale, x-slope, and y-slope constants.
    """
    band = band.upper()
    if band == 'FUV':
        xclk, yclk = 1997.0, 1993.0
        xcen, ycen = 7200.0, 6670.0
        xscl, yscl = 7.78, 10.73
        xslp, yslp = 0.0, 0.0
    elif band == 'NUV':
        xclk, yclk = 2007.0, 1992.0
        if eclipse >= 38150:
            yclk = 2016.0
        xcen, ycen = 7400.0, 6070.0
        xscl, yscl = 8.79, 14.01
        xslp, yslp = 0.53, 0.0
    else:
        print('Band must be either fuv or nuv ... Exiting.')
        return
    return xclk, yclk, xcen, ycen, xscl, yscl, xslp, yslp


def isnull(val):
    """Return True if `val` is null.

    Null values are None, the empty string and any False instance of
    `xotl.tools.symbols.boolean`:class:.

    Notice that 0, the empty list and other false values in Python are not
    considered null.  This allows that the CSV null (the empty string) is
    correctly treated while other sources that provide numbers (and 0 is a
    valid number) are not misinterpreted as null.

    """
    from xotl.tools.symbols import boolean
    return val in (None, '') or isinstance(val, boolean) and not val


def stagnation_energy(V):
    """Calculates the increase in enthalpy `dH` which is provided by a fluid's
    velocity `V`.

    .. math::
        \\Delta H = \\frac{V^2}{2}

    Parameters
    ----------
    V : float
        Velocity [m/s]

    Returns
    -------
    dH : float
        Incease in enthalpy [J/kg]

    Notes
    -----
    The units work out. This term is pretty small, but not trivial.

    Examples
    --------
    >>> stagnation_energy(125)
    7812.5

    References
    ----------
    .. [1] Cengel, Yunus, and John Cimbala. Fluid Mechanics: Fundamentals and
       Applications. Boston: McGraw Hill Higher Education, 2006.
    """
    return 0.5 * V * V


def bond_is_in_ring(bond):
    """Get whether the bond is in a ring of any size.
    Parameters
    ----------
    bond : rdkit.Chem.rdchem.Bond
        RDKit bond instance.
    Returns
    -------
    list
        List containing one bool only.
    """
    return [bond.IsInRing()]


def numberp(v):
    """Return true iff 'v' is a number."""
    return not isinstance(v, bool) and (isinstance(v, int) or isinstance(v,
        float))


@staticmethod
def build_username_from_suffix(username, suffix):
    """
            Transform backend username into federated username using ``suffix``

            :param unicode username: A CAS backend returned username
            :param unicode suffix: A suffix identifying the CAS backend
            :return: The federated username: ``username`` @ ``suffix``.
            :rtype: unicode
        """
    return u'%s@%s' % (username, suffix)


def empty(value) ->bool:
    """Checks if the value is empty"""
    if value is None:
        return True
    if isinstance(value, str):
        if value.strip() == '':
            return True
    if isinstance(value, list) or isinstance(value, dict):
        if len(value) == 0:
            return True
    return False


def scaleprob(prob: float, factor: float=100) ->int:
    """
    Provide consistent scaling of values into integer space. This maintains a
    minimum value of 1.

    Args:
        prob: probability value, typically from 0 to 1
        factor: scale factor

    Returns:
        scaled probability value
    """
    prob *= factor
    if prob < 1:
        return 1
    return int(prob)


@classmethod
def histogram(cls, metric_name, value, tags=None, **kwargs):
    """
        Send a histogram metric value. Histograms describe the distribution
        of the recorded values of a metric (minimum, maximum, average, count
        and the 75th, 85th, 95th and 99th percentiles).

        Args:
            metric_name (str): name of the metric to be stored
            value (int or float): the value of the metric
            tags (list or dict): miscellaneous tags to describe the value
        """
    cls.stats().histogram(cls.get_metric_name(metric_name), value=value,
        tags=cls._convert_tags(tags), **kwargs)


def _byte_pad(data, bound=4):
    """
    GLTF wants chunks aligned with 4 byte boundaries.
    This function will add padding to the end of a
    chunk of bytes so that it aligns with the passed
    boundary size.

    Parameters
    --------------
    data : bytes
      Data to be padded
    bound : int
      Length of desired boundary

    Returns
    --------------
    padded : bytes
      Result where: (len(padded) % bound) == 0
    """
    bound = int(bound)
    if len(data) % bound != 0:
        count = bound - len(data) % bound
        pad = (' ' * count).encode('utf-8')
        result = bytes().join([data, pad])
        if len(result) % bound != 0:
            raise ValueError('byte_pad failed! ori:{} res:{} pad:{} req:{}'
                .format(len(data), len(result), count, bound))
        return result
    return data


def validate_resize_factor(factor):
    """Validates resizing/scaling factor argument.

    Parameters
    ----------
    factor : float
        A factor by which the images or the bounding box annotations should be scaled.

    Returns
    ----------
    None

    Raises
    ----------
    ValueError
        When `factor` is not positive.
    """
    if factor <= 0:
        raise ValueError(
            'Resize factor must be positive. The value provided was {}'.
            format(factor))


def inheritdoc(method):
    """Set __doc__ of *method* to __doc__ of *method* in its parent class.

    Since this is used on :class:`.StringMixIn`, the "parent class" used is
    ``str``. This function can be used as a decorator.
    """
    method.__doc__ = getattr(str, method.__name__).__doc__
    return method


def optional_override(method):
    """Decorator to label methods that may optionally be overridden.

    The corresponding is_overriden function will determine if the method has been overridden in a particular class.

    """
    method._is_overriden = False
    return method


@classmethod
def get_inverted_operation_type(cls, operation_type):
    """ Get the inverted operation_type (IN->OUT / OUT->IN)

        :param operation_type: the type of transaction
        :returns: the inverted transaction type
        """
    if operation_type == cls.TYPE_IN:
        return cls.TYPE_OUT
    return cls.TYPE_IN


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


def subobject_auth_adapter(field, ctx, source_dict, target_obj):
    """
    Adapter for fields of savory_pie.fields.SubObjectResourceField, or subclasses thereof
    """
    name = field._compute_property(ctx)
    if source_dict[name] is not None:
        source = source_dict[name]['resourceUri']
    else:
        source = None
    target_subobject = getattr(target_obj, field.name)
    if target_subobject is not None:
        target = ctx.build_resource_uri(field._resource_class(target_subobject)
            )
    else:
        target = None
    return name, source, target


def getPlayersName(prompt):
    """Obtain the player's name.
    Returns what the player types in."""
    return input(prompt)


@classmethod
def get_name(cls):
    """ Returns the name of the supplier.
		"""
    return 'pickle'


@staticmethod
def supportedViews():
    """Overrides :meth:`.ControlMixin.supportedViews`. The
        ``PowerSpectrumToolBar`` is only intended to be added to
        :class:`.PowerSpectrumPanel` views.
        """
    from fsleyes.views.powerspectrumpanel import PowerSpectrumPanel
    return [PowerSpectrumPanel]


def frac_in(f, t, **kwargs):
    """
    Returns the tuple (fa, fd), where fa and fd are Polys in t.

    This is a common idiom in the Risch Algorithm functions, so we abstract
    it out here.  f should be a basic expresion, a Poly, or a tuple (fa, fd),
    where fa and fd are either basic expressions or Polys, and f == fa/fd.
    **kwargs are applied to Poly.

    """
    cancel = kwargs.pop('cancel', False)
    if type(f) is tuple:
        fa, fd = f
        f = fa.as_expr() / fd.as_expr()
    fa, fd = f.as_expr().as_numer_denom()
    fa, fd = fa.as_poly(t, extension=False, **kwargs), fd.as_poly(t,
        extension=False, **kwargs)
    if cancel:
        fa, fd = fa.cancel(fd, include=True)
    if fa is None or fd is None:
        raise ValueError(f'Could not turn {f} into a fraction in {t}.')
    return fa, fd


def UnsealAll(inst):
    """ Unseal all LocustEndpoint instances making them able to perform requests"""
    for instance in inst.BackpackPouch:
        instance.unseal


@staticmethod
def process(data):
    """
        Overridden to modify data from sources in unlimited ways.

        Default implementation passes single-source unaltered data.
        """
    return data


def filetypes():
    """Get supported archive filetypes for system import."""
    return {'npz': 'Numpy Zipped Archive'}


def google_list_style(style):
    """
    Finds out whether this is an ordered or unordered list

    :type style: dict

    :rtype: str
    """
    if 'list-style-type' in style:
        list_style = style['list-style-type']
        if list_style in ['disc', 'circle', 'square', 'none']:
            return 'ul'
    return 'ol'


def p_host_param_value(p):
    """ host_param_value : ALWAYS_REPLY_RFC1048 global_param_flag_value
                         | DDNS_HOSTNAME str_value
                         | DDNS_DOMAINNAME str_value
                         | FIXED_ADDRESS IPADDR
                         | FIXED_ADDRESS6 str_value
                         | FIXED_PREFIX6 str_value
                         | HARDWARE ETHERNET str_value
                         | HARDWARE TOKEN_RING str_value
    """
    len_p = len(p)
    if len_p == 5:
        p[0] = {p[1]: {p[2]: {p[3]: p[4]}}}
    elif len_p == 4:
        p[0] = {p[1]: {p[2]: p[3]}}
    elif len_p == 3:
        p[0] = {p[1]: p[2]}
    else:
        p[0] = {p[1]: None}


@classmethod
def fromkeys(cls, iterable, *args):
    """Create a ChainMap with a single dict created from the iterable."""
    return cls(dict.fromkeys(iterable, *args))


def cfs_to_mmday(cfs, SA_sq_ft):
    """
    cfs: (float) flow rate in cubic feet per second
    SA_sq_ft: (float) surface area in square feet
    """
    return cfs / SA_sq_ft * 24 * 60 * 60 * 304.8


def is_complex(data):
    """
    Test whether the data has a complex value in it or not.

    :param data:
    :return:
    """
    cpx_check = False
    for dd in data:
        cpx_check |= isinstance(dd, complex)
    return cpx_check


def get_itemsize(context, list_type):
    """
    Return the item size for the given list type.
    """
    llty = context.get_data_type(list_type.dtype)
    return context.get_abi_sizeof(llty)


def ancestors(node):
    """
    Returns the list of all nodes dominating the given tree node.
    This method will not work with leaf nodes, since there is no way
    to recover the parent.
    """
    results = []
    try:
        current = node.parent()
    except AttributeError:
        return results
    while current:
        results.append(current)
        current = current.parent()
    return results


def integer(number: float):
    """Convert a float to an int if they have the same value.
       For example convert 1.0 to 1."""
    try:
        int_n = int(number)
        return int_n if number == int_n else number
    except:
        return number


def init_tensorrt_params(sym, arg_params, aux_params):
    """
    Set weights in attributes of TensorRT nodes
    :param sym: Symbol, the symbol graph should contains some TensorRT nodes
    :param arg_params: arg_params
    :param aux_params: aux_params
    :return arg_params, aux_params: remaining params that are not in TensorRT nodes
    """
    arg_params = arg_params.copy()
    aux_params = aux_params.copy()
    for s in sym.get_internals():
        new_params_names = ''
        tensorrt_params = {}
        if 'subgraph_params_names' in s.list_attr():
            keys = s.list_attr()['subgraph_params_names'].split(';')
            for k in keys:
                if k in arg_params:
                    new_params_names += k + ';'
                    tensorrt_params['subgraph_param_' + k] = arg_params[k]
                    arg_params.pop(k)
                elif k in aux_params:
                    new_params_names += k + ';'
                    tensorrt_params['subgraph_param_' + k] = aux_params[k]
                    aux_params.pop(k)
            new_attrs = {}
            for k, v in tensorrt_params.items():
                new_attrs[k] = str(v.handle.value)
            if len(new_attrs) > 0:
                s._set_attr(**new_attrs)
                s._set_attr(subgraph_params_names=new_params_names[:-1])
    return arg_params, aux_params


def V_aho(x):
    """ Slightly anharmonic oscillator potential => E0 =  0.602405. """
    return x ** 2 / 2.0 + 0.2 * x ** 4


def undo(cursor, undo_tid, self_tid):
    """Undo a transaction.

        Parameters: "undo_tid", the integer tid of the transaction to undo,
        and "self_tid", the integer tid of the current transaction.

        Returns the states copied forward by the undo operation as a
        list of (oid, old_tid).

        May raise UndoError.
        """


@classmethod
def get_valid_format_order(cls, format_target, format_order=None):
    """ Checks to see if the target format string follows the proper style
        """
    format_order = format_order or cls.parse_format_order(format_target)
    cls.validate_no_token_duplicates(format_order)
    format_target = cls.remove_tokens(format_target, format_order)
    format_target = cls.remove_static_text(format_target)
    cls.validate_separator_characters(format_target)
    cls.validate_matched_parenthesis(format_target)
    return format_order


@staticmethod
def _directive_set_attribute(directive_body):
    """Directive for :py:meth:`set_attribute`"""
    instance, attribute_name, new_value = directive_body
    return setattr(instance, attribute_name, new_value)


def safe_indexing(X, indices):
    """Slice an array or dataframe. This is deprecated in sklearn"""
    if hasattr(X, 'iloc'):
        return X.iloc[indices]
    if hasattr(X, 'ndim') and X.ndim == 2:
        return X[(indices), :]
    return X[indices]


def plotAsciiConcentrationsBar(r, scale=5):
    """
    Display the floating species concentrations as an ASCII bar chart.

    Argument
    --------
        r : reference
            roadrunner instance
        scale : integer
            optional parameter to scale the ascii bar graph

    >>> teUtils.prettyTabular.plotAsciiConcentrationsBar (r, scale=20)
    """
    import math
    c = r.getFloatingSpeciesConcentrations()
    ids = r.getFloatingSpeciesIds()
    maxString = len(max(ids, key=len))
    for value in range(len(c)):
        print('{:{X}.{Y}}'.format(ids[value], X=maxString, Y=maxString),
            ':', math.trunc(scale * c[value]) * '*')


@classmethod
def hmac_sha1(cls, key):
    """Creates a new HMAC SHA1 algorithm instance.

        Args:
            key: Signer key as a byte sequence.

        Returns:
            UserImportHash: A new ``UserImportHash``.
        """
    return cls._hmac('HMAC_SHA1', key)


def learning_rate_warmup_distributed(learning_rate, epoch, warmup_epochs,
    num_workers, curr_step, steps_per_epoch):
    """Implements gradual learning rate warmup:
    `lr = initial_lr / hvd.size()` ---> `lr = initial_lr`
     `initial_lr` is the learning rate of the model optimizer at the start
     of the training. This technique was described in the paper
     "Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour".
     See https://arxiv.org/pdf/1706.02677.pdf for details.

     Inspired by Horovod's implementation:
     https://github.com/uber/horovod/blob/master/horovod/keras/callbacks.py#L202
     Math recap:
                                                   curr_step
            epoch               = full_epochs + ---------------
                                                steps_per_epoch
                                   lr     size - 1
            lr'(epoch)          = ---- * (-------- * epoch + 1)
                                  size     warmup
                                   lr
            lr'(epoch = 0)      = ----
                                  size
            lr'(epoch = warmup) = lr
    """
    if epoch > warmup_epochs:
        return learning_rate
    else:
        epoch_adjusted = float(epoch) + curr_step / steps_per_epoch
        return learning_rate / num_workers * (epoch_adjusted * (num_workers -
            1) / warmup_epochs + 1)


@staticmethod
def _node_key(layer, node_index):
    """Converts a layer and its index to a unique (immutable type) name.

        This function is used internally with `self._network_nodes`.

        # Arguments
            layer: The layer.
            node_index: The layer's position (e.g. via enumerate) in a list of
                nodes.

        # Returns
            The unique name.
        """
    return layer.name + '_ib-' + str(node_index)


def assure_list_from_str(s, sep='\n'):
    """Given a multiline string convert it to a list of return None if empty

    Parameters
    ----------
    s: str or list
    """
    if not s:
        return None
    if isinstance(s, list):
        return s
    return s.split(sep)


def fallbackSeries(requestContext, seriesList, fallback):
    """
    Takes a wildcard seriesList, and a second fallback metric.
    If the wildcard does not match any series, draws the fallback metric.

    Example::

        &target=fallbackSeries(server*.requests_per_second, constantLine(0))

    Draws a 0 line when server metric does not exist.

    """
    if len(seriesList) > 0:
        return seriesList
    else:
        return fallback


def __init_subclass__(cls, **kwargs):
    """
        An __init_subclass__ hook initializes all of the subclasses of a given
        class.

        So for each subclass, it will call this block of code on import.
        This replicates some metaclass magic without the need to be
        aware of metaclasses. Here we use this to register each subclass
        in a dict that has the `is_datasource_for` attribute. This is
        then passed into the TimeSeries Factory so we can register them.
        """
    super().__init_subclass__(**kwargs)
    if hasattr(cls, 'is_datasource_for'):
        cls._registry[cls] = cls.is_datasource_for


def ggsave(plot, *arg, **kwargs):
    """
    Save a ggplot object as an image file

    Use :meth:`ggplot.save` instead
    """
    return plot.save(*arg, **kwargs)


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 monthly_std_dev(merged_data):
    """Calculates monthly seasonal standard deviation of the timeseries data in a DataFrame

    Parameters
    ----------

    merged_data: DataFrame
        A pandas DataFrame with a datetime index and columns containing float type values.

    Returns
    -------
    DataFrame
        A pandas dataframe with a string type index of date representations and the monthly seasonal standard deviation
        as float values in the columns.

    Examples
    --------

    >>> import hydrostats.data as hd
    >>> import pandas as pd
    >>> pd.options.display.max_rows = 15

    The data URLs contain streamflow data from two different models, and are provided from the Hydrostats Github page

    >>> sfpt_url = r'https://github.com/waderoberts123/Hydrostats/raw/master/Sample_data/sfpt_data/magdalena-calamar_interim_data.csv'
    >>> glofas_url = r'https://github.com/waderoberts123/Hydrostats/raw/master/Sample_data/GLOFAS_Data/magdalena-calamar_ECMWF_data.csv'
    >>> merged_df = hd.merge_data(sfpt_url, glofas_url, column_names=('Streamflow Prediction Tool', 'GLOFAS'))

    >>> hd.monthly_std_dev(merged_df)
        Streamflow Prediction Tool       GLOFAS
    01                 2483.087791  2346.587412
    02                 2049.872689  1834.931830
    03                 2762.489873  2401.929369
    04                 4251.358318  4001.410267
    05                 5458.296296  4597.889041
    06                 4858.578846  4410.784791
    07                 4494.550854  3802.392524
    08                 4261.406429  3626.662349
    09                 4645.650733  4011.522281
    10                 4410.965472  3755.362766
    11                 4760.001179  3773.190543
    12                 4449.865762  3885.481991

    """
    a = merged_data.groupby(merged_data.index.strftime('%m'))
    return a.std()


def asunicode(s):
    """Turns bytes into unicode, if needed.

    Uses UTF-8.
    """
    if isinstance(s, bytes):
        return s.decode('utf-8', 'replace')
    else:
        return s


def addr_to_str(addr):
    """Convert a Twisted IAddress object to readable string."""
    return addr.host + ':' + str(addr.port)


def end_iter(foo):
    """Iterate to the end of foo."""
    try:
        next(foo)
        return False
    except StopIteration:
        return True


@classmethod
def main(cls, argv=None):
    """Run program. Returns program exit code."""
    return cls(argv).run()


@classmethod
def disable(cls):
    """Disables the WebAudio domain.
        """
    return cls.build_send_payload('disable', {}), None


@classmethod
def fromfloat(cls, seconds):
    """Create an instance from a floating point number of seconds"""
    return cls(seconds // 1, seconds % 1 * 1000000000.0)


def fix_null_values(model, field_names, new_value=''):
    """
    For each fieldname, update any records in 'model' where the field's value is NULL
    to be an empty string instead (or whatever new_value is)
    """
    for name in field_names:
        model._default_manager.filter(**{name: None}).update(**{name:
            new_value})


def array_assert(a, b, decimal=None, **kwargs):
    """Function checking whether two arrays are equal in size and almost_equal
    in content (using numpy.testing.assert_almost_equal).

    Parameters
    ----------
    a : ndarray
        First array to check
    b : ndarray
        Second array to check
    decimal : float
        The precisionof the comparison (Default value = None)
    **kwargs : dict
        Extra arguments to pass to numpy.testing.assert_almost_equal

    Returns
    -------

    """
    if decimal is None:
        if a.shape != b.shape:
            raise AssertionError("Sizes of matrices don't match (%s vs %s)" %
                (str(a.shape), str(b.shape)))
        if (a == b).all():
            return
        raise AssertionError(
            'Arrays are not the same:\nArray A:%s\nArray B:%s' % (a, b))
    else:
        from numpy.testing import assert_almost_equal
        assert_almost_equal(a, b, decimal, *kwargs)


def gather_row(data, row_index):
    """Slice out the data given the row index.

    Parameters
    ----------
    data : Tensor
        The data tensor
    row_index : Tensor
        A 1-D integer tensor containing which rows to be sliced out.

    Returns
    -------
    Tensor
        The sliced data. The first dimension should equal to ``len(row_index)``.
    """
    pass


def store_user_documents(user_document_gen, client, mongo_database_name,
    mongo_collection_name):
    """
    Stores Twitter list objects that a Twitter user is a member of in different mongo collections.

    Inputs: - user_document_gen: A python generator that yields a Twitter user id and an associated document list.
            - client: A pymongo MongoClient object.
            - mongo_database_name: The name of a Mongo database as a string.
            - mongo_collection_name: The name of the mongo collection as a string.
    """
    mongo_database = client[mongo_database_name]
    mongo_collection = mongo_database[mongo_collection_name]
    for user_twitter_id, user_document_list in user_document_gen:
        document = user_document_list
        document['_id'] = int(user_twitter_id)
        mongo_collection.update({'_id': user_twitter_id}, document, upsert=True
            )


def DoNothing():
    """A routine that does nothing. This is called in place of IPyBreak and pdbBreak
    except when the debug option is set True in config.py
    """
    pass


def clean_geo(geo_data):
    """Clean RIPE reply specifics for geolocation query"""
    if 'country' in geo_data and geo_data['country'] == '?':
        del geo_data['country']
    return geo_data


def gpencil_modifier_move_up(modifier: str=''):
    """Move modifier up in the stack

    :param modifier: Modifier, Name of the modifier to edit
    :type modifier: str
    """
    pass


def getId(ob):
    """
        Get a unique id of an object.

        :raises zope.intid.interfaces.IntIdMissingError: if
           there is no id for that object.
        :raises zc.intid.interfaces.IntIdMismatchError: if the recorded id
           doesn't match the id of the object.
        """


@staticmethod
def p_brackets_list(symbols):
    """brackets_list : brackets brackets_list
                         | empty
        """
    if len(symbols) == 3:
        symbols[0] = symbols[2]
        symbols[0].insert(0, symbols[1])
    else:
        symbols[0] = []


def lru_key_func(x):
    """
    Least Recently Used key function.

    :param x: (:class:`~hazelcast.near_cache.DataRecord`)
    :return: (float), last access time of x.
    """
    return x.last_access_time


def show_mattes_ui(instance=[]):
    """Show the mtoatools mattes ui"""
    from .ui.controllers import MattesController
    if not instance:
        instance.append(MattesController())
    controller = instance[0]
    controller.show()
    return controller


@classmethod
def get_instance(cls):
    """This class stores no state, so we can store a global instance in the
        class and give it out on demand."""
    if cls.instance is None:
        cls.instance = cls()
    return cls.instance


def get_is_post_signup(request):
    """If the session contains a true value for ``is_post_signup``, then wipe
      it and return ``True``.  Otherwise, return ``False``.

      Setup::

          >>> from mock import Mock
          >>> mock_request = Mock()

      If the session contains a true value for ``is_post_signup``, then wipe
      it and return ``True``::

          >>> mock_request.session = {'is_post_signup': True}
          >>> get_is_post_signup(mock_request)
          True
          >>> mock_request.session
          {}

      Otherwise, return ``False``::

          >>> get_is_post_signup(mock_request)
          False

    """
    is_post_signup = request.session.get('is_post_signup', False)
    if is_post_signup:
        del request.session['is_post_signup']
        return True
    return False


def getSession(sessionInterface=None):
    """
        Look up the session associated with this request or create a new one if
        there is not one.

        @return: The L{Session} instance identified by the session cookie in
            the request, or the C{sessionInterface} component of that session
            if C{sessionInterface} is specified.
        """


def bulk_docs(docs, **kwargs):
    """Create, update or delete multiple documents.

    http://docs.couchdb.org/en/stable/api/database/bulk-api.html#post--db-_bulk_docs

    :param list docs: The sequence of documents to be sent.
    :param kwargs: (optional) Arguments that :meth:`requests.Session.request` takes.
    :rtype: (str, str, dict)
    """
    if 'json' not in kwargs or not isinstance(kwargs['json'], dict):
        kwargs['json'] = {}
    kwargs['json']['docs'] = docs
    return 'POST', '_bulk_docs', kwargs


def execute_query_return_result_proxy(query):
    """
    Execute a query, yield result proxy.

    :param query: :class:`sqlalchemy.orm.Query`,
        has to be created from ``session.query(Object)``

    :return: :class:`sqlalchemy.engine.result.ResultProxy`
    """
    context = query._compile_context()
    context.statement.use_labels = False
    if query._autoflush and not query._populate_existing:
        query.session._autoflush()
    conn = query._get_bind_args(context, query._connection_from_session,
        close_with_result=True)
    return conn.execute(context.statement, query._params)


@staticmethod
def in_expo(progress):
    """.. image:: images/anim_in_expo.png
        """
    if progress == 0:
        return 0.0
    return pow(2, 10 * (progress - 1.0))


def tris_convert_to_quads(face_threshold: float=0.698132, shape_threshold:
    float=0.698132, uvs: bool=False, vcols: bool=False, seam: bool=False,
    sharp: bool=False, materials: bool=False):
    """Join triangles into quads

    :param face_threshold: Max Face Angle, Face angle limit
    :type face_threshold: float
    :param shape_threshold: Max Shape Angle, Shape angle limit
    :type shape_threshold: float
    :param uvs: Compare UVs
    :type uvs: bool
    :param vcols: Compare VCols
    :type vcols: bool
    :param seam: Compare Seam
    :type seam: bool
    :param sharp: Compare Sharp
    :type sharp: bool
    :param materials: Compare Materials
    :type materials: bool
    """
    pass


def return_ticketccstring_and_show_subscribe(user, ticket):
    """used in view_ticket() and followup_edit()"""
    username = user.get_username().upper()
    useremail = user.email.upper()
    strings_to_check = list()
    strings_to_check.append(username)
    strings_to_check.append(useremail)
    ticketcc_string = ''
    all_ticketcc = ticket.ticketcc_set.all()
    counter_all_ticketcc = len(all_ticketcc) - 1
    show_subscribe = True
    for i, ticketcc in enumerate(all_ticketcc):
        ticketcc_this_entry = str(ticketcc.display)
        ticketcc_string += ticketcc_this_entry
        if i < counter_all_ticketcc:
            ticketcc_string += ', '
        if strings_to_check.__contains__(ticketcc_this_entry.upper()):
            show_subscribe = False
    assignedto_username = str(ticket.assigned_to).upper()
    strings_to_check = list()
    if ticket.submitter_email is not None:
        submitter_email = ticket.submitter_email.upper()
        strings_to_check.append(submitter_email)
    strings_to_check.append(assignedto_username)
    if strings_to_check.__contains__(username
        ) or strings_to_check.__contains__(useremail):
        show_subscribe = False
    return ticketcc_string, show_subscribe


@classmethod
def is_equal(cls, requested_flow, flow_from_server):
    """Return True if a RequestedFlow is equal to an existing flow from BusinessFlow.

        For each source, destination, user, network_application and service check if that it is equal to
        the flow's relevant attribute.
        If all of the above are true, it means that the requested flow equals to the existing one.

        Args:
            requested_flow (algosec.models.RequestedFlow): The new flow to check if included in the existing flow.
            flow_from_server (dict): The existing flow from BusinessFlow.

        Returns:
            bool:  True if the requested flow is equal to the existing flow.
        """
    return all([cls._are_sources_equal_in_flow(requested_flow.sources,
        flow_from_server['sources']), cls._are_destinations_equal_in_flow(
        requested_flow.destinations, flow_from_server['destinations']), cls
        ._are_network_services_equal_in_flow(requested_flow.
        network_services, flow_from_server['services']), cls.
        _are_network_applications_equal_in_flow(requested_flow.
        network_applications, flow_from_server.get('networkApplications', [
        ])), cls._are_network_users_equal_in_flow(requested_flow.
        network_users, flow_from_server.get('networkUsers', []))])


def s_one_pre(topics):
    """Performs segmentation on a list of topics.

    Notes
    -----
    Segmentation is defined as
    :math:`s_{pre} = {(W', W^{*}) | W' = w_{i}; W^{*} = {w_j}; w_{i}, w_{j} \\in W; i > j}`.

    Parameters
    ----------
    topics : list of np.array
        list of topics obtained from an algorithm such as LDA.

    Returns
    -------
    list of list of (int, int)
        :math:`(W', W^{*})` for all unique topic ids.

    Examples
    --------
    .. sourcecode:: pycon

        >>> import numpy as np
        >>> from gensim.topic_coherence import segmentation
        >>>
        >>> topics = [np.array([1, 2, 3]), np.array([4, 5, 6])]
        >>> segmentation.s_one_pre(topics)
        [[(2, 1), (3, 1), (3, 2)], [(5, 4), (6, 4), (6, 5)]]

    """
    s_one_pre_res = []
    for top_words in topics:
        s_one_pre_t = []
        for w_prime_index, w_prime in enumerate(top_words[1:]):
            for w_star in top_words[:w_prime_index + 1]:
                s_one_pre_t.append((w_prime, w_star))
        s_one_pre_res.append(s_one_pre_t)
    return s_one_pre_res


@staticmethod
def is_done():
    """
        The default behaviour of this visitor
        is to always return False, when asked
        if the visitor is done operating.

        @return: False, since the visitor is not done.
        @rtype: C{bool}
        """
    return False


def longest_prefix(text, pattern, start):
    """
    Finds the longest prefix of text and pattern.
    """
    end = len(pattern)
    while text[start:start + end] != pattern[:end]:
        end -= 1
    return text[start:start + end]


def filter_nan(file_name):
    """
    This function filters out NaN values from a csv file.

    :param file_name: Name of csv file to filter.
    :type file_name: str.
    :return: None
    """
    with open(file_name, 'r') as r:
        lines = r.readlines()
    with open(file_name, 'w') as w:
        for l in lines:
            if 'nan' not in l:
                w.write(l)


def p_type_specifier_list(t):
    """type_specifier_list : COMMA type_specifier type_specifier_list
                           | empty"""


def e(s):
    """Convert a string in 0.1D+01 FORTRAN notation into 0.1e+10."""
    return s.replace('D', 'e')


def bootstrap_starting():
    """Called before attempting to load/download packages."""


def get_int2(data, offset):
    """Pull two bytes from data at offset and return as an integer."""
    return (data[offset] << 8) + data[offset + 1]


def duplicate_move(GPENCIL_OT_duplicate=None, TRANSFORM_OT_translate=None):
    """Make copies of the selected Grease Pencil strokes and move them

    :param GPENCIL_OT_duplicate: Duplicate Strokes, Duplicate the selected Grease Pencil strokes
    :param TRANSFORM_OT_translate: Translate, Translate (move) selected items
    """
    pass


@staticmethod
def _add_library(parser, name):
    """Adds a third party build options"""
    parser.add_argument('--no-%s' % name.lower(), help='do not build a %s.' %
        name, action='store_true', default=False)


def ensure_list(value, attr):
    """raise an error if `value` is not a list"""
    from distutils.errors import DistutilsSetupError
    if not isinstance(value, list):
        raise DistutilsSetupError('{} must be a list, got {}'.format(attr,
            value.__class__))


def escape_latex(value):
    """Escape a value for Latex
    """
    value = value.replace('\\', '\\textbackslash{}')
    value = value.replace('{', '\\{')
    value = value.replace('}', '\\}')
    value = value.replace('#', '\\#')
    value = value.replace('$', '\\$')
    value = value.replace('%', '\\%')
    value = value.replace('&', '\\&')
    value = value.replace('^', '\\^{}')
    value = value.replace('_', '\\_')
    value = value.replace('~', '\\textasciitidle{}')
    value = value.replace('\\textbackslash\\{\\}', '\\textbackslash{}')
    return value


def listify(src):
    """Make a list with source object if not already a list.

    :param src:
    :rtype: list

    """
    if not isinstance(src, list):
        src = [src]
    return src


def phys_rev_column(scale=1):
    """Return the Phys. Rev. figure size (3.375, 3) scaled witth scale (default = 1)"""
    return [3.375 * scale, 3.0 * scale]


def map_per_image(label, predictions, k: int=5):
    """Computes the precision score of one image.

    Parameters
    ----------
    label : string
            The true label of the image
    predictions : list
            A list of predicted elements (order does matter, k predictions allowed per image)

    k : int
            MAP@k

    Returns
    -------
    score : double
    """
    try:
        return 1 / (predictions[:k].index(label) + 1)
    except ValueError:
        return 0.0


@classmethod
def from_redeemScript(cls, redeemScript):
    """Convert a redeemScript to a P2SH address

        Convenience function: equivalent to P2SHBitcoinAddress.from_scriptPubKey(redeemScript.to_p2sh_scriptPubKey())
        """
    return cls.from_scriptPubKey(redeemScript.to_p2sh_scriptPubKey())


def curve_q(x, y, p, n):
    """Find curve parameter q mod n having point (x, y) and parameter p"""
    return ((x * x - p) * x - y * y) % n


def parallel_fit(args):
    """
    This is a convenience function for parallelizing the fitting
    procedure.  Each call is handed a tuple or list containing
    all the necessary inputs for instantiaing a `GaussianFit`
    class object and estimating the model parameters.

    Paramaters
    ----------
    args : list/tuple
        A list or tuple containing all the necessary inputs for fitting
        the Gaussian pRF model.

    Returns
    -------

    fit : `Fit` class object
        A fit object that contains all the inputs and outputs of the
        pRF model estimation for a single voxel.

    """
    Fit = args[0]
    model = args[1]
    data = args[2]
    grids = args[3]
    bounds = args[4]
    voxel_index = args[5]
    Ns = args[6]
    auto_fit = args[7]
    verbose = args[8]
    fit = Fit(model, data, grids, bounds, Ns, voxel_index, auto_fit, verbose)
    return fit


def getstack(repo, rev=None):
    """return a sorted smartrev of the stack containing either rev if it is
    not None or the current working directory parent.

    The stack will always contain all drafts changesets which are ancestors to
    the revision and are not merges.
    """
    if rev is None:
        rev = b'.'
    revspec = b'only(%s) and not public() and not ::merge()'
    revisions = repo.revs(revspec, rev)
    revisions.sort()
    return revisions


def update_param(event, param):
    """ update the param based on event information """
    origin = event.preferred_origin()
    origin = event.preferred_origin()
    event_latitude = origin.latitude
    event_longitude = origin.longitude
    event_time = origin.time
    param['starttime'] = event_time + param['relative_starttime']
    param.pop('relative_starttime')
    param['endtime'] = event_time + param['relative_endtime']
    param.pop('relative_endtime')
    param['event_latitude'] = event_latitude
    param['event_longitude'] = event_longitude


@classmethod
def make(cls, event_type, event_data):
    """Creates a new TreeEvent tuple.

        :returns: A :class:`~kazoo.recipe.cache.TreeEvent` instance.
        """
    assert event_type in (cls.NODE_ADDED, cls.NODE_UPDATED, cls.
        NODE_REMOVED, cls.CONNECTION_SUSPENDED, cls.CONNECTION_RECONNECTED,
        cls.CONNECTION_LOST, cls.INITIALIZED)
    return cls((event_type, event_data))


def strip_comment(string, comment_characters=('!',), quote_characters=('"',
    "'")):
    """
    Return the string only until the first comment (if any), but makes
    sure to ignore comments if inside a string

    Note: it expects to get a SINGLE line, without newline characters

    Note: it does not cope with escaping of quotes

    :param string: the string to check
    :param comment_characters: a list or tuple of accepted comment characters
    :param quote_characters: a list or tuple of accepted valid string characters
    """
    new_string = []
    in_string = False
    string_quote = None
    for char in string:
        if char == '\n':
            raise ValueError(
                'I still cannot cope with newlines in the string...')
        if in_string and char == string_quote:
            in_string = False
            string_quote = None
        elif not in_string and char in quote_characters:
            in_string = True
            string_quote = char
        if not in_string and char in comment_characters:
            return ''.join(new_string)
        new_string.append(char)
    if in_string:
        raise ValueError(
            'String >>{}<< is not closed, it was open with the {} char'.
            format(string, string_quote))
    return string


@staticmethod
def _default_evidence_code() ->str:
    """Yields the default GO evidence code"""
    return 'NR'


def hello_world():
    """Returns hello world string.

    :returns: str

    """
    return 'Hello, world!'


def unset(db, collection, field, match=None):
    """
    Removes ``field`` from all records in ``collection`` that meet
    ``match`` criteria.

    Arguments:

        field (str): Field to be removed.

        db (Database): A pymongo Database object.

        collection (str): Collection name.

        match (dict): A dictionary containing the match criteria, for example::

            {'seq_id': {'$in': ['a', 'b', 'c']}, 'cdr3_len': {'$gte': 18}}
    """
    c = db[collection]
    match = match if match is not None else {}
    if db.client.server_info()['version'].startswith('2'):
        c.update(match, {'$unset': {field: ''}}, multi=True)
    else:
        c.update_many(match, {'$unset': {field: ''}})


def plot_sn_discovery_map(log, snSurveyDiscoveryTimes, peakAppMagList,
    snCampaignLengthList, redshifts, extraSurveyConstraints,
    pathToOutputPlotFolder):
    """
    *Plot the SN discoveries in a polar plot as function of redshift & time*

    **Key Arguments:**
        - ``log`` -- logger
        - ``snSurveyDiscoveryTimes`` --
        - ``peakAppMagList`` --
        - ``snCampaignLengthList`` -- a list of campaign lengths in each filter
        - ``redshifts`` --
        - ``extraSurveyConstraints`` --
        - ``pathToOutputPlotDirectory`` -- path to add plots to

    **Return:**
        - None
    """
    import sys
    import matplotlib.pyplot as plt
    import numpy as np
    filters = ['g', 'r', 'i', 'z']
    lunarMonth = 29.3
    surveyYear = 12.0 * lunarMonth
    faintMagLimit = extraSurveyConstraints['Faint-Limit of Peak Magnitude']
    discovered = []
    tooFaint = []
    shortCampaign = []
    discoveredRedshift = []
    tooFaintRedshift = []
    notDiscoveredRedshift = []
    shortCampaignRedshift = []
    for item in range(len(redshifts)):
        if snSurveyDiscoveryTimes[item]['any'] is True:
            discoveryDayList = []
            faintDayList = []
            shortCampaignDayList = []
            for ffilter in filters:
                if snSurveyDiscoveryTimes[item][ffilter]:
                    if peakAppMagList[item][ffilter] < faintMagLimit:
                        if snCampaignLengthList[item]['max'
                            ] < extraSurveyConstraints[
                            'Observable for at least ? number of days']:
                            shortCampaignDayList.append(snSurveyDiscoveryTimes
                                [item][ffilter])
                        else:
                            discoveryDayList.append(snSurveyDiscoveryTimes[
                                item][ffilter])
                    else:
                        faintDayList.append(snSurveyDiscoveryTimes[item][
                            ffilter])
            if len(discoveryDayList) > 0:
                discovered.append(min(discoveryDayList))
                discoveredRedshift.append(redshifts[item])
            elif len(shortCampaignDayList) > 0:
                shortCampaign.append(min(shortCampaignDayList))
                shortCampaignRedshift.append(redshifts[item])
            else:
                tooFaint.append(min(faintDayList))
                tooFaintRedshift.append(redshifts[item])
        else:
            notDiscoveredRedshift.append(redshifts[item])
    colors = [{'red': '#dc322f'}, {'blue': '#268bd2'}, {'green': '#859900'},
        {'orange': '#cb4b16'}, {'gray': '#93a1a1'}, {'violet': '#6c71c4'},
        {'cyan': '#2aa198'}, {'magenta': '#d33682'}, {'yellow': '#b58900'}]
    fig = plt.figure(num=None, figsize=(8, 8), dpi=None, facecolor=None,
        edgecolor=None, frameon=True)
    ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, frameon=False)
    maxInList = max(redshifts) * 1.1
    ax.set_ylim(0, maxInList)
    circleTicks = np.arange(0, 350, 30)
    tickLabels = []
    for tick in circleTicks:
        tickLabels.append('%s days' % (tick,))
    plt.xticks(2 * np.pi * circleTicks / 360.0, tickLabels)
    discovered = 2 * np.pi * np.array(discovered) / surveyYear
    discoveredRedshift = np.array(discoveredRedshift)
    tooFaint = 2 * np.pi * np.array(tooFaint) / surveyYear
    tooFaintRedshift = np.array(tooFaintRedshift)
    shortCampaign = 2 * np.pi * np.array(shortCampaign) / surveyYear
    shortCampaignRedshift = np.array(shortCampaignRedshift)
    plt.scatter(tooFaint, tooFaintRedshift, label=
        'Detected - too faint to constrain as transient', s=50, c='#dc322f',
        marker='o', cmap=None, norm=None, vmin=None, vmax=None, alpha=0.2,
        linewidths=None, edgecolor='#657b83', verts=None, hold=True)
    plt.scatter(discovered, discoveredRedshift, label=
        'Discovered transient', s=50, c='#859900', marker='o', cmap=None,
        norm=None, vmin=None, vmax=None, alpha=0.2, linewidths=None,
        edgecolor='#657b83', verts=None, hold=True)
    plt.scatter(shortCampaign, shortCampaignRedshift, label=
        'Detected - campaign to short to constrain as transient', s=50, c=
        '#268bd2', marker='o', cmap=None, norm=None, vmin=None, vmax=None,
        alpha=0.2, linewidths=None, edgecolor='#657b83', verts=None, hold=True)
    title = 'transients Detected Within the Suvrey Year'
    box = ax.get_position()
    ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
    ax.legend(loc='center left', bbox_to_anchor=(0.7, -0.1), prop={'size': 8})
    plt.grid(True)
    plt.title(title, fontsize='small', verticalalignment='bottom',
        linespacing=0.2)
    fileName = pathToOutputPlotFolder + title.replace(' ', '_') + '.png'
    imageLink = '\n![%s_plot](%s)\n\n' % (title.replace(' ', '_'), fileName)
    plt.savefig(fileName)
    plt.clf()
    return imageLink


def new_or_existing(k):
    """
        If an object already exists in the container with key "k", it
        is returned.

        Otherwise, create a new subobject of the type supported by this
        container with key "k" and return it.

        "k" must be a string, else a TypeError is raised.

        If a new object needs to be created and the container is 'full',
        a MaxTransientObjectsExceeded exception will be raised.

        Returned object is acquisition-wrapped in self.
        """


def gluUnProject(winx, winy, winz, modelMatrix: 'Buffer', projMatrix:
    'Buffer', viewport: 'Buffer', objx, objy, objz):
    """Map object coordinates to window coordinates.

    :param winz: Specify the window coordinates to be mapped.
    :param modelMatrix: Specifies the current modelview matrix (as from a glGetDoublev call).
    :type modelMatrix: 'Buffer'
    :param projMatrix: Specifies the current projection matrix (as from a glGetDoublev call).
    :type projMatrix: 'Buffer'
    :param viewport: Specifies the current viewport (as from a glGetIntegerv call).
    :type viewport: 'Buffer'
    :param objz: Return the computed object coordinates.
    """
    pass


def boolean(message, err='Please enter 1 (True) or 0 (False).'):
    """Command line input and error checking for boolean values (1 or 0).

    Args:
        message (str): The input message displayed in the command line.
        err (str, optional): The message displayed for an erroneous input.
            Defaults to "Please enter 1 (True) or 0 (False).".

    Returns:
        bool: The first sucessfully input boolean value.
    """
    while True:
        data = input(message)
        data = data.strip()
        if data == '':
            print('Please provide an input.')
            continue
        if data == '1':
            return True
        elif data == '0':
            return False
        print(err)


def _to_number(value):
    """
    Convert the string containing a number to a number

    :param str value: The value to convert
    :rtype: float|int

    """
    return float(value) if '.' in value else int(value)


def progress_log(msg):
    """
    Send a notification to the client to update on the progress of a job

    Parameters
        - msg ( *string* ): message to send to client
    """
    from toyz.web import session_vars
    print(msg)
    if hasattr(session_vars, 'pipe'):
        notification = {'id': 'notification', 'msg': msg}
        session_vars.pipe.send(notification)


def serialize_value(value):
    """Attempts to convert `value` into an ISO8601-compliant timestamp string.
    If `value` is ``None``, ``None`` will be returned.

    Args:
        value: A datetime.datetime value.

    Returns:
        An ISO8601 formatted timestamp string.

    """
    if not value:
        return None
    return value.isoformat()


def delete_slide(presentation, index):
    """
    Delete a slide from Presentation.
    """
    xml_slides = presentation.slides._sldIdLst
    slides = list(xml_slides)
    xml_slides.remove(slides[index])


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


@classmethod
def get_statements(cls):
    """Statetements getter.

        Returns:
            iterator: A key-value itertator of all statements.
        """
    return cls.statements.iteritems()


@staticmethod
def make_cache_key(pattern, flags):
    """Creates a unique cache key for every pattern"""
    return '{}_{}'.format(pattern, flags)


def unordered_domain_values(var, assignment, csp):
    """The default value order."""
    return csp.choices(var)


def get_object_root_module(obj):
    """
    Get the obj module version
    :param T obj: Any object
    :rtype: str
    :return The root module of the object's type
    """
    return type(obj).__module__.split('.')[0]


@staticmethod
def merge_kwargs(kwargs, key, value):
    """
        set the kwargs key/value pair, joining any pre-existing value with
        a space.

        :param kwargs: keyword arguments
        :type kwargs: dict
        :param key: key
        :type key: str
        :param value: the value to set the kwarg to
        :type value: object
        """
    if key is not None:
        if key in kwargs:
            value = ' '.join([kwargs[key], value])
        kwargs[key] = value


def get_single_field(fields):
    """Finds neurons with and indices of single fields.

    Parameters
    ----------
    fields : dict
        Where the key is the neuron number (int), value is a list of arrays (int).
        Each inner array contains the indices for a given place field.
        Eg. Neurons 7, 3, 11 that have 2, 1, and 3 place fields respectively would be:
        {7: [[field], [field]], 3: [[field]], 11: [[field], [field], [field]]}

    Returns
    -------
    fields : dict
        Where the key is the neuron number (int), value is a list of arrays (int).
        Each inner array contains the indices for a given place field.
        Eg. For the above input, only neuron 3 would be output in this dict:
        {3: [[field]]}

    """
    fields_single = dict()
    for neuron in fields.keys():
        if len(fields[neuron]) == 1:
            fields_single[neuron] = fields[neuron]
    return fields_single


@classmethod
def _cleanup(cls):
    """Clean up the started subprocesses at exit.
        """
    for proc in list(cls._procs):
        proc.terminate()


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

        :param SharedFolderChangeMembersPolicyDetails val:
        :rtype: EventDetails
        """
    return cls('shared_folder_change_members_policy_details', val)


def comp(returns):
    """ Calculates total compounded returns """
    return returns.add(1).prod() - 1


def _moduleof(obj, dflt=''):
    """Return the object's module name.
    """
    return getattr(obj, '__module__', dflt)


def configure(iptables_mgr):
    """Configure the iptables manager impl.

    :param iptables_mgr: the iptables manager instance
    """
    global _IPTABLES_MANAGER
    _IPTABLES_MANAGER = iptables_mgr


@classmethod
def get_table_names(cls, inspector, schema):
    """Need to consider foreign tables for PostgreSQL"""
    tables = inspector.get_table_names(schema)
    tables.extend(inspector.get_foreign_table_names(schema))
    return sorted(tables)


@classmethod
def list_valid_update_frequencies(cls):
    """List of valid update frequency values

        Returns:
            List[str]: Allowed update frequencies
        """
    return list(cls.update_frequencies.keys())


def remove_keys(apps, schema_editor):
    """
    We can't import the Post model directly as it may be a newer
    version than this migration expects. We use the historical version.
    """
    Setting = apps.get_model('settings', 'Setting')
    try:
        key = 'ACCOUNT_BANK_NUMBER'
        Setting.objects.get(key=key).delete()
    except Exception:
        pass


def count_from_0(index, collection):
    """Numbering function: consecutive integers starting at 0."""
    return index


def languages():
    """Returns list of supported languages.

    This should correspond to the existing translations
    """
    return ['en', 'ru', 'pl', 'cz']


def validate_format(*_arg):
    """
    This method can be overridden with format validation logic.
    """
    return True


def layout_position_to_feet(x: float, y: float, maxx: float, maxy: float,
    width: float=12, height: float=8) ->(float, float):
    """Correct given position based on maximal position in whole graph
    and expected final size"""
    apply = lambda v, m, s: round(s * v / m, 2)
    return apply(x, maxx, width), apply(y, maxy, height)


def error(message):
    """Print error message."""
    print('False: ' + str(message))


def format_bm_pair(toformat):
    """
	Formats a primitive killstreak/bookmark pair ((), ())
	into a readable string.
	"""
    if toformat is None:
        return 'None'
    return f'{len(toformat[0])} Killstreaks; {len(toformat[1])} Bookmarks'


def poptrailing(lst):
    """Remove trailing blank items from lst.
    """
    while lst and lst[-1] == '':
        lst.pop()
    return lst


def _c_find_handler(event):
    """Default handler for when a C-FIND request is received.

    See _handlers.doc_handle_find for detailed documentation.
    """
    raise NotImplementedError("No handler has been bound to 'evt.EVT_C_FIND'")


def _is_sunder(name):
    """Returns True if a _sunder_ name, False otherwise."""
    return name[0] == name[-1] == '_' and name[1:2] != '_' and name[-2:-1
        ] != '_' and len(name) > 2


def loc2Dict(loc):
    """
	Convert a loc into a dictionary, for the consideration of maintainability.

	Parameters
	----------
	loc: list
		A location, in format of [lat, lon] or [lat, lon, alt]

	Return
	------
	dictionary
		A dictionary of location
	"""
    if len(loc) == 2:
        locDict = {'lat': loc[0], 'lon': loc[1], 'alt': 0}
    elif len(loc) == 3:
        locDict = {'lat': loc[0], 'lon': loc[1], 'alt': loc[2]}
    else:
        return
    return locDict


@classmethod
def parse_from_file(cls, filename):
    """Construct YamlParser from a filename."""
    with open(filename, 'r') as fh:
        return cls.parser_from_buffer(fh)


@classmethod
def sample(cls, x, y, runs=1, *, nsamples=50000):
    """
        Return a sample of posterior distribution for the given data

        Args:
            x (np.array): a vector of scores for the first model
            y (np.array): a vector of scores for the second model
            runs (int): number of repetitions of cross validation (default: 1)
            nsamples (int): the number of samples (default: 50000)

        Returns:
            mean, var, degrees_of_freedom
        """
    return cls(x, y, runs=runs, nsamples=nsamples).sample


def reboot_instances(DryRun=None, InstanceIds=None):
    """
    Requests a reboot of one or more instances. This operation is asynchronous; it only queues a request to reboot the specified instances. The operation succeeds if the instances are valid and belong to you. Requests to reboot terminated instances are ignored.
    If an instance does not cleanly shut down within four minutes, Amazon EC2 performs a hard reboot.
    For more information about troubleshooting, see Getting Console Output and Rebooting Instances in the Amazon Elastic Compute Cloud User Guide .
    See also: AWS API Documentation

    :example: response = client.reboot_instances(
        DryRun=True|False,
        InstanceIds=[
            '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 InstanceIds: list
    :param InstanceIds: [REQUIRED]
            One or more instance IDs.
            (string) --

    """
    pass


def get_class_property_from_LAW(id, texts_NV, class_property, NOUN, VERB):
    """대상 법령에서 Class와 Property 요소를 추출합니다"""
    text_class_property = []
    nouns = texts_NV[int(id)][2].split(',')
    verbs = texts_NV[int(id)][3].split(',')
    for i in range(4):
        if class_property[i].startswith('NOUN'):
            idx = class_property[i][4:]
            t_idx = NOUN[int(idx)][4:]
            text_class_property.append(nouns[int(t_idx)])
        elif class_property[i].startswith('VERB'):
            idx = class_property[i][4:]
            t_idx = VERB[int(idx)][4:]
            text_class_property.append(verbs[int(t_idx)] + '다')
        else:
            text_class_property.append('')
    return text_class_property, nouns


@classmethod
def from_string(cls, s, offset=0):
    """ Parse a `Tag` definition from `s` at `offset` (default `0`).
    """
    tag, post_offset = cls.parse(s, offset=offset)
    if post_offset < len(s):
        raise ValueError('unparsed text after Tag %s: %r' % (tag, s[
            post_offset:]))
    return tag


@staticmethod
def _filter_inputs(key):
    """Perform any necessary filtering of input keys for PySAM.

        Parameters
        ----------
        key : str
            SAM input key.

        Returns
        -------
        key : str
            Filtered SAM input key.
        """
    if '.' in key:
        key = key.replace('.', '_')
    if ':constant' in key and 'adjust:' in key:
        key = key.replace('adjust:', '')
    return key


def image_grid_to_raster(image_grid):
    """ Converts image grid to RGB raster image.
    :param image_grid: numpy array of size (nY x nX x Y x X x C)
    :return: RGB image
    """
    """
    1. nY    x    nX    x    Y    x    X    x    C        -> swap axes
                   .       .
                     .   .
                       .
                     .   .
                   .       .
    2. nY    x    Y    x    nX    x    X    x    C        -> reshape merge axis 0 with 1, 2 with 3
    3. (nY   *   Y)    x    (nX   *   X)    x    C        = H x W x C
    """
    nY, nX, Y, X, C = image_grid.shape
    return image_grid.swapaxes(1, 2).reshape(nY * Y, nX * X, C)


def atom_implicit_valence(atom):
    """Get the implicit valence of an atom.

    Parameters
    ----------
    atom : rdkit.Chem.rdchem.Atom
        RDKit atom instance.

    Reurns
    ------
    list
        List containing one int only.
    """
    return [atom.GetImplicitValence()]


def escape(s, quote=None):
    """Replace special characters "&", "<", ">" and (") to HTML-safe sequences.

    There is a special handling for `None` which escapes to an empty string.

    .. versionchanged:: 0.9
       `quote` is now implicitly on.

    :param s: the string to escape.
    :param quote: ignored.
    """
    if s is None:
        return ''
    elif hasattr(s, '__html__'):
        return str(s.__html__())
    elif not isinstance(s, str):
        s = str(s)
    if quote is not None:
        from warnings import warn
        warn(DeprecationWarning('quote parameter is implicit now'),
            stacklevel=2)
    s = s.replace('&', '&').replace('<', '<').replace('>', '>'
        ).replace('"', '"')
    return s


def code_point_order(cp):
    """Ordering function for code points."""
    return cp if isinstance(cp, int) else cp[0]


@staticmethod
def filter_empty_items(items):
    """
        Filter out items that give False when casted to boolean.

        :argument items: List of tuples
        :type items: iterable

        :returns: List of URL part specs (with empty items cleared out)
        :rtype: list of tuple

        >>> list(URLBuilder.filter_empty_items([
        ...   (None, ''),
        ...   (None, '<not empty>'),
        ...   (None, []),
        ...   (None, None),
        ...   (None, '<not empty 2>'),
        ... ]))
        [(None, '<not empty>'), (None, '<not empty 2>')]

        >>> list(URLBuilder.filter_empty_items([
        ...   (None, '<not empty>'),
        ...   None
        ... ]))
        Traceback (most recent call last):
          ...
        TypeError: 'NoneType' object is not iterable

        """
    for required, item in items:
        if item:
            yield required, item


def escape_single_quotes(text):
    """Return `text` with any single quotes escaped (doubled)."""
    return text.replace("'", "''")


def remote_archive(class_obj: type) ->type:
    """
    Decorator to annotate the RemoteArchive class. Registers the decorated class
    as the RemoteArchive known type.
    """
    assert isinstance(class_obj, type), 'class_obj is not a Class'
    global _remote_archive_resource_type
    _remote_archive_resource_type = class_obj
    return class_obj


def perm_cycles(p, singletons=False, n=None):
    """
    Return the cycle decomposition of ``p``

    INPUT:

    - ``p`` -- the permutation

    - ``singletons`` -- bool (default: ``False``) - return or not the singletons

    - ``n`` - (optional) only use the first ``n`` elements of the permutation ``p``

    EXAMPLES::

        sage: from surface_dynamics.misc.permutation import perm_cycles, perm_init
        sage: perm_cycles([0,2,1])
        [[1, 2]]
        sage: perm_cycles([0,2,1],True)
        [[0], [1, 2]]

        sage: perm_cycles([2,-1,0])
        [[0, 2]]

        sage: perm_cycles([2,0,1,-1,-1], n=3)
        [[0, 2, 1]]

        sage: perm_cycles([-1,3,-1,1], singletons=True)
        [[1, 3]]

        sage: perm_cycles(perm_init('(1,3)', partial=True))
        [[1, 3]]
    """
    if n is None:
        n = len(p)
    seen = [1] * n
    res = []
    for i in range(n):
        if seen[i] and p[i] != -1:
            cycle = []
            j = i
            while seen[j]:
                seen[j] = 0
                cycle.append(j)
                j = p[j]
            if singletons or len(cycle) > 1:
                res.append(cycle)
    return res


def _sort_io_counters(process, sortedby='io_counters', sortedby_secondary=
    'memory_percent'):
    """Specific case for io_counters
    Sum of io_r + io_w"""
    return process[sortedby][0] - process[sortedby][2] + process[sortedby][1
        ] - process[sortedby][3]


def calculate_floating_replaced_width(node, context):
    """Implements S10.3.6"""
    raise NotImplementedError('Section 10.3.6')


@classmethod
def register(cls, name):
    """Register a new projection to handle."""
    return cls.projection_registry.register(name)


def is_none(val):
    """
    Check if a value is None.

    :param val: the value to be tested
    :return: returns false if the value is not none
    """
    if val is None:
        raise TypeError('None detected')
    return False


def license_destination(config, libname, filename):
    """Given the (reconstructed) library name, find appropriate destination"""
    normal = config.vendor_dir / libname
    if normal.is_dir():
        return normal / filename
    lowercase = config.vendor_dir / libname.lower()
    if lowercase.is_dir():
        return lowercase / filename
    if libname in config.library_dirnames:
        return config.vendor_dir / config.library_dirnames[libname] / filename
    return config.vendor_dir / '{}.{}'.format(libname, filename)


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

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


def _get_edges_elist(line, attributes, separator, secondary, edges,
    di_attributes, di_convert):
    """
    Add edges and attributes to `edges` and `di_attributes` for the "neighbour"
    format.
    """
    data = line.split(separator)
    source, target = int(data[0]), int(data[1])
    edges.append((source, target))
    if len(data) == 3:
        attr_data = data[2].split(secondary)
        for name, val in zip(attributes, attr_data):
            di_attributes[name].append(di_convert[name](val))


def isblank(s: str):
    """
    >>> assert isblank('')
    >>> assert isblank('  ')
    >>> assert not isblank('   a    ')
    """
    return not s or s.isspace()


def combine(value, new=None):
    """ Jinja2 filter which merges dictionaries.
	"""
    new = new or {}
    value = dict(value)
    value.update(new)
    return value


@staticmethod
def ConvertToCommandName(func_name):
    """
        Converts a function name to a command name:
            - lower-case
            - dashes separates words

        The command name is used as the argument from the command line.

        Ex.
            CreateDb -> create-db

        :param unicode func_name:
            The function name, using camel cases standard.

        :return unicode:
        """
    import re
    s1 = re.sub('(.)([A-Z][a-z]+)', '\\1-\\2', func_name)
    return re.sub('([a-z0-9])([A-Z])', '\\1-\\2', s1).lower()


def t_AUTHENTICATED_CLIENTS(t):
    """authenticated\\ clients"""
    return t


@staticmethod
def should_delete_outdated_entities():
    """Should the processor delete entities when become outdated

        An entity that was not updated in the last get_all is considered
        outdated. If this method returns true, then it will be automatically
        deleted when outdated.
        Note that this behavior does not suit all datasources - datasources
        that are based only on notifications do not update their entities in
        get_all, so they should return False.
        """
    return False


@staticmethod
def evaluate(x, offset):
    """One dimensional Shift model function"""
    return x + offset


def text_stripper(txt: str) ->str:
    """This is a stdout/stderr processor that strips the given text.

    :param str txt: The text to be stripped
    :rtype: str
    """
    return txt.strip()


@classmethod
def get_affected_sensors(cls, session, server_key, source_name):
    """Get sensors affected by the source sensor

        Args:
            session: database session
            server_key(int): key of the server sensors belong to
            source_name(str): name of the source sensor
        Returns:
            dict: source and target sensor details
        """
    results = session.run(
        """
            MATCH (:ServerWithBMC { key: $server })-[:HAS_SENSOR]->(source:Sensor { name: $source })
            MATCH (source)<-[rel]-(targets:Sensor) return source, targets, collect(rel) as rel
            """
        , server=server_key, source=source_name)
    return cls.format_target_elements(results)


def center_path(x: float, diameter: float) ->float:
    """
    Describes the y values of a a straight path across the center of a
    detector given a position x and detector diameter d0.

    """
    return 0.0


def value_to_none(config_val, evar):
    """
    Given a value that evaluates to a boolean False, return None.

    :param str config_val: The env var value.
    :param EnvironmentVariable evar: The EVar object we are validating
        a value for.
    :rtype: str or None
    :return: Either the non-False value or None.
    """
    if not config_val:
        return None
    return config_val


def add_event_team(event_dict, event):
    """
    Add event team for event

    :param event_dict: dict of event info
    :param event: list with parsed event info

    :return: None
    """
    if event_dict['Event'] in ['GOAL', 'SHOT', 'MISS', 'BLOCK', 'PENL',
        'FAC', 'HIT', 'TAKE', 'GIVE']:
        event_dict['Ev_Team'] = event[5].split()[0]
    else:
        event_dict['Ev_Team'] = ''


def add_marker_at_click():
    """Place new marker at the desired (clicked) position

    """
    pass


def _shift16(num: int) ->int:
    """Left shift with 16 bit.

    Usage:
    >>> hex(_shift16(0x20009))
    0x30000
    """
    ten = 1 << 16
    return num + ten - num % ten


@classmethod
def load(cls, load_path, env=None, custom_objects=None, **kwargs):
    """
        Load the model from file

        :param load_path: (str or file-like) the saved parameter location
        :param env: (Gym Environment) the new environment to run the loaded model on
            (can be None if you only need prediction from a trained model)
        :param custom_objects: (dict) Dictionary of objects to replace
            upon loading. If a variable is present in this dictionary as a
            key, it will not be deserialized and the corresponding item
            will be used instead. Similar to custom_objects in
            `keras.models.load_model`. Useful when you have an object in
            file that can not be deserialized.
        :param kwargs: extra arguments to change the model when loading
        """
    data, params = cls._load_from_file(load_path, custom_objects=custom_objects
        )
    if 'policy_kwargs' in kwargs and kwargs['policy_kwargs'] != data[
        'policy_kwargs']:
        raise ValueError(
            'The specified policy kwargs do not equal the stored policy kwargs. Stored kwargs: {}, specified kwargs: {}'
            .format(data['policy_kwargs'], kwargs['policy_kwargs']))
    model = cls(policy=data['policy'], env=None, _init_setup_model=False)
    model.__dict__.update(data)
    model.__dict__.update(kwargs)
    model.set_env(env)
    model.setup_model()
    model.load_parameters(params)
    return model


def split_by_lines(tokens: list):
    """
    Splits given value token by lines: returns array where each entry is a token list
    for a single line
    """
    result = []
    line = []
    for t in tokens:
        if isinstance(t, str):
            lines = t.splitlines()
            line.append(lines.pop(0) if lines else '')
            while lines:
                result.append(line)
                line = [lines.pop(0) or '']
        else:
            line.append(t)
    if line:
        result.append(line)
    return result


def warp_image_filter(*args, **kwargs):
    """Procedural interface for WarpImageFilter"""
    import itk
    instance = itk.WarpImageFilter.New(*args, **kwargs)
    return instance.__internal_call__()


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


def clean_lines(lines, lstrip=None, rstrip=None, remove_empty=True,
    remove_comments=True):
    """
    clean lines (usually read from a config file):

    1. strip whitespace (left and right), 2. remove empty lines, 3. remove comments.

    note: only "pure comment lines" are supported, no support for "trailing comments".

    :param lines: input line iterator (e.g. list or open text file) that gives unclean input lines
    :param lstrip: lstrip call arguments or False, if lstripping is not desired
    :param rstrip: rstrip call arguments or False, if rstripping is not desired
    :param remove_comments: remove comment lines (lines starting with "#")
    :param remove_empty: remove empty lines
    :return: yields processed lines
    """
    for line in lines:
        if lstrip is not False:
            line = line.lstrip(lstrip)
        if rstrip is not False:
            line = line.rstrip(rstrip)
        if remove_empty and not line:
            continue
        if remove_comments and line.startswith('#'):
            continue
        yield line


def electron_shells_start(nelectrons, maxam=20):
    """Return the starting principle quantum numbers of electron shells

    For example, an ECP covering 10 electrons will covers 1s, 2s, 2p shells. The
    electrons shells will then start at 3s, 3p, 3d, and 4f (returned as [3, 3, 3, 4])

    If an ECP covers 30 electrons, then the shells will start at [5, 4, 4, 4]

    Only fully-covered shells are counted. If a shell is partly covered, an exception
    is raised.

    The returned list is extended up to maxam.

    Note: Since the main use of this is for ECPs, we only cover what can really be found
    on the periodic table. No excited states!

    Parameters
    ----------
    nelectrons : int
        Number of electrons covered by an ECP
    maxam : int
        Fill out the starting principal quantum numbers up to this am

    Returns
    -------
    list
        The starting principal quantum numbers of s, p, d, and f shells.
    """
    if nelectrons < 0:
        raise RuntimeError("Can't have a negative number of electrons")
    if nelectrons > 118:
        raise NotImplementedError(
            'Too many electrons for electrons_shells_start')
    aminfo = (0, 2), (0, 2), (1, 6), (0, 2), (1, 6), (0, 2), (2, 10), (1, 6), (
        0, 2), (2, 10), (1, 6), (0, 2), (3, 14), (2, 10), (1, 6), (0, 2), (
        3, 14), (2, 10), (1, 6)
    special_am = {(28): [0, 0, 0, 1, 1, 2], (46): [0, 0, 0, 0, 1, 1, 1, 2,
        2], (60): [0, 0, 0, 0, 1, 1, 1, 2, 2, 3], (68): [0, 0, 0, 0, 0, 1,
        1, 1, 1, 2, 2, 3], (78): [0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3], (
        92): [0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3]}
    if nelectrons in special_am:
        contained_am = special_am[nelectrons]
    else:
        contained_am = []
        for am, n in aminfo:
            if nelectrons >= n:
                nelectrons -= n
                contained_am.append(am)
            else:
                break
        if nelectrons != 0:
            raise RuntimeError(
                'Electrons cover a partial shell. {} electrons left'.format
                (nelectrons))
    start = [contained_am.count(0) + 1, contained_am.count(1) + 2,
        contained_am.count(2) + 3, contained_am.count(3) + 4]
    start.extend(range(5, maxam + 2))
    return start


def get_version():
    """Get the current r2c-cli version based on __init__"""
    from r2c.cli import __version__
    return __version__


def define_analysis_scheme(DomainName=None, AnalysisScheme=None):
    """
    Configures an analysis scheme that can be applied to a text or text-array field to define language-specific text processing options. For more information, see Configuring Analysis Schemes in the Amazon CloudSearch Developer Guide .
    See also: AWS API Documentation

    :example: response = client.define_analysis_scheme(
        DomainName='string',
        AnalysisScheme={
            'AnalysisSchemeName': 'string',
            'AnalysisSchemeLanguage': 'ar'|'bg'|'ca'|'cs'|'da'|'de'|'el'|'en'|'es'|'eu'|'fa'|'fi'|'fr'|'ga'|'gl'|'he'|'hi'|'hu'|'hy'|'id'|'it'|'ja'|'ko'|'lv'|'mul'|'nl'|'no'|'pt'|'ro'|'ru'|'sv'|'th'|'tr'|'zh-Hans'|'zh-Hant',
            'AnalysisOptions': {
                'Synonyms': 'string',
                'Stopwords': 'string',
                'StemmingDictionary': 'string',
                'JapaneseTokenizationDictionary': 'string',
                'AlgorithmicStemming': 'none'|'minimal'|'light'|'full'
            }
        }
    )

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

    :type AnalysisScheme: dict
    :param AnalysisScheme: [REQUIRED]
            Configuration information for an analysis scheme. Each analysis scheme has a unique name and specifies the language of the text to be processed. The following options can be configured for an analysis scheme: Synonyms , Stopwords , StemmingDictionary , JapaneseTokenizationDictionary and AlgorithmicStemming .
            AnalysisSchemeName (string) -- [REQUIRED]Names must begin with a letter and can contain the following characters: a-z (lowercase), 0-9, and _ (underscore).
            AnalysisSchemeLanguage (string) -- [REQUIRED]An IETF RFC 4646 language code or mul for multiple languages.
            AnalysisOptions (dict) --Synonyms, stopwords, and stemming options for an analysis scheme. Includes tokenization dictionary for Japanese.
            Synonyms (string) --A JSON object that defines synonym groups and aliases. A synonym group is an array of arrays, where each sub-array is a group of terms where each term in the group is considered a synonym of every other term in the group. The aliases value is an object that contains a collection of string:value pairs where the string specifies a term and the array of values specifies each of the aliases for that term. An alias is considered a synonym of the specified term, but the term is not considered a synonym of the alias. For more information about specifying synonyms, see Synonyms in the Amazon CloudSearch Developer Guide .
            Stopwords (string) --A JSON array of terms to ignore during indexing and searching. For example, ['a', 'an', 'the', 'of'] . The stopwords dictionary must explicitly list each word you want to ignore. Wildcards and regular expressions are not supported.
            StemmingDictionary (string) --A JSON object that contains a collection of string:value pairs that each map a term to its stem. For example, {'term1': 'stem1', 'term2': 'stem2', 'term3': 'stem3'} . The stemming dictionary is applied in addition to any algorithmic stemming. This enables you to override the results of the algorithmic stemming to correct specific cases of overstemming or understemming. The maximum size of a stemming dictionary is 500 KB.
            JapaneseTokenizationDictionary (string) --A JSON array that contains a collection of terms, tokens, readings and part of speech for Japanese Tokenizaiton. The Japanese tokenization dictionary enables you to override the default tokenization for selected terms. This is only valid for Japanese language fields.
            AlgorithmicStemming (string) --The level of algorithmic stemming to perform: none , minimal , light , or full . The available levels vary depending on the language. For more information, see Language Specific Text Processing Settings in the Amazon CloudSearch Developer Guide

    :rtype: dict
    :return: {
        'AnalysisScheme': {
            'Options': {
                'AnalysisSchemeName': 'string',
                'AnalysisSchemeLanguage': 'ar'|'bg'|'ca'|'cs'|'da'|'de'|'el'|'en'|'es'|'eu'|'fa'|'fi'|'fr'|'ga'|'gl'|'he'|'hi'|'hu'|'hy'|'id'|'it'|'ja'|'ko'|'lv'|'mul'|'nl'|'no'|'pt'|'ro'|'ru'|'sv'|'th'|'tr'|'zh-Hans'|'zh-Hant',
                'AnalysisOptions': {
                    'Synonyms': 'string',
                    'Stopwords': 'string',
                    'StemmingDictionary': 'string',
                    'JapaneseTokenizationDictionary': 'string',
                    'AlgorithmicStemming': 'none'|'minimal'|'light'|'full'
                }
            },
            'Status': {
                'CreationDate': datetime(2015, 1, 1),
                'UpdateDate': datetime(2015, 1, 1),
                'UpdateVersion': 123,
                'State': 'RequiresIndexDocuments'|'Processing'|'Active'|'FailedToValidate',
                'PendingDeletion': True|False
            }
        }
    }

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

    """
    pass


def truth(a):
    """Return True if a is true, False otherwise."""
    return True if a else False


def has_value(key, target, epsilon=0.1):
    """Returns a function that computes whether a specified value in a dict
    is within ``epsilon`` of ``target``.

    The output function takes in a dict ``d`` and returns ``True`` if the
    absolute difference between ``d[key]`` and ``target`` is less than
    ``epsilon``.

    Args:
        key: Lookup key for the value in the dict to compare.
        target: The value to compare against.
        epsilon: Maximum difference between the two values.

    Returns:
        A function that takes a dict and returns ``True`` if the absolute value
        between ``dict[key]`` and ``target`` is less than ``epsilon``.
    """
    return lambda bbox: abs(bbox[key] - target) < epsilon


def _get_omex_description(obj):
    """ Encode the id, name, and description of a model or simulation into an OMEX description

    Args:
        obj (:obj:`Biomodel` or :obj:`Simulation`): object

    Returns:
        :obj:`str`: description
    """
    desc = obj.id
    if obj.name:
        desc += ': ' + obj.name
    if obj.description:
        desc += '\n\n' + obj.description
    return desc


def xsd2dict(xsd, namespace='xsd'):
    """ Function that creates a dictionary from a xml schema with the type of element """
    types = ['xsd:integer', 'xsd:decimal', 'xsd:double', 'xsd:float',
        'xsd:duration', 'xsd:date', 'xsd:time', 'xsd:dateTime',
        'xsd:string', 'xsd:boolean']
    dct = {}
    element = '%s:element' % namespace
    elems = xsd.getElementsByTagName(element)
    for e in elems:
        val = 'complexType'
        typ = str(e.getAttribute('type'))
        lst = e.hasAttribute('maxOccurs')
        if types.count(typ) > 0:
            val = 'element'
        dct[str(e.getAttribute('name'))] = val, typ, lst
    return dct


def unsafe(f):
    """Marks a function or method as unsafe.

    ::

        @unsafe
        def delete(self):
            pass
    """
    f.unsafe_callable = True
    return f


def p_reference_variable_compound_variable(p):
    """reference_variable : compound_variable"""
    p[0] = p[1]


def echo_output(output, echo=False):
    """
    Print output if echo is True

    Parameters
    ----------
    output : str
        The output to echo

    echo : bool
        Flag to indicate if the output should be displayed.
        Default: False
    """
    if not echo:
        return
    print(output, end='')


def create_hash_table(holder):
    """
    Create a hash table for all the cells in the domain
    """
    print('Building hash table')
    holder.hash_table = dict()
    for icell in range(holder.info['ncells']):
        igrid = int(holder.get('x')[icell] / holder.get('dx')[icell])
        jgrid = int(holder.get('y')[icell] / holder.get('dx')[icell])
        kgrid = int(holder.get('z')[icell] / holder.get('dx')[icell])
        theHash = str(igrid) + ',' + str(jgrid) + ',' + str(kgrid) + ',' + str(
            int(holder.get('level')[icell]))
        holder.hash_table[theHash] = icell
    return


def get_tagged(item_type=None, userid=None, tag=None):
    """
        List <item_type> item_ids tagged as <tag> by <user_id>.

        See implementation docstring and test suite for specifications
        of return values when one or more parameters are set to None.
        """


def tab_print(polynome, longueur=0, parenthese=False, debut=0):
    """utilisé par TeX_division pour décaler le reste dans la partie gauche"""
    degre = polynome.degre_max + debut
    string = ''
    if parenthese:
        string = '-('
        fin = ')'
    else:
        fin = ''
    if polynome == 0:
        string += '+' + str(0) + ' &'
    else:
        for i in range(longueur):
            k = degre - i
            coeff = polynome.dictio.get(k, 0)
            if coeff >= 0:
                string += '+'
            string += str(coeff)
            if k != 0:
                string += polynome.var
            if k != 1 and k != 0:
                string += u'^' + str(k)
            if longueur - i == 1:
                string += fin
            string += ' & '
    return string


def __new__(cls) ->'EntityName':
    """Prevent creating abstract base class."""
    raise TypeError(f'{cls.__name__} can not be instantiated.')


def _squeeze_output(out):
    """
    Remove single-dimensional entries from array and convert to scalar,
    if necessary.

    """
    out = out.squeeze()
    if out.ndim == 0:
        out = out[()]
    return out


def bases(schemaName, tree):
    """Return the bases to use.
        """


def post_document_content(gismo, i, max_size=None):
    """
    Document indice to document content.

    Assumes that document has a 'content' key.

    Parameters
    ----------
    gismo: Gismo
        Gismo instance
    i : int
        document indice
    max_size: int, optional
        Maximum number of chars to return

    Returns
    -------
    str
        Content of document i from corpus
    """
    return gismo.corpus[i]['content'][:max_size]


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 quantized_elemwise_add(lhs=None, rhs=None, lhs_min=None, lhs_max=None,
    rhs_min=None, rhs_max=None, out=None, name=None, **kwargs):
    """elemwise_add operator for input dataA and input dataB data type of int8,
    and accumulates in type int32 for the output. For each argument, two more arguments of type
    float32 must be provided representing the thresholds of quantizing argument from data
    type float32 to int8. The final outputs contain result in int32, and min
    and max thresholds representing the threholds for quantizing the float32 output into int32.

    .. Note::
        This operator only supports forward propogation. DO NOT use it in training.

    Parameters
    ----------
    lhs : NDArray
        first input
    rhs : NDArray
        second input
    lhs_min : NDArray
        3rd input
    lhs_max : NDArray
        4th input
    rhs_min : NDArray
        5th input
    rhs_max : NDArray
        6th input

    out : NDArray, optional
        The output NDArray to hold the result.

    Returns
    -------
    out : NDArray or list of NDArrays
        The output of this function.
    """
    return 0,


@staticmethod
def _parse_lsb_release_content(lines):
    """
        Parse the output of the lsb_release command.

        Parameters:

        * lines: Iterable through the lines of the lsb_release output.
                 Each line must be a unicode string or a UTF-8 encoded byte
                 string.

        Returns:
            A dictionary containing all information items.
        """
    props = {}
    for line in lines:
        kv = line.strip('\n').split(':', 1)
        if len(kv) != 2:
            continue
        k, v = kv
        props.update({k.replace(' ', '_').lower(): v.strip()})
    return props


@staticmethod
def stop(widget, force=False):
    """
        Stops a loader widget on the inputed widget.

        :param      widget | <QWidget>
        """
    loader = getattr(widget, '_private_xloader_widget', None)
    if not loader:
        return
    count = getattr(widget, '_private_xloader_count', 0)
    if force or count <= 1:
        setattr(widget, '_private_xloader_count', 0)
        setattr(widget, '_private_xloader_widget', None)
        loader.close()
        loader.setParent(None)
        loader.deleteLater()
    else:
        setattr(widget, '_private_xloader_count', count - 1)


def powers_of_two():
    """Powers of 2, from 1"""
    n = 1
    while True:
        yield n
        n *= 2


@classmethod
def range(cls, start, end=None, step=1):
    """Create a Stream from range.

        >>> Stream.range(2, 10, 2).to_list()
        [2, 4, 6, 8]
        >>> Stream.range(3).to_list()
        [0, 1, 2]
        """
    if end is None:
        start, end = 0, start
    return cls(range(start, end, step))


def gravity_gpemgh(GPE, mass, height):
    """Usage: Find gravity from gravitational potential energy, mass and height"""
    result = GPE / mass * height
    return result


def fix_nextprog(forest_halos):
    """
    Walks the descendants of a single forest to generate the `NextProgenitor`
    field.

    Parameters
    ----------

    forest_halos : Numpy structured array with data structure defined by
                  :py:mod:`astro3D.genesis.utils.treefrog_to_lhalo.get_LHalo_datastruct`
        The halos within a single forest.

    Returns
    ----------

    forest_halos : Numpy structured array with data structure defined by
                  :py:mod:`astro3D.genesis.utils.treefrog_to_lhalo.get_LHalo_datastruct`
        The forest halos with updated ``NextProgenitor`` field.
    """
    all_descendants = forest_halos['Descendant'][:]
    for ii, d in enumerate(all_descendants):
        if d == ii:
            continue
        curr = forest_halos['FirstProgenitor'][d]
        if curr == ii:
            continue
        while forest_halos['NextProgenitor'][curr] != -1:
            curr = forest_halos['NextProgenitor'][curr]
        assert forest_halos['NextProgenitor'][curr] == -1
        forest_halos['NextProgenitor'][curr] = ii
    return forest_halos


def can_paginate(operation_name=None):
    """
    Check if an operation can be paginated.

    :type operation_name: string
    :param operation_name: The operation name. This is the same name
            as the method name on the client. For example, if the
            method name is create_foo, and you'd normally invoke the
            operation as client.create_foo(**kwargs), if the
            create_foo operation can be paginated, you can use the
            call client.get_paginator('create_foo').

    """
    pass


@classmethod
def register_signature_method(cls, name, sign):
    """Extend client signature methods.

        :param name: A string to represent signature method.
        :param sign: A function to generate signature.

        The ``sign`` method accept 2 parameters::

            def custom_sign_method(client, request):
                # client is the instance of Client.
                return 'your-signed-string'

            Client.register_signature_method('custom-name', custom_sign_method)
        """
    cls.SIGNATURE_METHODS[name] = sign


def to_bundle_ingest_dirname(ts):
    """Convert a pandas Timestamp into the name of the directory for the
    ingestion.

    Parameters
    ----------
    ts : pandas.Timestamp
        The time of the ingestions

    Returns
    -------
    name : str
        The name of the directory for this ingestion.
    """
    return ts.isoformat().replace(':', ';')