def get_prefix_url(request):
    """ Retrieve the base of short urls after computation (forest, local site).
        """


def as_tall(x):
    """ Turns a row vector into a column vector """
    return x.reshape(x.shape + (1,))


def is_equal_configuration(source_configuration, target_configuration):
    """
        Check if all outputs from target are already configured correctly in source and
        that no other outputs are active.
    """
    for output in target_configuration.keys():
        if 'off' in target_configuration[output].options:
            if (output in source_configuration and 'off' not in
                source_configuration[output].options):
                return False
        elif output not in source_configuration or source_configuration[output
            ] != target_configuration[output]:
            return False
    for output in source_configuration.keys():
        if 'off' in source_configuration[output].options:
            if (output in target_configuration and 'off' not in
                target_configuration[output].options):
                return False
        elif output not in target_configuration:
            return False
    return True


def plotLightCurves(log, lightCurves, polyOrder, pathToOutputDirectory):
    """
    *plot lightcurve(s) given an list of magnitude, time pairs*

    **Key Arguments:**
        - ``log`` -- logger
        - ``lightCurves`` -- list of magnitude, time numPy arrays
        - ``polyOrder`` -- order of polynomial used to fit the model lightcurves extracted from spectra
        - ``pathToOutputDirectory`` -- path to the output directory

    **Return:**
        - None
    """
    import matplotlib.pyplot as plt
    import numpy as np
    resultsDict = {}
    ax = plt.subplot(111)
    curveDict = {}
    for curve in lightCurves:
        x = curve[1]
        y = curve[0]
        if len(x) <= 4:
            curveDict['poly'] = None
            continue
        order = polyOrder
        poly = np.polyfit(x, y, order)
        curveDict['poly'] = poly
        pOrder = np.poly1d(poly)
        polyString = 'mxxx[i] = '
        polyStringMd = '\\\\(mag = '
        for i in range(0, order + 1):
            if i > 0 and poly[i] > 0:
                polyString += '+'
                polyStringMd += '+'
            polyString += '%s*pow(i,%s) ' % (poly[i], order - i)
            polyStringMd += '%s*time^{%s} ' % (poly[i], order - i)
        polyStringMd += '\\\\)'
        xp = np.arange(int(min(x)), int(max(x)), 0.2)
        ax.plot(x, y, '.', xp, pOrder(xp), '--')
    title = curve[5]
    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=(1, 0.5), prop={'size': 8})
    ax.titlesize = 'medium'
    ax.labelsize = 'medium'
    plt.xlabel('Days Relative to Peak')
    plt.ylabel('Magnitude')
    plt.title(title, fontsize='small', verticalalignment='bottom',
        linespacing=0.2)
    ax.invert_yaxis()
    fileName = pathToOutputDirectory + title.replace(' ', '_') + '.png'
    plt.savefig(fileName)
    plt.clf()
    return curveDict


def linalg_potrf(A=None, out=None, name=None, **kwargs):
    """Performs Cholesky factorization of a symmetric positive-definite matrix.
    Input is a tensor *A* of dimension *n >= 2*.

    If *n=2*, the Cholesky factor *B* of the symmetric, positive definite matrix *A* is
    computed. *B* is triangular (entries of upper or lower triangle are all zero), has
    positive diagonal entries, and:

      *A* = *B* \\* *B*\\ :sup:`T`  if *lower* = *true*
      *A* = *B*\\ :sup:`T` \\* *B*  if *lower* = *false*

    If *n>2*, *potrf* is performed separately on the trailing two dimensions for all inputs
    (batch mode).

    .. note:: The operator supports float32 and float64 data types only.

    Examples::

       Single matrix factorization
       A = [[4.0, 1.0], [1.0, 4.25]]
       potrf(A) = [[2.0, 0], [0.5, 2.0]]

       Batch matrix factorization
       A = [[[4.0, 1.0], [1.0, 4.25]], [[16.0, 4.0], [4.0, 17.0]]]
       potrf(A) = [[[2.0, 0], [0.5, 2.0]], [[4.0, 0], [1.0, 4.0]]]

    Defined in src/operator/tensor/la_op.cc:L214

    Parameters
    ----------
    A : NDArray
        Tensor of input matrices to be decomposed

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

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


def data_ref_type_str(dref_enum):
    """
    Translate an ``enum DataRefTypes`` value into a string representation.
    """
    if dref_enum == 36864:
        return 'unknown'
    elif dref_enum == 36865:
        return 'integer'
    elif dref_enum == 36866:
        return 'fp'
    else:
        return 'INVALID'


def all_are_equal(argument) ->bool:
    """
    Is true when ``argument`` is an iterable collection of equal items.

    ..  container:: example

        >>> abjad.mathtools.all_are_equal([99, 99, 99, 99, 99, 99])
        True

        >>> abjad.mathtools.all_are_equal(17)
        False

    ..  container:: example

        Is true when ``argument`` is empty:

        >>> abjad.mathtools.all_are_equal([])
        True

    """
    try:
        first_element = None
        for element in argument:
            if first_element is None:
                first_element = element
            elif not element == first_element:
                return False
        return True
    except TypeError:
        return False


@staticmethod
def get_available_name(name, max_length=None):
    """Return the name as-is; in CAS, given names are ignored anyway."""
    return name


@classmethod
def get_counterparty_by_name(cls, name, cp_type='Sender'):
    """
        Method for fetching info about counterparty by name.

        :example:
            ``Counterparty.get_counterparties(name='Талісман', cp_type='Recipient')``
        :param name:
            name of the desired counterparty
        :type name:
            str or unicode
        :param cp_type:
            type of the counterparty: can be either `Sender` or `Recipient` (`Sender` used as default)
        :type cp_type:
            str or unicode
        :return:
            dictionary with info about counterparty
        :rtype:
            dict
        """
    return cls.send(method='getCounterparties', method_props={
        'CounterpartyProperty': cp_type, 'FindByString': name})


def dosplot(p0='./', totonly=True, color='', label='', marker='', lw=2, ms=
    5, ls='-', ls_ef=':', lw_ef=1, units='Ry', noefline=False, interpol=
    False, allatoms=False, onespin=False, atoms=[], lmdos=False, lm=[],
    nofig=False, scale=1.0, shift=0, normalized=False, xyswitch=False,
    efcolor='', return_data=False, xscale=1.0, xshift=0.0, yshift=0.0,
    filled=False, spins=2):
    """ plotting routine for dos files """
    from numpy import loadtxt, sort, array, sum
    from matplotlib.pyplot import figure, plot, axvline, xlabel, ylabel, ion, title, figure, fill_between, axhline
    from os import listdir
    from os.path import isdir
    ion()
    if type(p0) != str:
        pathname_with_file = p0.name
        p0 = pathname_with_file.replace('/dos.atom1', '')
    if p0[-1] != '/':
        p0 += '/'
    ef = float(open(p0 + 'potential').readlines()[3].split()[1])
    first = True
    for i in sort(listdir(p0)):
        if (((i[:8] == 'dos.atom' and 'interpol' not in i) and not interpol or
            interpol and i[:17] == 'dos.interpol.atom') or 'out_ldos.atom' in
            i and 'out_lmdos.atom' not in i and not interpol or (
            'out_ldos.interpol.atom' in i and 'out_lmdos.interpol.atom' and
            interpol) and not isdir(p0 + i)):
            if lmdos:
                i = i.replace('out_ldos.', 'out_lmdos.')
            if not onespin or 'spin' + str(spins) not in i:
                iatom = i.replace('dos.', '').replace('interpol.', '').replace(
                    'atom', '').replace('out_l', '').replace('=', '').replace(
                    'm', '').split('_')[0]
                if atoms == [] or int(iatom) in atoms:
                    tmp = loadtxt(p0 + i)
                    print(p0 + i)
                    if 'rel' in units:
                        tmp[:, (0)] = tmp[:, (0)] - ef
                    if 'eV' in units:
                        tmp[:, (0)] = tmp[:, (0)] * 13.6
                        tmp[:, 1:] = tmp[:, 1:] / 13.6
                    tmp[:, (0)] = tmp[:, (0)] * xscale + xshift
                    tmp[:, (1)] = tmp[:, (1)] + yshift
                    if allatoms:
                        sgn = 1
                        if 'spin2' in i:
                            sgn = -1
                        if totonly:
                            if color == '':
                                if first:
                                    if not nofig:
                                        figure()
                                plot(tmp[:, (0)], sgn * tmp[:, (1)], marker +
                                    ls, label=label + str(i), lw=lw, ms=ms)
                            else:
                                if not nofig:
                                    figure()
                                if filled:
                                    fill_between(tmp[:, (0)], sgn * tmp[:,
                                        (1)], color=color, label=label)
                                else:
                                    plot(tmp[:, (0)], sgn * tmp[:, (1)],
                                        marker + ls, color=color, label=
                                        label, lw=lw, ms=ms)
                        else:
                            if not nofig and sgn == 1:
                                figure()
                            if color == '':
                                if lm == []:
                                    if filled:
                                        fill_between(tmp[:, (0)], sgn * tmp[:, 1:])
                                    else:
                                        plot(tmp[:, (0)], sgn * tmp[:, 1:],
                                            marker + ls, lw=lw, ms=ms)
                                else:
                                    for ilm in lm:
                                        lmname = label + ' '
                                        if ilm == 1:
                                            lmname += 's'
                                        if ilm == 2:
                                            lmname += 'p_x'
                                        if ilm == 3:
                                            lmname += 'p_y'
                                        if ilm == 4:
                                            lmname += 'p_z'
                                        if ilm == 5:
                                            lmname += 'd_{x^2-y^2}'
                                        if ilm == 6:
                                            lmname += 'd_{xz}'
                                        if ilm == 7:
                                            lmname += 'd_{z^2}'
                                        if ilm == 8:
                                            lmname += 'd_{yz}'
                                        if ilm == 9:
                                            lmname += 'd_{xy}'
                                        if ilm == 10:
                                            lmname += 'f_{-3}'
                                        if ilm == 11:
                                            lmname += 'f_{-2}'
                                        if ilm == 12:
                                            lmname += 'f_{-1}'
                                        if ilm == 13:
                                            lmname += 'f_{0}'
                                        if ilm == 14:
                                            lmname += 'f_{1}'
                                        if ilm == 15:
                                            lmname += 'f_{2}'
                                        if ilm == 16:
                                            lmname += 'f_{3}'
                                        plot(tmp[:, (0)], sgn * tmp[:, (1 + ilm
                                            )], marker + ls, lw=lw, ms=ms,
                                            label=lmname)
                            elif lm == []:
                                if filled:
                                    fill_between(tmp[:, (0)], sgn * tmp[:,
                                        1:], color=color)
                                else:
                                    plot(tmp[:, (0)], sgn * tmp[:, 1:],
                                        marker + ls, color=color, lw=lw, ms=ms)
                            else:
                                for ilm in lm:
                                    lmname = label + ' '
                                    if ilm == 1:
                                        lmname += 's'
                                    if ilm == 2:
                                        lmname += 'p_x'
                                    if ilm == 3:
                                        lmname += 'p_y'
                                    if ilm == 4:
                                        lmname += 'p_z'
                                    if ilm == 5:
                                        lmname += 'd_{x^2-y^2}'
                                    if ilm == 6:
                                        lmname += 'd_{xz}'
                                    if ilm == 7:
                                        lmname += 'd_{z^2}'
                                    if ilm == 8:
                                        lmname += 'd_{yz}'
                                    if ilm == 9:
                                        lmname += 'd_{xy}'
                                    if ilm == 10:
                                        lmname += 'f_{-3}'
                                    if ilm == 11:
                                        lmname += 'f_{-2}'
                                    if ilm == 12:
                                        lmname += 'f_{-1}'
                                    if ilm == 13:
                                        lmname += 'f_{0}'
                                    if ilm == 14:
                                        lmname += 'f_{1}'
                                    if ilm == 15:
                                        lmname += 'f_{2}'
                                    if ilm == 16:
                                        lmname += 'f_{3}'
                                    plot(tmp[:, (0)], sgn * tmp[:, (1 + ilm
                                        )], marker + ls, lw=lw, ms=ms,
                                        label=lmname, color=color)
                            title(label + ' ' + i)
                    if first:
                        d = tmp
                        d[:, 1:] = d[:, 1:] * scale
                        first = False
                    else:
                        d[:, 1:] += tmp[:, 1:] * scale
    if 'eV' in units:
        ef = ef * 13.6
    if 'rel' in units:
        ef = 0
    if lm != []:
        d = d[:, ([0, 1] + list(array(lm) + 1))]
    d[:, (1)] = sum(d[:, 2:], axis=1)
    if normalized:
        d[:, 1:] = d[:, 1:] / d[:, 1:].max()
    xlab = 'E (Ry)'
    ylab = 'DOS (states/Ry)'
    if units == 'eV':
        xlab = 'E (eV)'
        ylab = 'DOS (states/eV)'
    elif units == 'eV_rel':
        xlab = 'E-E_F (eV)'
        ylab = 'DOS (states/eV)'
    elif units == 'Ry_rel':
        xlab = 'E-E_F (Ry)'
        ylab = 'DOS (states/Ry)'
    if not allatoms:
        if totonly:
            if color == '':
                if xyswitch:
                    plot(d[:, (1)], d[:, (0)] + shift, marker + ls, label=
                        label, lw=lw, ms=ms)
                else:
                    plot(d[:, (0)] + shift, d[:, (1)], marker + ls, label=
                        label, lw=lw, ms=ms)
            elif xyswitch:
                if filled:
                    fill_between(d[:, (1)], d[:, (0)] + shift, color=color,
                        label=label)
                else:
                    plot(d[:, (1)], d[:, (0)] + shift, marker + ls, color=
                        color, label=label, lw=lw, ms=ms)
            elif filled:
                fill_between(d[:, (0)] + shift, d[:, (1)], color=color,
                    label=label)
            else:
                plot(d[:, (0)] + shift, d[:, (1)], marker + ls, color=color,
                    label=label, lw=lw, ms=ms)
        else:
            if color == '':
                if xyswitch:
                    plot(d[:, 1:], d[:, (0)] + shift, marker + ls, lw=lw, ms=ms
                        )
                else:
                    plot(d[:, (0)] + shift, d[:, 1:], marker + ls, lw=lw, ms=ms
                        )
            elif xyswitch:
                if filled:
                    fill_between(d[:, (1)], d[:, (0)] + shift, color=color)
                else:
                    plot(d[:, 1:], d[:, (0)] + shift, marker + ls, color=
                        color, lw=lw, ms=ms)
            elif filled:
                fill_between(d[:, (0)] + shift, d[:, (1)], color=color)
            else:
                plot(d[:, (0)] + shift, d[:, 1:], marker + ls, color=color,
                    lw=lw, ms=ms)
            title(label)
    if not noefline:
        if color != '' and efcolor == '':
            efcolor = color
        if efcolor == '':
            if xyswitch:
                axhline(ef, ls=ls_ef, lw=lw_ef, color='grey')
            else:
                axvline(ef, ls=ls_ef, lw=lw_ef, color='grey')
        elif xyswitch:
            axhline(ef, color=efcolor, ls=ls_ef, lw=lw_ef)
        else:
            axvline(ef, color=efcolor, ls=ls_ef, lw=lw_ef)
    if xyswitch:
        ylabel(xlab)
        xlabel(ylab)
    else:
        xlabel(xlab)
        ylabel(ylab)
    if return_data:
        return d, ef


def parse_file_line_numbers(formatted_numbers):
    """
    Parse "start,count" formatted line numbers
    """
    formatted = formatted_numbers[1:]
    formatted_parts = formatted.split(',')
    start = int(formatted_parts[0])
    count = int(formatted_parts[1]) if len(formatted_parts) > 1 else 1
    return start, count


def fill_expected_columns(source_user_df):
    """
    Populates any missing 'expected_columns' with None value if they do not yet exist.
    :param pd.DataFrame source_user_df: a Pandas DataFrame with source user details
    :return: source_user_df
    """
    expected_columns = ['source_email', 'source_full_name',
        'source_site_role', 'source_auth_setting']
    source_columns = source_user_df.columns
    for expected_column in expected_columns:
        if expected_column not in source_columns:
            source_user_df[expected_column] = None
    return source_user_df


def exponential_trace_update(trace, x, alpha_t, tau_t, dt):
    """Calculate change in cell's trace based on current trace and incoming spikes x.

    Trace updates are performed according to the following formula:

    .. math::

        trace_{t+1} = trace_{t} + \\frac{(-trace_{t} + alpha * x_{t}) * dt}{tau}

    :param trace: Current trace
    :param x: Incoming/presynaptic spikes
    :param alpha_t: Scaling factor for spike influence on trace
    :param tau_t: Trace decay time constant
    :param dt: Duration of single timestep

    :return: New trace values
    """
    trace += dt / tau_t * (-trace + alpha_t * x)
    return trace


@classmethod
def serializer_version(cls) ->int:
    """
        If the format of serialization changes, this number should be incremented.
        The `deserialize` method of this class should continue to handle the old versions as well as the
        current version.
        """
    return 1


def expand_and_mirror_patch(full_img_shape=None, orig_patch_indices=None,
    expand_by=None):
    """
    Given a patch within an image, this function select a speciified region around it if present, else mirros it.
    It is useful in neuralnetworks like u-net which look for wide range of area than the actual input image.
    :param full_img_shape: Full image shape
    :param orig_patch_indices: Four cornets of the actual patch
    :param expand_by: Expand by (x, y ) in each dimension
    :return:
    """
    i, j = int(expand_by[0] / 2), int(expand_by[1] / 2)
    p, q, r, s = orig_patch_indices
    a, b, c, d = p - i, q + i, r - j, s + j
    pad_a, pad_b, pad_c, pad_d = [0] * 4
    if a < 0:
        pad_a = i - p
        a = 0
    if b > full_img_shape[0]:
        pad_b = b - full_img_shape[0]
        b = full_img_shape[0]
    if c < 0:
        pad_c = j - r
        c = 0
    if d > full_img_shape[1]:
        pad_d = d - full_img_shape[1]
        d = full_img_shape[1]
    return a, b, c, d, [(pad_a, pad_b), (pad_c, pad_d)]


def date(args):
    """This method prints the syatem date and time"""
    import time
    l_t = time.localtime()
    t_format = (
        f'{l_t.tm_year}/{l_t.tm_mon}/{l_t.tm_mday} {l_t.tm_hour}:{l_t.tm_min}:{l_t.tm_sec}'
        )
    print(time.strftime('%a %b %d %Y %T GMT%z', time.strptime(t_format,
        '%Y/%m/%d %H:%M:%S')))


def table_width(outer_widths, outer_border, inner_border):
    """Determine the width of the entire table including borders and padding.

    :param iter outer_widths: List of widths (with padding) for each column.
    :param int outer_border: Sum of left and right outer border visible widths.
    :param int inner_border: Visible width of the inner border character.

    :return: The width of the table.
    :rtype: int
    """
    column_count = len(outer_widths)
    non_data_space = outer_border
    if column_count:
        non_data_space += inner_border * (column_count - 1)
    data_space = sum(outer_widths)
    return data_space + non_data_space


def eval_string(text):
    """Evaluate a string operand.

    :param text: The operand, including enclosing quotes.
    :return: A list of byte values.
    :raises: `ValueError` if the operand is not a valid string.
    """
    if text.startswith('"') and text.endswith('"'):
        data = []
        i = 1
        while i < len(text) - 1:
            if text[i] == '"':
                raise ValueError
            if text[i] == '\\':
                i += 1
            data.append(ord(text[i]))
            i += 1
        return data
    raise ValueError


def analyse_one_drug(master, drug):
    """Function used by :func:`multicore_analysis`

    :param master: an instance of :class:`ANOVA`
    :param drug: a valid drug name

    """
    if drug in master.individual_anova.keys():
        res = master.individual_anova[drug]
    else:
        res = master.anova_one_drug(drug_id=drug, animate=False, output=
            'dataframe')
    return drug, res


def read_n_bytes(f, N):
    """ read_n_bytes(file, n)

    Read n bytes from the given file, or less if the file has less
    bytes. Returns zero bytes if the file is closed.
    """
    bb = bytes()
    while len(bb) < N:
        extra_bytes = f.read(N - len(bb))
        if not extra_bytes:
            break
        bb += extra_bytes
    return bb


@classmethod
def get_subject_name_for_value(cls, base_namespace: str,
    schema_fully_qualified_name: str) ->str:
    """
        Returns the Avro subject name given the schema fully qualified name.

        The fully qualified name of a schema is generated according to
        "io.confluent.kafka.serializers.subject.TopicRecordNameStrategy"

        :param base_namespace: The schemas base namespace
        :param schema_fully_qualified_name: Fully qualified name of the schema
        :return: The subject name
        """
    topic = cls.get_topic(base_namespace, schema_fully_qualified_name)
    return topic + '-' + schema_fully_qualified_name


def to_struct(model):
    """Cast instance of model to python structure.

    :param model: Model to be casted.
    :rtype: ``dict``

    """
    model.validate()
    resp = {}
    for _, name, field in model.iterate_with_name():
        value = field.__get__(model)
        if value is None:
            continue
        value = field.to_struct(value)
        resp[name] = value
    return resp


@classmethod
def _is_gs_folder(cls, result):
    """Return ``True`` if GS standalone folder object.

        GS will create a 0 byte ``<FOLDER NAME>_$folder$`` key as a
        pseudo-directory place holder if there are no files present.
        """
    return cls.is_key(result) and result.size == 0 and result.name.endswith(cls
        ._gs_folder_suffix)


def db2pow(xdb):
    """Convert decibels (dB) to power

    .. doctest::

        >>> from spectrum import db2pow
        >>> p = db2pow(-10)
        >>> p
        0.1

    .. seealso:: :func:`pow2db`
    """
    return 10.0 ** (xdb / 10.0)


def p_datalines(p):
    """DataLines : DataLine
                 | DataLines DataLine"""
    if len(p) == 2:
        p[0] = [p[1]]
    else:
        p[0] = p[1] + [p[2]]


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

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


def getSliceByIndex(start, end):
    """Return a slice of the results.

        :param start: The index of the first element contained in the
            result.
        :param end: The index of the first element not contained in the
            result.
        """


@staticmethod
def delete_one_row(control_instance, index_to_remove):
    """ Delete a two columns row if a widget is found in column two

        Parameters
        ----------
        control_instance: QFrame (mandatory)
            the instance of the controller widget control we want to
            synchronize with the controller
        index_to_remove: int (mandatory)
            the row index we want to delete from the widget

        Returns
        -------
        is_deleted: bool
            True if a widget has been found and the row has been deledted,
            False otherwise
        widget: QWidget
            the widget that has been deleted. If 'is_deleted' is False return
            None
        """
    is_deleted = False
    widget_item = (control_instance.controller_widget._grid_layout.
        itemAtPosition(index_to_remove, 1))
    if widget_item is not None:
        widget = widget_item.widget()
        control_instance.controller_widget._grid_layout.removeItem(widget_item)
        widget.deleteLater()
        label_item = (control_instance.controller_widget._grid_layout.
            itemAtPosition(index_to_remove, 0))
        if label_item is not None:
            label = label_item.widget()
            control_instance.controller_widget._grid_layout.removeItem(
                label_item)
            label.deleteLater()
        is_deleted = True
    else:
        widget = None
    return is_deleted, widget


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

    The ".dev0" means dirty.

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


def generate_address(data):
    """
    generate a address dynamically by hashing.
    """
    if not isinstance(data, str):
        data = str(data)
    return hash(data) ^ hash(data) >> 2


def get_priority_elem_in_set(obj_set, priority_list):
    """Returns the highest priority element in a set.

    The set will be searched for objects in the order they appear in the
    priority list, and the first one to be found will be returned. None is
    returned if no such object is found.

    Parameters
    ---------
    obj_set : set, list
        A set or list of objects.
    priority_list : list
        A list of objects in descending order of priority.

    Returns
    -------
    object
        The highest priority object in the given set.

    Example:
    --------
    >>> obj_set = set([3, 2, 7, 8])
    >>> priority_list = [4, 8, 1, 3]
    >>> print(get_priority_elem_in_set(obj_set, priority_list))
    8
    """
    for obj in priority_list:
        if obj in obj_set:
            return obj
    return None


@classmethod
def change_context(cls, span):
    """Change the context for the life of this context manager.

        :rtype: contextmanager
        """


def infinite_dataloader(dataloader):
    """ Yield an unbounded amount of batches from a `torch.utils.data.DataLoader`.
    Parameters
    ----------
    dataloader : torch.utils.data.DataLoader
        Iterable yielding batches of data from a dataset of interest.
    """
    while True:
        for batch in dataloader:
            yield batch


def linear_gradient(temperature, temperature_height, hub_height):
    """
    Calculates the temperature at hub height using a linear gradient.

    A linear temperature gradient of -6.5 K/km is assumed. This function is
    carried out when the parameter `temperature_model` of an instance of
    the :class:`~.modelchain.ModelChain` class is
    'temperature_gradient'.

    Parameters
    ----------
    temperature : :pandas:`pandas.Series<series>` or numpy.array
        Air temperature in K.
    temperature_height : float
        Height in m for which the parameter `temperature` applies.
    hub_height : float
        Hub height of wind turbine in m.

    Returns
    -------
    :pandas:`pandas.Series<series>` or numpy.array
        Temperature at hub height in K.

    Notes
    -----

    The following equation is used [1]_:

    .. math:: T_{hub}=T_{air}-0.0065\\cdot\\left(h_{hub}-h_{T,data}\\right)

    with:
        T: temperature [K], h: height [m]

    :math:`h_{T,data}` is the height in which the temperature :math:`T_{air}`
    is measured and :math:`T_{hub}` is the temperature at hub height
    :math:`h_{hub}` of the wind turbine.

    Assumptions:

    * Temperature gradient of -6.5 K/km (-0.0065 K/m)

    References
    ----------
    .. [1] ICAO-Standardatmosphäre (ISA).
        http://www.dwd.de/DE/service/lexikon/begriffe/S/Standardatmosphaere_pdf.pdf?__blob=publicationFile&v=3

    """
    return temperature - 0.0065 * (hub_height - temperature_height)


def get_home_desktop():
    """
    Get Desktop path
    """
    import os
    return os.getenv('USERPROFILE', '') + '\\Desktop'


def url_open(url: str=''):
    """Open a website in the web-browser

    :param url: URL, URL to open
    :type url: str
    """
    pass


def _get_id(id):
    """Allow containers to override the generation of object copy id by
        attempting to call its _get_id method, if it exists.
        """


@classmethod
def after_table_cql(cls, ext_key, ext_blob):
    """
        Called to produce CQL/DDL to follow the table definition.
        Should contain requisite terminating semicolon(s).
        """
    pass


@classmethod
def deserialize(cls, dict_model):
    """Returns an unsaved class object based on the valid properties passed in."""
    kwargs = {}
    for f in cls._meta.concrete_fields:
        if f.attname in dict_model:
            kwargs[f.attname] = dict_model[f.attname]
    return cls(**kwargs)


@classmethod
def get_psu_sensor_names(cls, session, server_key, psu_num):
    """Retrieve server-specific psu sensor names
        Args:
            session:  database session
            server_key(int): key of the server sensors belongs to
            psu_num(int): psu num
        """
    query = []
    sensor_match = (
        'MATCH (:PSU {{ key: {} }})<-[:HAS_COMPONENT]-(:Asset)-[:HAS_SENSOR]->(sensor {{ num: {} }})'
        )
    label_match = map('sensor:{}'.format, ['psuCurrent', 'psuTemperature',
        'psuStatus', 'psuPower'])
    query.extend([sensor_match.format(server_key, psu_num), 'WHERE {}'.
        format(' or '.join(label_match)), 'RETURN sensor'])
    results = session.run('\n'.join(query))
    psu_names = {}
    for record in results:
        entry = dict(record.get('sensor'))
        psu_names[entry['type']] = entry['name']
    return psu_names


def one_or_none(values):
    """Fetch the first value from values, or None if values is empty. Raises
    ValueError if values has more than one thing in it."""
    if not values:
        return None
    if len(values) > 1:
        raise ValueError('Got more than one value.')
    return values[0]


def CEN_misclassification_calc(table, TOP, P, i, j, subject_class, modified
    =False):
    """
    Calculate misclassification probability of classifying.

    :param table: input matrix
    :type table : dict
    :param TOP: test outcome positive
    :type TOP : int
    :param P: condition positive
    :type P : int
    :param i: table row index (class name)
    :type i : any valid type
    :param j: table col index (class name)
    :type j : any valid type
    :param subject_class: subject to class (class name)
    :type subject_class: any valid type
    :param modified : modified mode flag
    :type modified : bool
    :return: misclassification probability of classifying as float
    """
    try:
        result = TOP + P
        if modified:
            result -= table[subject_class][subject_class]
        result = table[i][j] / result
        return result
    except (ZeroDivisionError, TypeError):
        return 'None'


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

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


def get_sessions(client, project, subject=None, session=None):
    """Query the flywheel client for a project name
    This function uses the flywheel API to find the first match of a project
    name. The name must be exact so make sure to type it as is on the
    website/GUI.
    Parameters
    ---------
    client
        The flywheel Client class object.
    project
        The name of the project to search for.
    subject
        Subject ID
    session
        Session ID

    Returns
    ---------
    seq_infos
        A list of SeqInfo objects
    """
    project_object = client.projects.find_first('label={0}'.format(project))
    context = {'project': project_object}
    if project_object is None:
        print('Available projects are:\n')
        for p in client.projects():
            print('%s' % p.label)
        raise ValueError('Could not find "{0}" project on Flywheel!'.format
            (project))
    if subject is not None:
        subject = project_object.subjects.find_one('code="{}"'.format(subject))
        sessions = subject.sessions()
    elif session is not None:
        sessions = project_object.sessions.find('label="{}"'.format(session))
    else:
        sessions = project_object.sessions()
    return sessions


@classmethod
def get_agent(cls, _id):
    """
        Provide game matching id.
        """
    return cls.AGENT_POOL[_id]


def make_where_statement(dicta=None, operator='=', separator='AND', **kwargs):
    """
    make_where_statement(operator='=', separator='AND', **kwargs) -> ('', (,))
    Makes a simple where statement, compatible with get_rows and get_row.

    Default operator used between col and value is '=' (equals)

    Available operators include everything supported by the dbms

    e.g. '>', '<', '!=', 'LIKE' (text fields), 'ILIKE', etcetera

    separator can be 'AND', 'OR' or anything else the dbms supports.

    Takes any other named arg and intperpres as a column name:value pair.
    """
    dicta = dicta if dicta else kwargs
    if not dicta:
        return '', ()
    sufstring = ''
    sufparams = []
    for key, value in dicta.iteritems():
        pref = 'WHERE' if not sufstring else separator
        sufstring += '%s %s %s ? ' % (pref, key, operator)
        sufparams.append(value)
    return sufstring, sufparams


def _matches_billing(price, hourly):
    """Return True if the price object is hourly and/or monthly."""
    return any([hourly and price.get('hourlyRecurringFee') is not None, not
        hourly and price.get('recurringFee') is not None])


def p_subscription(p):
    """subscription : primary "[" expression "]" """
    p[0] = ['SUBSCRIPTION', p[1], p[3]]


def df_to_html(caption, df):
    """DataFrame 对象转化为 table"""
    caption = '
{}
'.format(caption)
    html = ['
\n', caption, '
']
    for column in df.columns:
        html.append('' + column + '	')
    html.append('
\n')
    for row in df.values:
        tr = ['
']
        for col in row:
            tr.append('' + str(col) + '	')
        tr.append('
\n')
        html.append(''.join(tr))
    html.append('
\n')
    return ''.join(html)


def lasttrim(character, trim_this):
    """Get all contents after specified character

    ex: lasttrim('.', string)
    """
    trimmed = trim_this[trim_this.rindex(character) + 1:]
    return trimmed


def loglib(logfile, message):
    """ Generic logging function for Ganglia metric modules.

    In your program, define a logfile like so:
        logfile = '/var/log/nanigans/test.log'
        In your program call this function like so:
        loglib(logfile,'INFO:  Starting test app')

    You can also silence by adding to your program:
        logging.disable(logging.DEBUG)
    """
    import logging
    import read_config as cfg
    logging.basicConfig(level=logging.INFO, format=
        '%(asctime)s - %(name)s - %(levelname)s Thread-%(thread)d - %(message)s'
        , filename=logfile)
    logging.info(message)
    return ()


def get_exception_message(e):
    """ME ValidationError has compatibility code with py2.6
    that doesn't follow py3 .args interface. This works around that.
    """
    from mongoengine.errors import ValidationError as MEValidationError
    if isinstance(e, MEValidationError) and not e.args:
        return e.message
    else:
        return e.args[0]


def get_from_key(item, key, reduced_key=None, delimiter='.'):
    """
    nice little tool to aid in flexibility when dealing with multilayer dicts.
    """
    if type(item) is not dict:
        return item
    try:
        return item[key]
    except KeyError:
        if reduced_key is None:
            reduced_key = key.split(delimiter)[0]
        return item[reduced_key]


def replace_in_file(filepath, old, new):
    """Replace :py:obj:`old` string with :py:obj:`new` in a file.

    :param Path filepath:
    """
    with filepath.open() as f:
        content_as_string = f.read()
    content_as_string = content_as_string.replace(old, new)
    with filepath.open(mode='w') as f:
        f.write(content_as_string)


def clear():
    """Helper function to clear notebook display"""
    import IPython.display as dp
    return dp.clear_output()


def rgb_to_bw(r, g, b):
    """Method to convert rgb to a bw intensity value."""
    return 0.35 * r + 0.45 * g + 0.2 * b


def write_ind(out, triple, outfile):
    """
    Write the current output dictionary from test_individuals()
    to the file passed as an argument to the function.
    """
    for k, v in out.items():
        print(triple[0], '\t', k, '\t', triple[2], '\t', sep='', end='',
            file=outfile)
        print(v['Zscore'], '\t', sep='', end='', file=outfile)
        print(v['Pvalue'], '\t', sep='', end='', file=outfile)
        print(v['Gamma'], '\t', sep='', end='', file=outfile)
        print(v['AAAA'], '\t', sep='', end='', file=outfile)
        print(v['AAAB'], '\t', sep='', end='', file=outfile)
        print(v['AABA'], '\t', sep='', end='', file=outfile)
        print(v['AABB'], '\t', sep='', end='', file=outfile)
        print(v['AABC'], '\t', sep='', end='', file=outfile)
        print(v['ABAA'], '\t', sep='', end='', file=outfile)
        print(v['ABAB'], '\t', sep='', end='', file=outfile)
        print(v['ABAC'], '\t', sep='', end='', file=outfile)
        print(v['ABBA'], '\t', sep='', end='', file=outfile)
        print(v['BAAA'], '\t', sep='', end='', file=outfile)
        print(v['ABBC'], '\t', sep='', end='', file=outfile)
        print(v['CABC'], '\t', sep='', end='', file=outfile)
        print(v['BACA'], '\t', sep='', end='', file=outfile)
        print(v['BCAA'], '\t', sep='', end='', file=outfile)
        print(v['ABCD'], '\n', sep='', end='', file=outfile)


@classmethod
def from_values(cls, *args, **kwargs):
    """Create a new request object based on the values provided.  If
        environ is given missing values are filled from there.  This method is
        useful for small scripts when you need to simulate a request from an URL.
        Do not use this method for unittesting, there is a full featured client
        object (:class:`Client`) that allows to create multipart requests,
        support for cookies etc.

        This accepts the same options as the
        :class:`~werkzeug.test.EnvironBuilder`.

        .. versionchanged:: 0.5
           This method now accepts the same arguments as
           :class:`~werkzeug.test.EnvironBuilder`.  Because of this the
           `environ` parameter is now called `environ_overrides`.

        :return: request object
        """
    from werkzeug.test import EnvironBuilder
    charset = kwargs.pop('charset', cls.charset)
    kwargs['charset'] = charset
    builder = EnvironBuilder(*args, **kwargs)
    try:
        return builder.get_request(cls)
    finally:
        builder.close()


@staticmethod
def __split_key(key):
    """ Break the requested key into a list of items

        :param key: The config key to be validated
        :return:    List of items to traverse for the requested config value.
        """
    return key.split(u'.')


def stripnull(string, null=b'\x00'):
    """Return string truncated at first null character.

    Clean NULL terminated C strings. For unicode strings use null='\\0'.

    """
    i = string.find(null)
    return string if i < 0 else string[:i]


@staticmethod
def safe_rt(resource_type, lower=False):
    """Format the Resource Type.

        Takes Custom Indicator types with a space character and return a *safe* string.

        (e.g. *User Agent* is converted to User_Agent or user_agent.)

        Args:
           resource_type (str): The resource type to format.
           lower (bool): Return type in all lower case

        Returns:
            (str): The formatted resource type.
        """
    if resource_type is not None:
        resource_type = resource_type.replace(' ', '_')
        if lower:
            resource_type = resource_type.lower()
    return resource_type


def no_longer_stale():
    """
        Produce a new (or the original) object that is in the normal state
        and return it.

        :return: Another `IStaleAware`.
        """


def setdefaultattrs(obj, attrs):
    """
     Sets the attributes in attr if they are not contained in obj.

    :param obj:     the object to check
    :param attrs:   a dict containing attributes to check as key and a default
                    value as value.
    :return:        a copy of the object containing the default values for
                    missing attributes
    """
    for key in attrs.keys():
        if hasattr(obj, key):
            print('obj {} has {} ({})'.format(obj, key, getattr(obj, key)))
        else:
            print("obj {} doesn't have {} (default={})".format(obj, key,
                attrs[key]))
            setattr(obj, key, attrs[key])


def sec2HMS(sec):
    """Convert time in sec to H:M:S string

    :param sec: time in seconds
    :return: H:M:S string (to nearest 100th second)

    """
    H = int(sec // 3600)
    M = int(sec // 60 - H * 60)
    S = sec - 3600 * H - 60 * M
    return '%d:%2d:%.2f' % (H, M, S)


def monochrome(tag, text):
    """Basic Formatter for plain (monochrome) output"""
    label, hilight = tag
    for line in text.split('\n'):
        yield '[%s] %s\n' % (label, line)


def point_to_pixel(point, camera, pix=True):
    """ Function to compute the pixel coordinates of a given
        point in world space for a given camera.

        args:
            point  : vector 1x3 (list or numpy) [X, Y, Z]
            camera : CameraObject class
            pix    : Bool
                        Return measurement in pixel coordinates
        returns:
            list : [x, y]
                Returns None if point is not visible in camera
        """
    p = point
    c = [camera.x, camera.y, camera.z]
    r = camera.rotation_matrix
    if pix == True:
        assert camera.resolution is not None, '[error] resolution must be available to return in pixel coordinates'
    x_ = (r[0, 0] * (p[0] - c[0]) + r[1, 0] * (p[1] - c[1]) + r[2, 0] * (p[
        2] - c[2])) / (r[0, 2] * (p[0] - c[0]) + r[1, 2] * (p[1] - c[1]) +
        r[2, 2] * (p[2] - c[2]))
    y_ = (r[0, 1] * (p[0] - c[0]) + r[1, 1] * (p[1] - c[1]) + r[2, 1] * (p[
        2] - c[2])) / (r[0, 2] * (p[0] - c[0]) + r[1, 2] * (p[1] - c[1]) +
        r[2, 2] * (p[2] - c[2]))
    x_ = camera.principle_point[0] + -camera.focal_length * x_
    y_ = camera.principle_point[1] + -camera.focal_length * y_
    if abs(x_) > camera.sensor_size[0] / 2 or abs(y_) > camera.sensor_size[1
        ] / 2:
        return [None, None]
    if pix == True:
        x_ = (x_ + camera.sensor_size[0] / 2) / (camera.sensor_size[0] /
            camera.resolution[0])
        y_ = (y_ + camera.sensor_size[1] / 2) / (camera.sensor_size[1] /
            camera.resolution[1])
    return [x_, y_]


def get_display_usernames():
    """Get whether it should display usernames instead of users login
        names.
        """


def _bp_static_url(blueprint):
    """ builds the absolute url path for a blueprint's static folder """
    u = u'%s%s' % (blueprint.url_prefix or '', blueprint.static_url_path or '')
    return u


def p_expr_placeholder(p):
    """expr : PLACEHOLDER"""
    p[0] = 'placeholder', p[1]


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


def select(extend: bool=False, camera: bool=False):
    """Select time marker(s)

    :param extend: Extend, Extend the selection
    :type extend: bool
    :param camera: Camera, Select the camera
    :type camera: bool
    """
    pass


def add_cycle(G, nodes, t, **attr):
    """Add a cycle at time t.

            Parameters
            ----------

            G : graph
                A DyNetx graph

            nodes : iterable container
                A container of nodes.

            t : snapshot id (default=None)
                snapshot id

            See Also
            --------
            add_path, add_cycle

            Examples
            --------
            >>> G = dn.DynGraph()
            >>> dn.add_cycle(G, [0,1,2,3], t=0)
            """
    nlist = list(nodes)
    edges = zip(nlist, nlist[1:] + [nlist[0]])
    G.add_interactions_from(edges, t, **attr)


@classmethod
def simplify_form(cls, form: str) ->str:
    """
        TODO: figure out what transformation is needed
        :param form:
        :return:
        """
    return form.lower()


def deser_unary(ser):
    """
    unary_zero$0 = Unary ~0;
    unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1);
  """
    n = 0
    while True:
        r = ser.pop(0)
        if r:
            n += 1
        else:
            return n, ser


def _getDMSFields(decDeg, nFields=3, precision=1):
    """Return a string representation of dms fields for decDeg.

    Inputs:
    - decDeg: value in decimal degrees or hours
    - nFields: number of fields; must be >= 1 (and >3 is probably never used)
    - precision: number of digits after the decimal point in the last field;
        if 0, no decimal point is printed; must be >= 0

    Returns:
    - signStr: "" or "-"
    - fieldStrs: string value of each field (all positive)

    To compute dms a a string, use: signStr + ":".join(fieldStrs)
    This routine doesn't take that step to allow omitting fields
    whose value is zero (e.g. see dmsStrFromDeg and dmsStrFromSec).

    Error conditions:
    - Raises ValueError if precision < 0
    """
    if nFields < 1:
        raise ValueError('nFields=%r; must be >= 1' % (nFields,))
    if precision < 0:
        raise ValueError('precision=%r; must be >= 0' % (precision,))
    if decDeg < 0:
        signStr = '-'
    else:
        signStr = ''
    if nFields == 1:
        retNum = round(abs(decDeg), precision)
        retStr = '%.*f' % (precision, retNum)
        return signStr, [retStr]
    remVal = abs(decDeg)
    fieldNums = []
    for fieldNum in range(nFields - 1):
        intVal, remVal = divmod(abs(remVal), 1.0)
        intVal = int(intVal)
        fieldNums.append(intVal)
        remVal *= 60.0
    fieldNums.append(round(remVal, precision))
    incrPrevField = False
    for ind in range(nFields - 1, -1, -1):
        if incrPrevField:
            fieldNums[ind] += 1
        if ind > 0 and fieldNums[ind] >= 60:
            fieldNums[ind] -= 60
            incrPrevField = True
        else:
            incrPrevField = False
    if precision > 0:
        minFloatWidth = precision + 3
    else:
        minFloatWidth = 2
    fieldStrs = ['%d' % (fieldNums[0],)]
    for numVal in fieldNums[1:-1]:
        fieldStrs.append('%02d' % (numVal,))
    fieldStrs.append('%0*.*f' % (minFloatWidth, precision, fieldNums[-1]))
    return signStr, fieldStrs


def _make_list_type_name(model):
    """
    LIST QUERY TYPE NAME

    We need query type name. For example when we will query from graphql client end, we will be writing
    model name with lower and list with underscore or camelcase
    :param model:
    :return: a string name of query
    """
    return model.__name__.lower() + '_list'


@classmethod
def _infodict(cls, name):
    """load the info dictionary for the given name"""
    info = cls._dataset_info.get(name, None)
    if info is None:
        raise ValueError(
            'No such dataset {0} exists, use list_datasets() to get a list of available datasets.'
            .format(name))
    return info


@staticmethod
def _get_events_start_time():
    """DOES NOTHING ( Should get events start time)

        This function always returns 'n/a' to inform that it is not available

        :return: n/a always
        :rtype: str
        """
    return 'n/a'


def saveLocationHistory(history, filename):
    """Saves the given location ``history`` to the given ``filename``. See
    :func:`loadLocationHistory` and :meth:`LocationHistoryPanel.getHistory`.
    """
    lines = []
    for loc, comment in history:
        loc = '{:0.8f} {:0.8f} {:0.8f}'.format(*loc)
        lines.append('{} {}'.format(loc, comment))
    with open(filename, 'wt') as f:
        f.write('\n'.join(lines))


@classmethod
def fget(cls, obj, *default):
    """
        Returns the value contained in the function dictionary.

        Parameters
        ----------
        obj : function
            The function to acquire the value for.
        default
            The default value to return if the function is not found.
        """
    odict = cls.FUNC_DICT
    obj = '{}.{}'.format(obj.__module__, obj.__name__)
    if obj in odict:
        return odict[obj]
    elif default:
        return default[0]
    else:
        raise KeyError('Key {!r} does not exist.'.format(obj))


def _build_url(*args):
    """Build string url

    Disappointed in urllib.parse library because it does give the richness to build
    arbitrary URLs"""
    return '/'.join(args)


def merge_schemas(parent, child):
    """ Merge two json schemas.  Note that this method is asymmetric;
        if the child redefines a field present in the parent, the child's
        definition takes precedence.  But if either of them provide
        fields in the `requires` directive, those will be merged.

        :param parent: the parent operator's json schema
        :type parent: dict
        :param child: the child operator's json schema
        :type child: dict
        :returns: a new jsonschema reflecting the merger
        :rtype: dict
    """
    result = {'properties': {}}
    result['properties'].update(parent.get('properties', {}))
    result['properties'].update(child.get('properties', {}))
    required = parent.get('required', []) + child.get('required', [])
    if required:
        result['required'] = required
    for schema in [parent, child]:
        if 'additionalProperties' in schema:
            result['additionalProperties'] = schema['additionalProperties']
    extra_keys = (frozenset(parent) | frozenset(child)) - frozenset([
        'properties', 'required', 'additionalProperties'])
    if extra_keys:
        raise Exception(
            'Cannot merge schemas due to unrecognized fields: {} (parent schema: {}; child schema: {})'
            .format(extra_keys, parent, child))
    return result


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

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

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


def create_api_routing(config, api):
    """
    Central method to create the routing per api. This way a independent routing is created which takes even
    the route prefix into account.

    Args:
        config (pyramid.config.Configurator): The pyramid apps config object
        api (pyramid_georest.lib.rest.Api): The Api which the routing is bound to.
    """
    config.add_route('{api_name}/read'.format(api_name=api.name), '/' + api
        .pure_name + '/{schema_name}/{table_name}/read/{format}')
    config.add_view(api, route_name='{api_name}/read'.format(api_name=api.
        name), attr='read', request_method=(api.read_method, api.
        read_filter_method))
    config.add_route('{api_name}/count'.format(api_name=api.name), '/' +
        api.pure_name + '/{schema_name}/{table_name}/count')
    config.add_view(api, route_name='{api_name}/count'.format(api_name=api.
        name), attr='count', request_method=(api.read_method, api.
        read_filter_method), renderer='string')
    config.add_route('{api_name}/show'.format(api_name=api.name), '/' + api
        .pure_name + '/{schema_name}/{table_name}/read/{format}/*primary_keys')
    config.add_view(api, route_name='{api_name}/show'.format(api_name=api.
        name), attr='show', request_method=api.read_method)
    config.add_route('{api_name}/create'.format(api_name=api.name), '/' +
        api.pure_name + '/{schema_name}/{table_name}/create/{format}')
    config.add_view(api, route_name='{api_name}/create'.format(api_name=api
        .name), attr='create', request_method=api.create_method)
    config.add_route('{api_name}/update'.format(api_name=api.name), '/' +
        api.pure_name +
        '/{schema_name}/{table_name}/update/{format}/*primary_keys')
    config.add_view(api, route_name='{api_name}/update'.format(api_name=api
        .name), attr='update', request_method=api.update_method)
    config.add_route('{api_name}/delete'.format(api_name=api.name), '/' +
        api.pure_name +
        '/{schema_name}/{table_name}/delete/{format}/*primary_keys')
    config.add_view(api, route_name='{api_name}/delete'.format(api_name=api
        .name), attr='delete', request_method=api.delete_method)
    config.add_route('{api_name}/model'.format(api_name=api.name), '/' +
        api.pure_name + '/{schema_name}/{table_name}/model/{format}')
    config.add_view(api, route_name='{api_name}/model'.format(api_name=api.
        name), attr='model', request_method=api.read_method)
    config.add_route('{api_name}/adapter'.format(api_name=api.name), '/' +
        api.pure_name + '/{schema_name}/{table_name}/adapter/{format}')
    config.add_view(api, route_name='{api_name}/adapter'.format(api_name=
        api.name), attr='adapter', request_method=api.read_method)
    config.commit()


def tdescr(df_in, percentiles=None, disp=True):
    """
    Helper function to display and return the transposition
    of the output of DataFrame.describe(). This means that
    the columns of the input DataFrame are returned as rows
    and the various statistical values of interest are the
    columns in the result.

    It is useful when the input dataframe has a lot of columns.

    This function additionally computes the statistics on a
    larger set of percentiles than the default DataFrame.describe()
    function.
    """
    try:
        from IPython.display import display
    except ImportError:
        display = print
    if not percentiles:
        percentiles = [0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99]
    tdescr_out = df_in.describe(percentiles).T
    if disp:
        display(tdescr_out)
    return tdescr_out


def is_included_in(i1, i2):
    """ Is the interval included in i1?
        """
    return i2.inf <= i1.inf and i1.sup <= i2.sup


def plot_acf_results(acfp, outfile, maxlags=5000, yrange=(-0.4, 0.4)):
    """
    This plots the unsmoothed/smoothed ACF vs lag.

    Parameters
    ----------

    acfp : dict
        This is the dict returned from `macf_period_find` below.

    outfile : str
        The output file the plot will be written to.

    maxlags: int
        The maximum number of lags to include in the plot.

    yrange : sequence of two floats
        The y-range of the ACF vs. lag plot to use.

    """
    import matplotlib.pyplot as plt
    lags = acfp['acfresults']['lags'][:maxlags]
    smoothedacf = acfp['acf'][:maxlags]
    unsmoothedacf = acfp['acfresults']['acf'][:maxlags]
    acfparams = acfp['kwargs']['smoothfunckwargs'].copy()
    acfparams.update({'peakinterval': int(acfp['kwargs']['smoothacf'] / 2.0)})
    fig, ax1 = plt.subplots()
    ax1.plot(lags, unsmoothedacf, label='unsmoothed ACF', color='#1f77b4')
    ax1.plot(lags, smoothedacf, label='smoothed ACF', color='#ff7f0e')
    ax1.set_xlim((0, maxlags))
    ax1.set_xlabel('lags')
    acfmaxinds = acfp['acfpeaks']['maxinds']
    for i, maxind in enumerate(acfmaxinds):
        if i == 0:
            ax1.axvline(maxind, linewidth=2.0, color='red', ymin=0.2, ymax=
                0.3, label='identified ACF peaks')
        else:
            ax1.axvline(maxind, linewidth=2.0, color='red', ymin=0.2, ymax=0.3)
    plt.ylabel('ACF')
    plt.ylim(yrange)
    ax1.legend()
    plt.title('%s' % repr(acfparams))
    plt.tight_layout()
    plt.savefig(outfile)
    plt.close('all')
    return outfile


def _write_info(tracker, report, **data):
    """Write information to tracker"""
    tracker.write(text=data['func_para'][0], header=
        'Parameters for both estimated quadr. function y=max(|a|*x^2 + x + |c|, 0) (a)'
        )
    tracker.write(text=data['func_para'][1], header=
        'Parameters for both estimated quadr. function y=max(|a|*x^2 + x + |c|, 0) (c)'
        )
    if report:
        tracker.make_html()


@classmethod
def supported(cls, conn):
    """Return whether GSS MIC authentication is supported"""
    return conn.gss_mic_auth_supported()


def albuminfo():
    """
    @api {post} /music/moreinfo/albuminfo 专辑信息
    @apiVersion 1.0.0
    @apiGroup More
    @apiDescription 专辑信息

    @apiParam (Headers) {string} token 令牌
    @apiParam (Headers) {String} device_token 设备令牌
    @apiParam (Headers) {String} content_type 内容类型
    @apiParam (Headers) {String} timestamp 时间戳

    @apiParam (Body) {String} albumid 歌手编号

    @apiSuccess (Success) {Object} response 响应
    @apiSuccess (Success) {String} response.start 开始
    @apiSuccess (Success) {String} response.docs 响应文档

    @apiSuccess (Success) {String} response.docs.datainfo 数据信息
    @apiSuccess (Success) {String} response.docs.datainfo.genre 流派类型
    @apiSuccess (Success) {String} response.docs.datainfo.bitrates 比特率
    @apiSuccess (Success) {String} response.docs.datainfo.releasedate 发布日期
    @apiSuccess (Success) {String} response.docs.datainfo.label 标签
    @apiSuccess (Success) {String} response.docs.datainfo.exclusivity 歌曲版权付费模式（FREE，Normal，Purchase，ALAKA，Streaming，Cache）
    @apiSuccess (Success) {String} response.docs.datainfo.translatename 翻译名称
    @apiSuccess (Success) {String} response.docs.datainfo.version 版本
    @apiSuccess (Success) {String} response.docs.datainfo.duration 歌曲长度
    @apiSuccess (Success) {String} response.docs.datainfo.side 歌曲位于专辑的片（面）数
    @apiSuccess (Success) {String} response.docs.datainfo.explicit 脏标
    @apiSuccess (Success) {String} response.docs.datainfo.description 描述
    @apiSuccess (Success) {String} response.docs.datainfo.name 名称
    @apiSuccess (Success) {String} response.docs.datainfo.tracknumber 声音编号
    @apiSuccess (Success) {String} response.docs.datainfo.rating 收听总数
    @apiSuccess (Success) {String} response.docs.datainfo.cpItemID 出版公司单曲编号
    @apiSuccess (Success) {String} response.docs.datainfo.pinyinname 歌曲拼音名称
    @apiSuccess (Success) {String} response.docs.datainfo.languagetype 语言类型
    @apiSuccess (Success) {String} response.docs.datainfo.priceCode 价格代号

    @apiSuccess (Success) {String} response.docs.artists 歌手列表
    @apiSuccess (Success) {String} response.docs.artists.genre 歌手流派类型
    @apiSuccess (Success) {String} response.docs.artists.region 歌手区域
    @apiSuccess (Success) {String} response.docs.artists.birthday 歌手生日
    @apiSuccess (Success) {String} response.docs.artists.itemcount 歌手单曲数量
    @apiSuccess (Success) {String} response.docs.artists.translatename 歌手翻译名称
    @apiSuccess (Success) {String} response.docs.artists.imagePathMap 歌手图像路径图
    @apiSuccess (Success) {String} response.docs.artists.imagePathMap.value 歌手图像路径图值
    @apiSuccess (Success) {String} response.docs.artists.imagePathMap.key 歌手图像路径图键
    @apiSuccess (Success) {String} response.docs.artists.artistID 歌手编号
    @apiSuccess (Success) {String} response.docs.artists.description 歌手描述
    @apiSuccess (Success) {String} response.docs.artists.name 歌手名称
    @apiSuccess (Success) {String} response.docs.artists.gender 歌手性别
    @apiSuccess (Success) {String} response.docs.artists.rating 歌手收听总数
    @apiSuccess (Success) {String} response.docs.artists.pinyinname 歌手拼音名称
    @apiSuccess (Success) {String} response.docs.artists.albumcount 歌手专辑数量

    @apiSuccess (Success) {String} response.docs.itemID 单曲编号

    @apiSuccess (Success) {String} response.docs.album 专辑列表
    @apiSuccess (Success) {String} response.docs.album.genre 专辑流派类型
    @apiSuccess (Success) {String} response.docs.album.cpInfo 专辑出版公司信息
    @apiSuccess (Success) {String} response.docs.album.cpInfo.contentProviderGroupID 专辑版权唱片公司分组编号
    @apiSuccess (Success) {String} response.docs.album.cpInfo.cpGroupName 专辑出版公司组名
    @apiSuccess (Success) {String} response.docs.album.cpInfo.cpGroupAltName 专辑出版公司组名更改名
    @apiSuccess (Success) {String} response.docs.album.cpInfo.cpName 专辑出版公司名称
    @apiSuccess (Success) {String} response.docs.album.cpInfo.cpCode 专辑出版公司代号
    @apiSuccess (Success) {String} response.docs.album.cpInfo.contentProviderID 专辑版权唱片公司ID
    @apiSuccess (Success) {String} response.docs.album.albumID 专辑专辑编号
    @apiSuccess (Success) {String} response.docs.album.releasedate 专辑发布日期
    @apiSuccess (Success) {String} response.docs.album.translatename 专辑翻译名称
    @apiSuccess (Success) {String} response.docs.album.version 专辑版本
    @apiSuccess (Success) {String} response.docs.album.artists 专辑歌手
    @apiSuccess (Success) {String} response.docs.album.artists.artistname 专辑歌手名称
    @apiSuccess (Success) {String} response.docs.album.artists.artistID 专辑歌手编号
    @apiSuccess (Success) {String} response.docs.album.artists.artisttranslatename 专辑歌手翻译名称
    @apiSuccess (Success) {String} response.docs.album.artists.artistpinyinname 专辑歌手拼音名称
    @apiSuccess (Success) {String} response.docs.album.totaltrack 专辑总声音数量
    @apiSuccess (Success) {String} response.docs.album.imagePathMap 专辑图像路径图
    @apiSuccess (Success) {String} response.docs.album.imagePathMap.value 专辑图像路径图值
    @apiSuccess (Success) {String} response.docs.album.imagePathMap.key 专辑图像路径图键
    @apiSuccess (Success) {String} response.docs.album.explicit 专辑脏标
    @apiSuccess (Success) {String} response.docs.album.albumPriceCode 专辑专辑价格代号
    @apiSuccess (Success) {String} response.docs.album.description 专辑描述
    @apiSuccess (Success) {String} response.docs.album.name 专辑名称
    @apiSuccess (Success) {String} response.docs.album.totaldisk 专辑总磁盘
    @apiSuccess (Success) {String} response.docs.album.rating 专辑收听总数
    @apiSuccess (Success) {String} response.docs.album.pinyinname 专辑拼音名称
    @apiSuccess (Success) {String} response.docs.album.languagetype 专辑语言类型
    @apiSuccess (Success) {String} response.docs.itemType 单曲类型
    @apiSuccess (Success) {String} musicinfo.numFound 查找数

    @apiSuccess (Success) {Object} responseHeader 响应头
    @apiSuccess (Success) {String} responseHeader.errorinfo 错误信息
    @apiSuccess (Success) {String} responseHeader.status 状态

    @apiSuccessExample {json} Success-Response:
    {
        "data": {
            "response": {
                "start": 0,
                "docs": [
                    {
                        "datainfo": {
                            "genre": "Pop",
                            "bitrates": [
                                "LRC-LRC",
                                "MP3-128K-FTD",
                                "MP3-192K-FTD",
                                "MP3-256K-FTD",
                                "MP3-320K-FTD"
                            ],
                            "releasedate": "2010-10-22",
                            "label": "杰威尔音乐",
                            "exclusivity": 1,
                            "translatename": "阿爸",
                            "version": "",
                            "duration": "04:28",
                            "side": 1,
                            "explicit": 0,
                            "description": "",
                            "name": "阿爸",
                            "tracknumber": 1,
                            "rating": 105681,
                            "cpItemID": "GDJVR1203201_FTD",
                            "pinyinname": "A Ba",
                            "languagetype": "TWN",
                            "priceCode": ""
                        },
                        "artists": [
                            {
                                "genre": "Pop",
                                "region": "TW",
                                "birthday": "1963-03-26",
                                "itemcount": 242,
                                "translatename": "Hung Jung",
                                "imagePathMap": [
                                    {
                                        "value": "/artist/004/46822-JPG-200X200-ARTIST.jpg",
                                        "key": "JPG-200X200-ARTIST"
                                    }
                                ],
                                "artistID": 46822,
                                "description": "洪荣宏，Hung,Jung(1963～)，中国台湾地区知名艺人、主持人和歌手，台语歌坛“低音歌王”洪一峰的长子。其闽南语歌曲脍炙人口，曾横扫台湾的各个角落，是在沈文程后较早的台语歌手，1991、1993、1996获得3次金曲奖最佳台语男歌手奖，是1990-2013年间获得金曲奖最佳台语男歌手奖次数最多的男歌手，1990年获得金曲奖最佳国语男歌手奖。为台语歌曲在台湾音乐界地位的确立有重要的贡献。
洪荣宏发表声明已于2013年8月份与前妻陈施羽协议离婚。",
                                "name": "洪荣宏",
                                "gender": "Male",
                                "rating": 331611,
                                "pinyinname": "Hong Rong Hong",
                                "albumcount": 22
                            }
                        ],
                        "itemID": 488319,
                        "album": {
                            "genre": "Pop",
                            "cpInfo": [
                                {
                                    "contentProviderGroupID": 707,
                                    "cpGroupName": "杰威尔音乐",
                                    "cpGroupAltName": "杰威尔音乐",
                                    "cpName": "杰威尔音乐",
                                    "cpCode": "杰威尔音乐",
                                    "contentProviderID": 6157
                                }
                            ],
                            "albumID": 55090,
                            "releasedate": "2010-10-22",
                            "translatename": "阿爸",
                            "version": "",
                            "artists": [
                                {
                                    "artistname": "周杰伦",
                                    "artistID": 6478,
                                    "artisttranslatename": "Jay Chou",
                                    "artistpinyinname": "Zhou Jie Lun"
                                }
                            ],
                            "totaltrack": 1,
                            "imagePathMap": [
                                {
                                    "value": "/album/005/55090-JPG-240X240-ALBUM.jpg",
                                    "key": "JPG-240X240-ALBUM"
                                }
                            ],
                            "explicit": 0,
                            "albumPriceCode": -1,
                            "name": "阿爸",
                            "totaldisk": 1,
                            "rating": 62792,
                            "pinyinname": "A Ba",
                            "languagetype": "TWN"
                        },
                        "itemType": "FTD"
                    }
                ],
                "numFound": 1
            },
            "responseHeader": {
                "errorinfo": "",
                "status": "00"
            }
        }
    }

    @apiError (Error) 31007 No album id in the request params!

    @apiErrorExample {json} Error-Response:
    {
        "data": "No album id in the request params!"
    }
    """


def reverseByteOrder(data):
    """Reverses the byte order of an int (16-bit) or long (32-bit)
    value.
    """
    byteCount = len(hex(data)[2:].replace('L', '')[::2])
    val = 0
    for i in range(byteCount):
        val = val << 8 | data & 255
        data >>= 8
    return val


def good_tag(tag, starts='NVJA'):
    """ true for noun,verb, adjective and adverb tags"""
    c = tag[0]
    return c in starts


def as_dotted(dotted_str):
    """
    Implement RFC 5396 to support 'asdotted' notation for BGP AS numbers.
    Provide a string in format of '1.10', '65000.65015' and this will return
    a 4-byte decimal representation of the AS number.
    Get the binary values for the int's and pad to 16 bits if necessary
    (values <255). Concatenate the first 2 bytes with second 2 bytes then
    convert back to decimal. The maximum for low and high order values is
    65535 (i.e. 65535.65535).

    :param str dotted_str: asdotted notation for BGP ASN
    :rtype: int
    """
    if '.' not in dotted_str:
        return dotted_str
    max_byte = 65535
    left, right = map(int, dotted_str.split('.'))
    if left > max_byte or right > max_byte:
        raise ValueError(
            'The max low and high order value for a 32-bit ASN is 65535')
    binval = '{0:016b}'.format(left)
    binval += '{0:016b}'.format(right)
    return int(binval, 2)


def nernst_planck_vector(c, gc, gv, u, D, z, T, p):
    """
     Calculate the flux component of the Nernst-Planck equation
     along a directional gradient (e.g. gap junction)

     Parameters
     ------------

    c:     concentration
    gc:   concentration gradient
    gv:   voltage gradient
    u:    fluid velocity
    D:     diffusion constant, D
    z:     ion charge
    T:     temperature
    p:     parameters object

    Returns
    --------
    fx, fx        mass flux in x and y directions
    """
    alpha = D * z * p.q / (p.kb * T)
    f = -D * gc - alpha * gv * c + u * c
    return f


def label_axes(ax, labels=[], **kwargs):
    """
    Convenience function for labelling rectilinear and ternary axes.

    Parameters
    -----------
    ax : :class:`~matplotlib.axes.Axes`
        Axes to label.
    labels : :class:`list`
        List of labels: [x, y] | or [t, l, r]
    """
    if ax.name == 'ternary' and len(labels) == 3:
        tvar, lvar, rvar = labels
        ax.set_tlabel(tvar, **kwargs)
        ax.set_llabel(lvar, **kwargs)
        ax.set_rlabel(rvar, **kwargs)
    elif len(labels) == 2:
        xvar, yvar = labels
        ax.set_xlabel(xvar, **kwargs)
        ax.set_ylabel(yvar, **kwargs)
    else:
        raise NotImplementedError


def rm_incomplete_des_asc(des_mask, asc_mask):
    """Remove descents-ascents that have no corresponding ascent-descent

    Args
    ----
    des_mask: ndarray
        Boolean mask of descents in the depth data
    asc_mask: ndarray
        Boolean mask of ascents in the depth data

    Returns
    -------
    des_mask: ndarray
        Boolean mask of descents with erroneous regions removed
    asc_mask: ndarray
        Boolean mask of ascents with erroneous regions removed
    """
    from . import utils
    des_start, des_stop = utils.contiguous_regions(des_mask)
    asc_start, asc_stop = utils.contiguous_regions(asc_mask)
    des_mask = utils.rm_regions(des_mask, asc_mask, des_start, des_stop)
    asc_mask = utils.rm_regions(asc_mask, des_mask, asc_start, asc_stop)
    return des_mask, asc_mask


@classmethod
def get_perceval_params_from_url(cls, urls):
    """ Get the perceval params given the URLs for the data source """
    params = []
    dparam = cls.get_arthur_params_from_url(urls)
    params.append(dparam['url'])
    return params


def unregisterApplication(appId):
    """ unregister Application with all configlets """


def flatten(x):
    """Generator of values from a 2d collection"""
    for y in x:
        yield from y


def extract_utf8_file_from_zip(zip, filename):
    """
    Python's zip library returns bytes, not unicode strings. So we need to
    convert Medium posts into utf-8 manually before we parse them.
    :param zip: Medium export zip file
    :param filename: post export filename to pull out as utf-8
    :return: utf-8 string data for a file
    """
    with zip.open(filename) as file:
        data = file.read().decode('utf8')
    return data


def item_straat_adapter(obj, request):
    """
    Adapter for rendering an object of
    :class:`crabpy.gateway.crab.Straat` to json.
    """
    return {'id': obj.id, 'label': obj.label, 'namen': obj.namen, 'status':
        {'id': obj.status.id, 'naam': obj.status.naam, 'definitie': obj.
        status.definitie}, 'taal': {'id': obj.taal.id, 'naam': obj.taal.
        naam, 'definitie': obj.taal.definitie}, 'metadata': {'begin_tijd':
        obj.metadata.begin_tijd, 'begin_datum': obj.metadata.begin_datum,
        'begin_bewerking': {'id': obj.metadata.begin_bewerking.id, 'naam':
        obj.metadata.begin_bewerking.naam, 'definitie': obj.metadata.
        begin_bewerking.definitie}, 'begin_organisatie': {'id': obj.
        metadata.begin_organisatie.id, 'naam': obj.metadata.
        begin_organisatie.naam, 'definitie': obj.metadata.begin_organisatie
        .definitie}}, 'bounding_box': obj.bounding_box}


def extract_container_id(line):
    """
        Extract container id from a Running in line

         ---> Running in 816abeca3961
    """
    parts = line.strip().split(' ')
    if len(parts) == 4:
        return parts[3]
    else:
        raise Exception('Unrecognized docker running in line: ' + line)


def get_intervar_ranges(theta):
    """ theta (dict): parameters dictionary
    """
    if 'st' in theta.keys():
        theta['t_lo'] = theta['tr'] - theta['st'] / 2
        theta['t_hi'] = theta['tr'] + theta['st'] / 2
    if 'sz' in theta.keys():
        theta['z_lo'] = theta['z'] - theta['sz'] / 2
        theta['z_hi'] = theta['z'] + theta['sz'] / 2
    return theta


def add_vertex_slide(MASK_OT_add_vertex=None, MASK_OT_slide_point=None):
    """Add new vertex and slide it

    :param MASK_OT_add_vertex: Add Vertex, Add vertex to active spline
    :param MASK_OT_slide_point: Slide Point, Slide control points
    """
    pass


@staticmethod
def continuous(arr):
    """
        Return True if array is continuous

        Parameters
        ----------
        arr : numpy.array or pandas.series
            Must have a dtype

        Returns
        -------
        out : bool
            Whether array `arr` is continuous
        """
    return arr.dtype.kind in 'ifuc'


@classmethod
def create_log(cls, name, description=None, resource_type='security_group',
    resource_id=None, target_id=None, event='ALL', enabled=True):
    """Wrapper utility that returns a test log object."""
    log_args = {'name': name, 'description': description, 'resource_type':
        resource_type, 'resource_id': resource_id, 'target_id': target_id,
        'event': event, 'enabled': enabled}
    body = cls.admin_client.create_log(**log_args)
    log_object = body['log']
    cls.log_objects.append(log_object)
    return log_object


def chunks(l, n):
    """
    Yield successive n-sized chunks from l.

    Parameters
    ----------

    l : list

    n : size of chunk

    Returns
    -------
    generator
    """
    for i in range(0, len(l), n):
        yield l[i:i + n]


@staticmethod
def is_connected():
    """Returns the current connection status. This function must be overridden.
        :return: True-like value when connection is available,
                 False-like value otherwise."""
    return False


@staticmethod
def serialize(obj: object) ->bytes:
    """Serialize a _key to bytes."""
    raise NotImplementedError


def get_list(cls, *fields):
    """
        List of *fields.
        :param fields: Field name of `Option`. Such as `code`, (`name`, `code`), [`code`, `name`, `text`] or etc.
        :return: List of *fields tuple or single value.
        """
    if len(fields) == 0:
        raise ValueError('No fields argument found.')
    found_fields = set()
    for f in fields:
        if f not in ['code', 'name', 'text']:
            raise NameError(
                "'%s' is incorrect Option field. Only 'code', 'name' and 'text' are available."
                 % str(f))
        if f in found_fields:
            raise ValueError("Duplicated fields '%s' found." % str(f))
        found_fields.add(f)
    lst = []
    for o in cls.__get_name_options_mapping().values():
        value = []
        for f in fields:
            value.append(getattr(o, f))
        lst.append(value[0] if len(value) == 1 else tuple(value))
    return lst


def load_ignore(vcs='git', type='service'):
    """ a method to retrieve the module template vcs ignore text """
    from os import path
    from pocketlab import __module__
    from importlib.util import find_spec
    module_path = find_spec(__module__).submodule_search_locations[0]
    file_text = ''
    if vcs.lower() in ('git', 'mercurial'):
        file_name = 'models/gitignore'
        if type.lower() == 'python':
            file_name += '.python'
        elif type.lower() == 'node':
            file_name += '.node'
        else:
            file_name += '.service'
        file_name += '.txt'
        file_path = path.join(module_path, file_name)
        file_text = open(file_path).read()
    if vcs.lower() == 'mercurial':
        import re
        wildcard_regex = re.compile('\n\\*\\.')
        file_text = wildcard_regex.sub('\n.', file_text)
        file_regex = re.compile('\n\\..*')
        file_text = file_regex.sub(lambda x: '%s$' % x.group(0) if x.group(
            0).find('/') == -1 else x.group(0), file_text)
        file_text = file_text.replace('.', '\\.')
        file_text = file_text.replace('\\.gitignore', ' .hgignore')
    elif vcs.lower() == 'docker':
        file_path = path.join(module_path, 'models/dockerignore.txt')
        file_text = open(file_path).read()
    return file_text


def give_figure(n, singular, plural=None):
    """Combine a number with a unit, whose word can be singular or plural.

    Parameters
    ----------
    n : int
        The number.
    singular : str
        The singular word.
    plural : str
        The plural word. Default: the singular with a final 's'.

    Returns
    -------
    str
        The number and the word.

    Examples
    --------
        >>> give_figure(1, 'apple')
        '1 apple'
        >>> give_figure(2, 'apple')
        '2 apples'
        >>> give_figure(1, 'equilibrium', 'equilibria')
        '1 equilibrium'
        >>> give_figure(2, 'equilibrium', 'equilibria')
        '2 equilibria'
    """
    if n <= 1:
        return str(n) + ' ' + singular
    elif plural is None:
        return str(n) + ' ' + singular + 's'
    else:
        return str(n) + ' ' + plural


def maybe_int(x):
    """Try to convert x' to int, or return x' if that fails."""
    try:
        return int(x)
    except ValueError:
        return x


def bisection(func, a, b, args=(), xtol=1e-10, maxiter=400):
    """Bisection root-finding method.  Given a function and an interval with
    func(a) * func(b) < 0, find the root between a and b.
    """
    if b < a:
        a, b = b, a
    i = 1
    eva = func(a, *args)
    evb = func(b, *args)
    assert eva * evb < 0, 'Must start with interval with func(a) * func(b) <0'
    while i <= maxiter:
        dist = (b - a) / 2.0
        p = a + dist
        if dist / max(1.0, abs(p)) < xtol:
            return p
        ev = func(p, *args)
        if ev == 0:
            return p
        i += 1
        if ev * eva > 0:
            a = p
        else:
            b = p
    raise RuntimeError('bisection failed after %d iterations.' % maxiter)


def bool_element(element, name, default=True):
    """
    Returns the bool value of an element, or a default if it's not defined
    :param element: The XML Element object
    :type  element: etree._Element

    :param name: The name of the element to evaluate
    :type  name: str

    :param default: The default value to return if the element is not defined
    :type  default: bool
    """
    element_value = element.find(name)
    if element_value is not None:
        return element_value.text == 'true'
    return default


def predict(model, **kwargs):
    """
    Make predictions from the model
    """
    return model._OLS.predict(exog=dict(kwargs))


def _extract_fieldpart(s):
    """Split a field definition into exactly two __-separated parts. If
    there are no __ in the field definition, leave the second part empty."""
    idx = s.find('__')
    if idx < 0:
        return s, ''
    else:
        return s[:idx], s[idx + 2:]


def hex_to_rgb(x):
    """Convert a color hexcode to an rgb tuple.

    Example
    -------
    >>> rgb('#FFFFFF')
    (255, 255, 255)
    """
    if not (x.startswith('#') and len(x) == 7):
        raise ValueError('Invalid hex color')
    x = x.strip('#')
    try:
        return int(x[:2], 16), int(x[2:4], 16), int(x[4:], 16)
    except ValueError:
        raise ValueError('Invalid hex color')


@classmethod
def restore_ids(cls, obj, ids):
    """
        Given an list of ids as captured with capture_ids, restore the
        ids. Note the structure of an object must not change between
        the calls to capture_ids and restore_ids.
        """
    ids = iter(ids)
    obj.traverse(lambda o: setattr(o, 'id', next(ids)))


def debug(message, source='debug'):
    """
	Get function or class for console print.

	Parameters
	----------
	message : :class:`str`
		Log message.
	source : :class:`str`
		Origin of call. Either debug or timestamp.

	"""
    import inspect
    if source == 'debug':
        caller = inspect.getframeinfo(inspect.stack()[1][0])
        event = '%s, line %d, in processing.%s(), %s' % (caller.filename,
            caller.lineno, caller.function, message)
        print(event)
    elif source == 'timestamp':
        caller = inspect.getframeinfo(inspect.stack()[1][0])
        event = 'processing.%s()' % caller.function
    return event


def find_number(formula, current_ind):
    """Returns the stoichiometry of an element from a formula

    :param formula: a string of the formula
    :param current_ind: the current parsing index
    :returns: a tuple: new parsing index, stoichiometry coefficient
    """
    k = current_ind
    while k < len(formula) and (formula[k].isdigit() or formula[k] == '.'):
        k += 1
    if k > len(formula):
        stoech = 1.0
    elif formula[current_ind:k]:
        stoech = float(formula[current_ind:k])
    else:
        stoech = 1.0
    return k, stoech


@staticmethod
def _link_nodes(child, parent) ->None:
    """make node a child of a parent"""
    child.left.right = child.right
    child.right.left = child.left
    child.parent = parent
    if not parent.child:
        parent.child = child.right = child.left = child
    else:
        current_child = parent.child
        child.left = current_child
        child.right = current_child.right
        current_child.right.left = child
        current_child.right = child
    parent.degree += 1
    child.marked = False


def two_item_combos(items):
    """Iterates over the 2-item sets from items.

    Doesn't check that items are unique.
    """
    total = len(items)
    for i in range(total - 1):
        curr_i = items[i]
        for j in range(i + 1, total):
            yield curr_i, items[j]


@staticmethod
def is_field_blank(field, **kwargs):
    """Return True if django field is blank."""
    return field.blank


def normalizeCode(codestring):
    """
    Function to normalize the given code.

    @param codestring code to be normalized (string)
    @return normalized code (string)
    """
    codestring = codestring.replace('\r\n', '\n').replace('\r', '\n')
    if codestring and codestring[-1] != '\n':
        codestring = codestring + '\n'
    return codestring


def python_3000_not_equal(logical_line):
    """New code should always use != instead of <>.

    The older syntax is removed in Python 3.

    Okay: if a != 'no':
    W603: if a <> 'no':
    """
    pos = logical_line.find('<>')
    if pos > -1:
        yield pos, "W603 '<>' is deprecated, use '!='"


def lock_all():
    """Lock all Grease Pencil layers to prevent them from being accidentally modified

    """
    pass


def load_factor(ts, resolution=None, norm=None):
    """
    Calculate the ratio of input vs. norm over a given interval.

    Parameters
    ----------
    ts : pandas.Series
        timeseries
    resolution : str, optional
        interval over which to calculate the ratio
        default: resolution of the input timeseries
    norm : int | float, optional
        denominator of the ratio
        default: the maximum of the input timeseries

    Returns
    -------
    pandas.Series
    """
    if norm is None:
        norm = ts.max()
    if resolution is not None:
        ts = ts.resample(rule=resolution).mean()
    lf = ts / norm
    return lf


def batch_tasks(n_tasks, n_batches, arr=None, args=None, start_idx=0):
    """Split the tasks into some number of batches to sent out to MPI workers.

    Parameters
    ----------
    n_tasks : int
        The total number of tasks to divide.
    n_batches : int
        The number of batches to split the tasks into. Often, you may want to do
        ``n_batches=pool.size`` for equal sharing amongst MPI workers.
    arr : iterable (optional)
        Instead of returning indices that specify the batches, you can also
        directly split an array into batches.
    args : iterable (optional)
        Other arguments to add to each task.
    start_idx : int (optional)
        What index in the tasks to start from?

    """
    if args is None:
        args = []
    args = list(args)
    tasks = []
    if n_batches > 0 and n_tasks >= n_batches:
        base_batch_size = n_tasks // n_batches
        rmdr = n_tasks % n_batches
        i1 = start_idx
        for i in range(n_batches):
            i2 = i1 + base_batch_size
            if i < rmdr:
                i2 += 1
            if arr is None:
                tasks.append([(i1, i2), i1] + args)
            else:
                tasks.append([arr[i1:i2], i1] + args)
            i1 = i2
    elif arr is None:
        tasks.append([(start_idx, n_tasks + start_idx), start_idx] + args)
    else:
        tasks.append([arr[start_idx:n_tasks + start_idx], start_idx] + args)
    return tasks


def findPackagePath(modulePath):
    """
    Try to find the sys.path entry from a modulePath object, simultaneously
    computing the module name of the targetted file.
    """
    p = modulePath
    l = [p.basename().split('.')[0]]
    while p.parent() != p:
        for extension in ['py', 'pyc', 'pyo', 'pyd', 'dll']:
            sib = p.sibling('__init__.' + extension)
            if sib.exists():
                p = p.parent()
                l.insert(0, p.basename())
                break
        else:
            return p.parent(), '.'.join(l)


def basename(path):
    """Use for Windows compatibility.

    """
    pass


def solar_true_anomaly(solar_geometric_mean_anomaly, solar_equation_of_center):
    """Returns the Solar True Anomaly with Solar Geometric Mean Anomaly,
    solar_geometric_mean_anomaly, and Solar Equation of Center,
    solar_equation_of_center."""
    solar_true_anomaly = (solar_geometric_mean_anomaly +
        solar_equation_of_center)
    return solar_true_anomaly


def escape(s):
    """Replace potential special characters with escaped version.

    For example, \\n => \\\\n and \\t => \\\\t

    :param s: string to escape
    """
    return s.replace('\n', '\\n').replace('\t', '\\t').replace('\r', '\\r')


def _convert_conv_param(param):
    """
    Convert convolution layer parameter from Caffe to MXNet
    """
    param_string = 'num_filter=%d' % param.num_output
    pad_w = 0
    pad_h = 0
    if isinstance(param.pad, int):
        pad = param.pad
        param_string += ', pad=(%d, %d)' % (pad, pad)
    elif len(param.pad) > 0:
        pad = param.pad[0]
        param_string += ', pad=(%d, %d)' % (pad, pad)
    else:
        if isinstance(param.pad_w, int):
            pad_w = param.pad_w
        if isinstance(param.pad_h, int):
            pad_h = param.pad_h
        param_string += ', pad=(%d, %d)' % (pad_h, pad_w)
    if isinstance(param.kernel_size, int):
        kernel_size = param.kernel_size
        param_string += ', kernel=(%d,%d)' % (kernel_size, kernel_size)
    elif len(param.kernel_size) > 0:
        kernel_size = param.kernel_size[0]
        param_string += ', kernel=(%d,%d)' % (kernel_size, kernel_size)
    else:
        assert isinstance(param.kernel_w, int)
        kernel_w = param.kernel_w
        assert isinstance(param.kernel_h, int)
        kernel_h = param.kernel_h
        param_string += ', kernel=(%d,%d)' % (kernel_h, kernel_w)
    stride = 1
    if isinstance(param.stride, int):
        stride = param.stride
    else:
        stride = 1 if len(param.stride) == 0 else param.stride[0]
    param_string += ', stride=(%d,%d)' % (stride, stride)
    dilate = 1
    if hasattr(param, 'dilation'):
        if isinstance(param.dilation, int):
            dilate = param.dilation
        else:
            dilate = 1 if len(param.dilation) == 0 else param.dilation[0]
    param_string += ', no_bias=%s' % (not param.bias_term)
    if dilate > 1:
        param_string += ', dilate=(%d, %d)' % (dilate, dilate)
    if isinstance(param.group, int):
        if param.group != 1:
            param_string += ', num_group=%d' % param.group
    return param_string


def t_data_error(t):
    """
    Error handling in data state.
    """
    print("Illegal data character '%s'" % t.value[0])
    t.lexer.skip(1)


def is_figure() ->bool:
    """
    ``True`` only if one or more figures are currently open with the
    :mod:`matplotlib.pyplot` GCF API.
    """
    from matplotlib import pyplot
    return bool(pyplot.get_fignums())


def connect_hair(all: bool=False):
    """Connect hair to the emitter mesh

    :param all: All hair, Connect all hair systems to the emitter mesh
    :type all: bool
    """
    pass


def check_zeros(counts):
    """
    helper function to check if vector is all zero
    :param counts:
    :return: bool
    """
    if sum(counts) == 0:
        return True
    else:
        return False


@classmethod
def from_sysdisk(cls, label):
    """Retrieve disk id from available system disks"""
    disks = cls.safe_call('hosting.disk.list', {'name': label})
    if len(disks):
        return disks[0]['id']


@staticmethod
def serializable() ->bool:
    """ Whether or not this class supports state serialization.

        (This always returns True for TicTacToe)

        Returns
        -------
        is_serializable : bool
            True
        """
    return True


def get(key):
    """Fetch an IStatusUpdate by IStatusUpdate.id key."""


def _align_token_list(text, token_list, char_offset=0):
    """Align list of string tokens to text and return list of Token objects."""
    token_spans = []
    for text_token in token_list:
        start = text.index(text_token, char_offset)
        token_spans.append((start, start + len(text_token)))
        char_offset = start + len(text_token)
    return char_offset, token_spans


@staticmethod
def reset(sample_idx):
    """Reset layer variables."""
    pass


def saveInitialControlFile(jsonParams, originalControlFile):
    """
        Save the adaptive control file jsonParams in originalControlFile

        :param jsonParams: Input control file in JSON format
        :type jsonParams: str
        :param originalControlFile: Path where to save the control file
        :type originalControlFile: str
    """
    with open(originalControlFile, 'w') as f:
        with open(jsonParams, 'r') as fr:
            jsonFile = fr.read()
        f.write(jsonFile)


def plot_biocomp(ax, yc, yh, y_rm1, y_rm2, y_rm3):
    """
    Plot characterization of biomass sample and calculated reference mixtures
    as mass fractions, dry ash-free basis.

    Parameters
    ----------
    ax : Axes
        The Matplotlib axes from a figure
    yc : float
        Mass fraction of carbon in biomass, dry ash free basis [-]
    yh : float
        Mass fraction of hydrogen in biomass, dry ash free basis [-]
    y_rm1 : array
        Mass fraction of reference mixture RM1 where y_rm1 = [yC, yH, yO]
    y_rm2 : array
        Mass fraction of reference mixture RM2 where y_rm2 = [yC, yH, yO]
    y_rm3 : array
        Mass fraction of reference mixture RM3 where y_rm3 = [yC, yH, yO]

    Returns
    -------
    ax : Axes
        The Matplotlib axes for the plot figure
    """
    ax.plot(yc, yh, '^', label='biomass')
    ax.plot(0.4444, 0.0617, 'o')
    ax.annotate('cell', xy=(0.4444, 0.0617), xytext=(-10, 6), textcoords=
        'offset points')
    ax.plot(0.4545, 0.0606, 'o')
    ax.annotate('hemi', xy=(0.4545, 0.0606), xytext=(-10, -12), textcoords=
        'offset points')
    ax.plot(0.6977, 0.0543, 'o')
    ax.annotate('ligc', xy=(0.6977, 0.0543), xytext=(-10, -12), textcoords=
        'offset points')
    ax.plot(0.6055, 0.0642, 'o')
    ax.annotate('ligh', xy=(0.6055, 0.0642), xytext=(-10, 6), textcoords=
        'offset points')
    ax.plot(0.5687, 0.0521, 'o')
    ax.annotate('ligo', xy=(0.5687, 0.0521), xytext=(-10, -12), textcoords=
        'offset points')
    ax.plot(0.5921, 0.0395, 'o')
    ax.annotate('tann', xy=(0.5921, 0.0395), xytext=(-10, -12), textcoords=
        'offset points')
    ax.plot(0.7634, 0.1116, 'o')
    ax.annotate('tgl', xy=(0.7634, 0.1116), xytext=(-6, -12), textcoords=
        'offset points')
    x = 0.4444, 0.5921, 0.6977, 0.7634
    y = 0.0617, 0.0395, 0.0543, 0.1116
    ax.fill(x, y, '0.8', alpha=0.5)
    ax.plot(y_rm1[0], y_rm1[1], 's', label='rm1')
    ax.plot(y_rm2[0], y_rm2[1], 's', label='rm2')
    ax.plot(y_rm3[0], y_rm3[1], 's', label='rm3')
    x = y_rm1[0], y_rm2[0], y_rm3[0], y_rm1[0]
    y = y_rm1[1], y_rm2[1], y_rm3[1], y_rm1[1]
    ax.plot(x, y, 'k:')
    ax.grid(color='0.9')
    ax.set_axisbelow(True)
    ax.set_frame_on(False)
    ax.set_xlabel('Carbon mass fraction, daf basis [-]')
    ax.set_ylabel('Hydrogen mass fraction, daf basis [-]')
    ax.tick_params(color='0.9')
    ax.legend(frameon=False)
    return ax


@classmethod
def get_dbmodel_attribute_name(cls, attr_name):
    """
        Given the name of an attribute of the entity class give the corresponding name of the attribute
        in the db model.  It if doesn't exit this raises a ValueError

        :param attr_name:
        :return: the dbmodel attribute name
        :rtype: str
        """
    if hasattr(cls.MODEL_CLASS, attr_name):
        return attr_name
    raise ValueError("Unknown attribute '{}'".format(attr_name))


def launch(url, wait=False, locate=False):
    """This function launches the given URL (or filename) in the default
    viewer application for this file type.  If this is an executable, it
    might launch the executable in a new session.  The return value is
    the exit code of the launched application.  Usually, ``0`` indicates
    success.

    Examples::

        click.launch('http://click.pocoo.org/')
        click.launch('/my/downloaded/file', locate=True)

    .. versionadded:: 2.0

    :param url: URL or filename of the thing to launch.
    :param wait: waits for the program to stop.
    :param locate: if this is set to `True` then instead of launching the
                   application associated with the URL it will attempt to
                   launch a file manager with the file located.  This
                   might have weird effects if the URL does not point to
                   the filesystem.
    """
    from ._termui_impl import open_url
    return open_url(url, wait=wait, locate=locate)


@classmethod
def named_parameters(cls):
    """
        Returns the list of all supported named parameters. There are 3 possibilities:

        - if this method returns None (that's default), any named params are supported as-is,
          whetever client set, is sent to the run method,
        - if this method returns list of names, all user-specified named params are matched
          against this list, including support for using shortened/truncated versions, unknown
          params or non-unique are treated as errors
        - if this method returns empty list, named params are not supported and treated as errors,
        """
    return None


def _log_removed_output(log_file, original, new, type_):
    """
    function writing the output of functions that remove datapoints to a log file.

    Parameters
    ----------
    log_file : str
        string containing the directory to the log file to be written out
    original : int
        original length of the dataset
    new : int
        length of the new dataset
    type_ : str
        'removed' or 'dropped'
    """
    log_file = open(log_file, 'a')
    log_file.write(str('\nOriginal dataset: ' + str(original) +
        ' datapoints; new dataset: ' + str(new) + ' datapoints' + str(
        original - new) + ' datapoints ', type_))
    log_file.close()