def __call__(cls, value, names=None, module=None, type=None, start=1):
    """Either returns an existing member, or creates a new enum class.

        This method is used both when an enum class is given a value to match
        to an enumeration member (i.e. Color(3)) and for the functional API
        (i.e. Color = Enum('Color', names='red green blue')).

        When used for the functional API: `module`, if set, will be stored in
        the new class' __module__ attribute; `type`, if set, will be mixed in
        as the first base class.

        Note: if `module` is not set this routine will attempt to discover the
        calling module by walking the frame stack; if this is unsuccessful
        the resulting class will not be pickleable.

        """
    if names is None:
        return cls.__new__(cls, value)
    return cls._create_(value, names, module=module, type=type, start=start)


def unpack_arg(v):
    """Use for local methods."""
    if isinstance(v, tuple):
        return v[0], v[1]
    else:
        return v, {}


@classmethod
def escape(cls, text, quotes=True):
    """Create a Markup instance from a string and escape special characters
        it may contain (<, >, & and ").

        >>> escape('"1 < 2"')
        <Markup '"1 < 2"'>

        If the `quotes` parameter is set to `False`, the " character is left
        as is. Escaping quotes is generally only required for strings that are
        to be used in attribute values.

        >>> escape('"1 < 2"', quotes=False)
        <Markup '"1 < 2"'>

        :param text: the text to escape
        :param quotes: if ``True``, double quote characters are escaped in
                       addition to the other special characters
        :return: the escaped `Markup` string
        :rtype: `Markup`
        """
    if not text:
        return cls()
    if type(text) is cls:
        return text
    if hasattr(text, '__html__'):
        return cls(text.__html__())
    text = text.replace('&', '&').replace('<', '<').replace('>', '>')
    if quotes:
        text = text.replace('"', '"')
    return cls(text)


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

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

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


def random_flip_top_bottom(data=None, name=None, attr=None, out=None, **kwargs
    ):
    """

    Defined in src/operator/image/image_random.cc:L210

    Parameters
    ----------
    data : Symbol
        The input.

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

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


def stripped(jid):
    """ strip resource from jid. """
    try:
        return str(jid).split('/')[0]
    except (IndexError, ValueError):
        return str(jid)


def functionParams(args, vars):
    """
    Build a dictionary of var/value from :param: args.
    Parameters can be either named or unnamed. In the latter case, their
    name is taken fron :param: vars.
    """
    params = {}
    index = 1
    for var in vars:
        value = args.get(var)
        if value is None:
            value = args.get(str(index))
            if value is None:
                value = ''
            else:
                index += 1
        params[var] = value
    return params


def sprite_from_sprite(spritegroup, sprite, time):
    """Takes sprites returned from a sprite and adds it to a group.

    sprite is first updated, and if it returns something (i.e. a
    sprite) it is added to spritegroup.

    """
    if sprite.alive():
        newsprite = sprite.update(time)
        if newsprite is not None:
            spritegroup.add(newsprite)


def horizons(path, short_circuit=False, validity=None):
    """Validate Horizons.h5 file for NSNS simulation

    This function is here just for consistency; its input arguments are ignored, and it always
    returns True.

    """
    return True


def item_provincie_adapter(obj, request):
    """
    Adapter for rendering a object of
    :class:`crabpy.gateway.crab.Provincie` to json.
    """
    return {'niscode': obj.niscode, 'naam': obj.naam, 'gewest': {'id': obj.
        gewest.id, 'naam': obj.gewest.naam}}


def _confirm_prompt(message, prompt=
    """
Are you sure? [y/yes (default: no)]: """, affirmations=('Y', 'Yes',
    'yes', 'y')):
    """
    Display a message, then confirmation prompt, and return true
    if the user responds with one of the affirmations.
    """
    answer = input(message + prompt)
    return answer in affirmations


def _text_file_with_path(sc, path):
    """Return an RDD that yields (path, line) for each line in the file.

    *path* must be a single path, not a comma-separated list of paths
    """
    from pyspark.sql import SparkSession
    from pyspark.sql import functions as F
    spark = SparkSession(sc)
    df = spark.read.text(path).select([F.input_file_name().alias(
        'input_file_name'), F.col('value')])
    return df.rdd.map(lambda row: (row.input_file_name, row.value if
        isinstance(row.value, bytes) else row.value.encode('utf_8')))


def index_to_name(index):
    """Construct the full name for the node given its path."""
    if index:
        return '.'.join(index)
    return 'everything'


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 generate_uuid(record, digest_alg='sha512'):
    """
    Generates a unique identifer for the record
    This is used so that the record can be identified
    without the record id being exposed.
    """
    st = ''
    for k, v in record.items():
        st += '%s=%s|' % k, v
    return hash(st, digest_alg=digest_alg)


def get_type_by_dtype(dtype):
    """
    Convert the numpy dtype to native lambda
    :param dtype: the numpy dtype
    :type dtype: numpy.dtype
    :return: the Lambda
    :rtype: Lambda
    """
    from norm.models import lambdas
    if dtype.name.find('int') > -1:
        return lambdas.Integer
    elif dtype.name.find('float') > -1:
        return lambdas.Float
    else:
        return lambdas.Any


def valid_score(score, smin=0, smax=5):
    """ensure that the input score is an integr
    in the range [smin, smax]  (inclusive)"""
    return max(smin, min(smax, int(score)))


def get_the_written_file_list(writefile_cursor):
    """Return the written files (W)."""
    written_files_query = """
            SELECT process, name, mode
            FROM opened_files
            WHERE mode == 2
            """
    writefile_cursor.execute(written_files_query)
    return writefile_cursor.fetchall()


def _set_checkers_config(checklist_builder, config):
    """Configure checker factories."""
    for each_checker, each_conf in config.items():
        checklist_builder.configure_checker(each_checker, each_conf)


@classmethod
def content_lifecycle_environments(cls, options):
    """List the lifecycle environments attached to the capsule."""
    cls.command_sub = 'content lifecycle-environments'
    result = cls.execute(cls._construct_command(options), output_format='csv')
    return result


def p_import_stmt_1(p):
    """import_stmt : import_name"""
    p[0] = p[1]


def remove_stopwords(text, stopwords):
    """
    Standard way to remove stopwords from text. Text is a string. Stopwords is
    a list of strings to remove. Returns cleaned string.
    """
    text = ' ' + text + ' '
    for w in stopwords:
        text = text.replace(u' {0} '.format(w.decode('utf8')), u' ')
    return text.strip()


def substring(s, start, end):
    """
    Return a slice of s based on start and end indexes (that can be None).
    """
    startless = start is None
    endless = end is None
    if startless and endless:
        return s
    if endless:
        return s[start:]
    if startless:
        return s[:end]
    return s[start:end]


def field_to_flag(f, suffix):
    """
        Convert a field in the form of namespace:termname, along with a flag suffix, to a flag of the form:

            namespace_termname_suffix
    """
    return '{0}_{1}'.format(f.replace(':', '_'), suffix)


def EntryTable(master, hor=1, vert=1, ht=10, wd=30):
    """this widget creates a table of Entry Boxes
    these Entry Boxes are rows/columns of entry boxes
    cframe,cells=EntryTable(master,hor=2,vert=3)
    cframe.grid(column=0,row=0)#sets grid for cells frame
    cells[0][0].insert(0,"text")#insert text on first cell
    cells[1][2].insert(0,"text2")#insert text on last cell
    """
    from tkinter import Entry, Frame
    f = Frame(master)
    ent = [([[]] * vert) for k in range(hor)]
    for i in range(hor):
        for j in range(vert):
            ent[i][j] = Entry(f)
            ent[i][j].grid(column=i, row=j, ipadx=wd, ipady=ht)
    return f, ent


def _ascii_generate_header(tab, comments='#', delimiter=' ',
    commentedHeader=True):
    """ Generate the corresponding ascii Header that contains all necessary info

    Parameters
    ----------

    tab: SimpleTable instance
        table

    comments: str
        string to prepend header lines

    delimiter: str, optional
        The string used to separate values.  By default, this is any
        whitespace.

    commentedHeader: bool, optional
        if set, the last line of the header is expected to be the column titles

    Returns
    -------
    hdr: str
        string that will be be written at the beginning of the file
    """
    hdr = []
    if comments is None:
        comments = ''
    length = max(map(len, tab.header.keys()))
    fmt = '{{0:s}} {{1:{0:d}s}}\t{{2:s}}'.format(length)
    for k, v in tab.header.items():
        for vk in v.split('\n'):
            if len(vk) > 0:
                hdr.append(fmt.format(comments, k.upper(), vk.strip()))
    hdr.append(comments)
    length = max(map(len, tab.keys()))
    fmt = '{{0:s}}{{0:s}} {{1:{0:d}s}}\t{{2:s}}\t{{3:s}}'.format(length)
    for colname in tab.keys():
        unit = tab._units.get(colname, 'None')
        desc = tab._desc.get(colname, 'None')
        hdr.append(fmt.format(comments, colname, unit, desc))
    if len(tab._aliases) > 0:
        hdr.append(comments)
        for k, v in tab._aliases.items():
            hdr.append('{0:s} alias\t{1:s}={2:s}'.format(comments, k, v))
    hdr.append(comments)
    if commentedHeader:
        hdr.append('{0:s} {1:s}'.format(comments, delimiter.join(tab.keys())))
    else:
        hdr.append('{0:s}'.format(delimiter.join(tab.keys())))
    return '\n'.join(hdr)


def findSignificantOffsets(baseCountAtOffset, readCountAtOffset, minReads,
    homogeneousCutoff):
    """
    Find the genome offsets that have significant base variability.

    @param baseCountAtOffset: A C{list} of C{Counter} instances giving
        the count of each nucleotide at each genome offset.
    @param readCountAtOffset: A C{list} of C{int} counts of the total
        number of reads at each genome offset (i.e., just the sum of the
        values in C{baseCountAtOffset})
    @param minReads: The C{int} minimum number of reads that must cover
        a offset for it to be considered significant.
    @param homogeneousCutoff: A C{float} frequency. If the most common
        nucleotide at a offset occurs *more than* this fraction of the time
        (i.e., amongst all reads that cover the offset) then the locaion
        will be considered homogeneous and therefore uninteresting.
    @return: A generator that yields 0-based significant offsets.
    """
    for offset, (readCount, counts) in enumerate(zip(readCountAtOffset,
        baseCountAtOffset)):
        if readCount >= minReads and max(counts.values()
            ) / readCount <= homogeneousCutoff:
            yield offset


def build_option_parser(parser):
    """Hook to add global options"""
    return parser


@classmethod
def create(cls, **kwargs):
    """Create an instance of the associated class, with overriden attrs."""
    visibility = kwargs.pop('visibility', [])
    instance = super().create(**kwargs)
    if visibility:
        visibility_related = instance.get_visibility_relation()
        visibility_related.visibility = visibility
        visibility_related.save(update_fields=['visibility'])
    return instance


@classmethod
def get_logger_name(cls, name=None):
    """Returns a logger name according to the class' constant NAME.

        The logger name requested is always relative to the class'
        constant NAME; if you do not provide a name, then you'll get
        `cls.NAME`.

        If you provide a name, it will be treated as a child of
        that class name.  So the name "foo" will get the result of
        `'%s.foo' % cls.NAME`
        """
    if name is None:
        return cls.NAME
    return '%s.%s' % (cls.NAME, name)


def paths_clear(only_selected: bool=False):
    """Clear path caches for all objects, hold Shift key for selected objects only

    :param only_selected: Only Selected, Only clear paths from selected objects
    :type only_selected: bool
    """
    pass


def get_block_hashes(at_least_these=()):
    """
        @param at_least_these=SetOf(int)
        @return: ListOf(Hash)
        """


def _bytes(_str):
    """
    Convert ordinary Python string (utf-8) into bytes object (should be considered
    as c-string).

    @rtype:   bytes
    """
    return bytes(str(_str), 'utf-8')


def calculate_inline_block_replaced_normal_flow_width(node, context):
    """Implements S10.3.10"""
    raise NotImplementedError('Section 10.3.10')


def get_seg_features(string, seg):
    """
    Segment text with pkuseg
    features are represented in bies format
    s donates single word
    将输入句子进行pkuseg分词，然后获取每个词的长度特征
    0 代表为单字，1代表词的开头，2代表词的中间部分，3代表词的结尾
    例如，string=高血糖和血压 高血糖=[1,2,3] 和=[0] 高血压=[1,3] seg_inputs=[1,2,3,0,1,3]
    """
    seg_feature = []
    for word in seg.cut(string):
        if len(word) == 1:
            seg_feature.append(0)
        else:
            tmp = [2] * len(word)
            tmp[0] = 1
            tmp[-1] = 3
            seg_feature.extend(tmp)
    return seg_feature


def rand_cmap(nlabels, type='bright', first_color_black=True,
    last_color_black=False, verbose=True):
    """
    Creates a random colormap to be used together with matplotlib. Useful for segmentation tasks
    :param nlabels: Number of labels (size of colormap)
    :param type: 'bright' for strong colors, 'soft' for pastel colors
    :param first_color_black: Option to use first color as black, True or False
    :param last_color_black: Option to use last color as black, True or False
    :param verbose: Prints the number of labels and shows the colormap. True or False
    :return: colormap for matplotlib
    """
    from matplotlib.colors import LinearSegmentedColormap
    import colorsys
    import numpy as np
    if type not in ('bright', 'soft'):
        print('Please choose "bright" or "soft" for type')
        return
    if verbose:
        print('Number of labels: ' + str(nlabels))
    if type == 'bright':
        randHSVcolors = [(np.random.uniform(low=0.0, high=1), np.random.
            uniform(low=0.2, high=1), np.random.uniform(low=0.9, high=1)) for
            i in range(nlabels)]
        randRGBcolors = []
        for HSVcolor in randHSVcolors:
            randRGBcolors.append(colorsys.hsv_to_rgb(HSVcolor[0], HSVcolor[
                1], HSVcolor[2]))
        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]
        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]
        random_colormap = LinearSegmentedColormap.from_list('new_map',
            randRGBcolors, N=nlabels)
    if type == 'soft':
        low = 0.6
        high = 0.95
        randRGBcolors = [(np.random.uniform(low=low, high=high), np.random.
            uniform(low=low, high=high), np.random.uniform(low=low, high=
            high)) for i in range(nlabels)]
        if first_color_black:
            randRGBcolors[0] = [0, 0, 0]
        if last_color_black:
            randRGBcolors[-1] = [0, 0, 0]
        random_colormap = LinearSegmentedColormap.from_list('new_map',
            randRGBcolors, N=nlabels)
    if verbose:
        from matplotlib import colors, colorbar
        from matplotlib import pyplot as plt
        fig, ax = plt.subplots(1, 1, figsize=(15, 0.5))
        bounds = np.linspace(0, nlabels, nlabels + 1)
        norm = colors.BoundaryNorm(bounds, nlabels)
        cb = colorbar.ColorbarBase(ax, cmap=random_colormap, norm=norm,
            spacing='proportional', ticks=None, boundaries=bounds, format=
            '%1i', orientation=u'horizontal')
    return random_colormap


@classmethod
def _gen_item_id(cls, item):
    """
        Generate an ID for table, region layer, or extension entity.

        Parameters
        ----------
        item : {'Table', 'RegionLayer', 'Extension', 'XYPlot', 'Cell', 'FootprintLayer'}
            Entity type.

        Returns
        -------
        out : `str`
            ID string.
        """
    if item in cls._item_id:
        cls._item_id[item] += 1
        return item + '-' + str(cls._item_id[item])
    else:
        return None


def getWeblogsForUser(user_id):
    """Return a sequence of dictionaries for each of the weblogs that
        `user_id' has access to.
            [
                {'url': parent_blog.absolute_url(),
                 'blogid' : parent_blog.UID(),
                 'blogName' : parent_blog.title_or_id(),
                },
            ]
        """


def _ratio_metric(v1, v2, **_kwargs):
    """Metric for ratio data."""
    return ((v1 - v2) / (v1 + v2)) ** 2 if v1 + v2 != 0 else 0


@classmethod
def matmul(cls, m1, m2):
    """
        Will return a new matrix which is matrix product of m1 and m2.
        """
    if m1.columns() == m2.rows():
        return cls._alloc_matmul(m1, m2)
    else:
        raise ValueError('Matrix size mismatch')


@classmethod
def get_webasset_js_file(cls):
    """Return the filename of the javascript file."""
    if cls.webasset_js_file:
        return cls.webasset_js_file


def lookupMailboxInfo(name, timeout=None):
    """
        Perform an MINFO record lookup.

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

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

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


def decorate(func, fwrapped):
    """A wrapper call of decorator package, differs to call time

    Parameters
    ----------
    func : function
        The original function

    fwrapped : function
        The wrapped function
    """
    import decorator
    return decorator.decorate(func, fwrapped)


def _whctrs(anchor):
    """
    Return width, height, x center, and y center for an anchor (window).
    """
    w = anchor[2] - anchor[0] + 1
    h = anchor[3] - anchor[1] + 1
    x_ctr = anchor[0] + 0.5 * (w - 1)
    y_ctr = anchor[1] + 0.5 * (h - 1)
    return w, h, x_ctr, y_ctr


def resources_exists(realm, resids):
    """ Returns all existing resources described by `realm` and `resids`.
            If `resids` is a list return all listed resources which exist.
            If `resids` is a string, take it as a pattern and
            list all resources which match it.
            """
    pass


def delete_alias(AliasId=None):
    """
    Deletes a fleet alias. This action removes all record of the alias. Game clients attempting to access a server process using the deleted alias receive an error. To delete an alias, specify the alias ID to be deleted.
    See also: AWS API Documentation

    :example: response = client.delete_alias(
        AliasId='string'
    )

    :type AliasId: string
    :param AliasId: [REQUIRED]
            Unique identifier for a fleet alias. Specify the alias you want to delete.

    """
    pass


def read_chunks(fd, chunk_size=None):
    """Read chunks from a file descriptor"""
    if chunk_size is None:
        import resource
        chunk_size = resource.getpagesize()
    while True:
        data = fd.read(chunk_size)
        if not data:
            break
        yield data


def stage(hub, name):
    """
    Apply the exclude value
    """
    low = hub.idem.low.compile(hub.idem.RUNS[name]['high'], hub.idem.RUNS[
        name]['add_low'])
    hub.idem.RUNS[name]['low'] = low


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

        :param DeviceApprovalsChangeOverageActionDetails val:
        :rtype: EventDetails
        """
    return cls('device_approvals_change_overage_action_details', val)


def _calculate_pages_number(per_page, records_count):
    """Return pages number.

    :param per_page: (int) results number fot one page.
    :param records_count: (int) total records count.
    """
    quotient, remainder = divmod(records_count, per_page)
    if remainder > 0:
        return quotient + 1
    return quotient


def unicode_to_bytes(s, encoding='utf-8', errors='replace'):
    """
    Helper to convert unicode strings to bytes for data that needs to be
    written to on output stream (i.e. terminal)
    For Python 3 this should be called str_to_bytes

    :param str s: string to encode
    :param str encoding: utf-8 by default
    :param str errors: what to do when encoding fails
    :return: byte string utf-8 encoded
    """
    return s if isinstance(s, str) else s.encode(encoding, errors)


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


@classmethod
def _encode(cls, key, serial, cert_type, key_id, principals, valid_after,
    valid_before, options, extensions):
    """Encode an SSH certificate"""
    raise NotImplementedError


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

    Assumes `from __future__ import division`.

    >>> humanize_bytes(1)
    '1 byte'
    >>> humanize_bytes(1024)
    '1.0 kB'
    >>> humanize_bytes(1024 * 123)
    '123.0 kB'
    >>> humanize_bytes(1024 * 12342)
    '12.1 MB'
    >>> humanize_bytes(1024 * 12342, 2)
    '12.05 MB'
    >>> humanize_bytes(1024 * 1234, 2)
    '1.21 MB'
    >>> humanize_bytes(1024 * 1234 * 1111, 2)
    '1.31 GB'
    >>> humanize_bytes(1024 * 1234 * 1111, 1)
    '1.3 GB'

    """
    abbrevs = [(1 << 50, 'PB'), (1 << 40, 'TB'), (1 << 30, 'GB'), (1 << 20,
        'MB'), (1 << 10, 'kB'), (1, 'B')]
    if n == 1:
        return '1 B'
    for factor, suffix in abbrevs:
        if n >= factor:
            break
    return '%.*f %s' % (precision, n / factor, suffix)


def contains_upper(text: str) ->bool:
    """If text contains upper case characters, return True."""
    for character in text:
        if character.isupper():
            return True
    return False


def _reencode_string(string):
    """Ensure that the string is encodable into JSON."""
    if isinstance(string, bytes):
        return string.decode('utf-8', errors='__sqreen_ascii_to_hex')
    return string


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 format_link(url, md_text, md):
    """
    Formats url link depending on if it's Mardown or print function.

    Parameters
    ----------
    url: str
        Url string to the website
    md_text: str
        Text to display in hyperlink if it's markdown
    md: bool
        Whether the text is display in Markdown or with print function
    """
    return url if not md else f'[{md_text}]({url})'


def _clear(subs, shared):
    """Configure the `doorstop clear` subparser."""
    info = 'absolve items of their suspect link status'
    sub = subs.add_parser('clear', description=info.capitalize() + '.',
        help=info, **shared)
    sub.add_argument('label', help="item UID, document prefix, or 'all'")
    group = sub.add_mutually_exclusive_group()
    group.add_argument('-i', '--item', action='store_true', help=
        "indicates the 'label' is an item UID")
    group.add_argument('-d', '--document', action='store_true', help=
        "indicates the 'label' is a document prefix")
    sub.add_argument('parents', nargs='*', help=
        'only clear links with these parent item UIDs')


def unsubscribe(SubscriptionArn=None):
    """
    Deletes a subscription. If the subscription requires authentication for deletion, only the owner of the subscription or the topic's owner can unsubscribe, and an AWS signature is required. If the Unsubscribe call does not require authentication and the requester is not the subscription owner, a final cancellation message is delivered to the endpoint, so that the endpoint owner can easily resubscribe to the topic if the Unsubscribe request was unintended.
    See also: AWS API Documentation

    :example: response = client.unsubscribe(
        SubscriptionArn='string'
    )

    :type SubscriptionArn: string
    :param SubscriptionArn: [REQUIRED]
            The ARN of the subscription to be deleted.

    """
    pass


def __init__(A):
    """AddressType - a model defined in Swagger"""
    A.discriminator = None


def key_filt(keypoints1, keypoints2):
    """
    If there are any similar keypoints between two filtering methods used,
    This will find and remove duplicates in one list.
    """
    duplicates = 0
    if len(keypoints1) != 0 and len(keypoints2) != 0:
        newk1 = keypoints1
        for k1 in keypoints1:
            for k2 in keypoints2:
                if int(k1.pt[0]) == int(k2.pt[0]) and int(k1.pt[1]) == int(k2
                    .pt[1]):
                    newk1.remove(k1)
                    duplicates += 1
        return newk1, duplicates
    else:
        return keypoints1, duplicates


def unwrap_binary(client: 'Client', wrapped: tuple):
    """
    Unwrap wrapped BinaryObject and convert it to Python data.

    :param client: connection to Ignite cluster,
    :param wrapped: `WrappedDataObject` value,
    :return: dict representing wrapped BinaryObject.
    """
    from pyignite.datatypes.complex import BinaryObject
    blob, offset = wrapped
    client_clone = client.clone(prefetch=blob)
    client_clone.pos = offset
    data_class, data_bytes = BinaryObject.parse(client_clone)
    return BinaryObject.to_python(data_class.from_buffer_copy(data_bytes),
        client)


def set_num_axis_ticks(ax, num_x_ticks_old, num_y_ticks_old,
    num_x_ticks_new=10, num_y_ticks_new=10):
    """Set the number of x and y ticks of a plot axis

    Parameters
    ----------
    ax
    num_x_ticks_old
    num_y_ticks_old
    num_x_ticks_new
    num_y_ticks_new

    Returns
    -------

    """
    step_tick_x, step_tick_y = int(num_x_ticks_old / num_x_ticks_new), int(
        num_y_ticks_old / num_y_ticks_new)
    for n, tick in enumerate(ax.xaxis.iter_ticks()):
        if n % step_tick_x != 0:
            tick[0].set_visible(False)
    for n, tick in enumerate(ax.yaxis.iter_ticks()):
        if n % step_tick_y != 0:
            tick[0].set_visible(False)


@classmethod
def precompute_node_type_templates(cls):
    """Different node types may display differently. Scan the provided
        templates to see if any node-type-specific templates are present."""
    cls._find_templates('tree', cls.node_type_tpls)


def _variance_within_cluster(clu, X):
    """Calculate the variance for objects within the same clusters.

    Parameters
    ----------
    clu : list of frozensets
        Resource groups in an organizational model.
    X : DataFrame
        The corresponding resource feature table used for deriving the
        resource groups.

    Returns
    -------
    var_between : float
        The result within-cluster variance.
    """
    from numpy import mean, sum
    var_within = 0
    for ig, g in enumerate(clu):
        g_mean = mean(X.loc[g].values, axis=0)
        var_within += sum((X.loc[g].values - g_mean) ** 2)
    var_within /= len(X) - len(clu)
    return var_within


@staticmethod
def is_sha1(h):
    """
        Ensure h is a syntactically correct SHA1 hash in hexadecimal
        """
    if len(h) != 40:
        return False
    try:
        int(h, 16)
    except ValueError:
        return False
    return True


def get_grouped_psf_model(template_psf_model, star_group, pars_to_set):
    """
    Construct a joint PSF model which consists of a sum of PSF's templated on
    a specific model, but whose parameters are given by a table of objects.

    Parameters
    ----------
    template_psf_model : `astropy.modeling.Fittable2DModel` instance
        The model to use for *individual* objects.  Must have parameters named
        ``x_0``, ``y_0``, and ``flux``.
    star_group : `~astropy.table.Table`
        Table of stars for which the compound PSF will be constructed.  It
        must have columns named ``x_0``, ``y_0``, and ``flux_0``.

    Returns
    -------
    group_psf
        An `astropy.modeling` ``CompoundModel`` instance which is a sum of the
        given PSF models.
    """
    group_psf = None
    for star in star_group:
        psf_to_add = template_psf_model.copy()
        for param_tab_name, param_name in pars_to_set.items():
            setattr(psf_to_add, param_name, star[param_tab_name])
        if group_psf is None:
            group_psf = psf_to_add
        else:
            group_psf += psf_to_add
    return group_psf


def write_3col(filename, data1, data2, data3):
    """Writes data in 2 columns separated by tabs in a "filename" file."""
    f = open(filename, 'w')
    for i, __ in enumerate(data1):
        f.write('\t' + str(data1[i]) + '\t\t' + str(data2[i]) + '\t\t' +
            str(data3[i]) + '\n')
    f.close()


def create_helping_material_info(helping):
    """Create helping_material_info field."""
    helping_info = None
    file_path = None
    if helping.get('info'):
        helping_info = helping['info']
    else:
        helping_info = helping
    if helping_info.get('file_path'):
        file_path = helping_info.get('file_path')
        del helping_info['file_path']
    return helping_info, file_path


def reset():
    """Remove answers for all users."""


@classmethod
def sc_sum(cls, gid, excl, tm_dset, data, excl_dict=None, resolution=64,
    exclusion_shape=None, close=True):
    """
        Compute the aggregate (sum) of data for the sc point

        Parameters
        ----------
        gid : int
            gid for supply curve point to analyze.
        excl : str | ExclusionMask
            Filepath to exclusions h5 or ExclusionMask file handler.
        tm_dset : str
            Dataset name in the exclusions file containing the
            exclusions-to-resource mapping data.
        data : ndarray | ResourceDataset
            Array of data or open dataset handler to apply exclusions too
        excl_dict : dict | None
            Dictionary of exclusion LayerMask arugments {layer: {kwarg: value}}
            None if excl input is pre-initialized.
        resolution : int
            Number of exclusion points per SC point along an axis.
            This number**2 is the total number of exclusion points per
            SC point.
        exclusion_shape : tuple
            Shape of the full exclusions extent (rows, cols). Inputing this
            will speed things up considerably.
        offshore_flags : np.ndarray | None
            Array of offshore boolean flags if available from wind generation
            data. None if offshore flag is not available.
        close : bool
            Flag to close object file handlers on exit.

        Returns
        -------
        ndarray
            Sum / aggregation of data for supply curve point
        """
    kwargs = {'excl_dict': excl_dict, 'resolution': resolution,
        'exclusion_shape': exclusion_shape, 'close': close}
    with cls(gid, excl, tm_dset, **kwargs) as point:
        agg = point.aggregate(data)
    return agg


def floor(value, size, offset=200):
    """Floor of `value` given `size` and `offset`.

    The floor function is best understood with a diagram of the number line::

         -200  -100    0    100   200
        <--|--x--|-----|--y--|--z--|-->

    The number line shown has offset 200 denoted by the left-hand tick mark at
    -200 and size 100 denoted by the tick marks at -100, 0, 100, and 200. The
    floor of a value is the left-hand tick mark of the range where it lies. So
    for the points show above: ``floor(x)`` is -200, ``floor(y)`` is 0, and
    ``floor(z)`` is 100.

    >>> floor(10, 100)
    0.0
    >>> floor(120, 100)
    100.0
    >>> floor(-10, 100)
    -100.0
    >>> floor(-150, 100)
    -200.0
    >>> floor(50, 167)
    -33.0

    """
    return float((value + offset) // size * size - offset)


def rep(string):
    """Generator that yields an infinite supply of the given string"""
    while True:
        yield string


@staticmethod
def p_user(p):
    """user : USER STRING"""
    p[0] = p[2]


@classmethod
def remove_user(cls, options=None):
    """Disassociate an user.

        Usage:
            hammer user-group remove-user [OPTIONS]

        Options:
            --id ID
            --name NAME                   Name to search by
            --user USER_LOGIN             User's login to search by
            --user-id USER_ID
        """
    cls.command_sub = 'remove-user'
    return cls.execute(cls._construct_command(options), output_format='csv')


def levenshtein_distance(a, b):
    """Return the Levenshtein edit distance between two strings *a* and *b*."""
    if a == b:
        return 0
    if len(a) < len(b):
        a, b = b, a
    if not a:
        return len(b)
    previous_row = range(len(b) + 1)
    for i, column1 in enumerate(a):
        current_row = [i + 1]
        for j, column2 in enumerate(b):
            insertions = previous_row[j + 1] + 1
            deletions = current_row[j] + 1
            substitutions = previous_row[j] + (column1 != column2)
            current_row.append(min(insertions, deletions, substitutions))
        previous_row = current_row
    return previous_row[-1]


def updateRoleMappingsFor(ob):
    """ Update the object permissions according to the current workflow
            state of 'ob'.

        o Note that having the same permission(s) controlled by more than one
          workflow defintiion for an object results in undefined behavior.

        o Permission:  Private (Python only)
        """


def ghost_curves_clear():
    """Clear F-Curve snapshots (Ghosts) for active Graph Editor

    """
    pass


def get_confirmation(prompt, force=False):
    """Method to confirm decisions

    Args:
        prompt(str): Question to ask the user
        force(bool): Flag indicating if user prompts should be ignored

    Returns:
        (bool): True indicating yes, False indicating no
    """
    if not force:
        decision = False
        while True:
            confirm = input('{} (y/n): '.format(prompt))
            if confirm.lower() == 'y':
                decision = True
                break
            elif confirm.lower() == 'n':
                decision = False
                break
            else:
                print("Enter 'y' or 'n' for 'yes' or 'no'")
        return decision
    else:
        return True


def remove_geometries(data):
    """Remove geometry attributes from NetworkX adjacency data object,
    because they are not serializable. Mutates the ``data`` object.

    Does nothing if no geometry attributes are found.

    :param data: an adjacency data object (returned by
        :func:`networkx.readwrite.json_graph.adjacency_data`)
    """
    for node in data['nodes']:
        bad_keys = []
        for key in node:
            if hasattr(node[key], '__geo_interface__'):
                bad_keys.append(key)
        for key in bad_keys:
            del node[key]


def transform_stats(values):
    """Transform the output of stats to something more manageable.

    :param list values: The list of values from `SHOW STATS`
    :rtype: dict

    """
    output = {}
    for row in values:
        if row['database'] not in output:
            output[row['database']] = {}
        for k, v in row.items():
            if k == 'database':
                continue
            output[row['database']][k] = v
    return output


def extract_formation_energies_from_file(file_name):
    """ Read a file with the format:

    ::

        # arbitrary number of comment lines
        defect_name    defect_charge_state   defect_formation_energy

    Parameters
    ----------
    file_name : string
        the file with the data

    Returns
    -------
    init_args : tuple
        the tuple contains two elements: the two dictionaries to be used
        as the first two arguments for initializing a
        :class:`EquilibriumConcentrations` instance
    """
    charge_states = {}
    form_energies = {}
    with open(file_name, 'r') as f:
        for line in f:
            if not line.startswith('#'):
                data = line.strip().split()
                defect = data[0]
                charge = int(data[1])
                form_energy = float(data[-1])
                charge_states.setdefault(defect, [])
                charge_states[defect].append(charge)
                form_energies.setdefault(defect, [])
                form_energies[defect].append(form_energy)
    return charge_states, form_energies


@staticmethod
def split_comma_strings_into_lists(obj):
    """
        Splits a CSV String into a list.  Also takes a dictionary, and converts any CSV strings in any key, to a list.

        :param obj: object in CSV format to be parsed.
        :type obj: str or dict

        :return: A list containing the CSV items.
        :rtype: list
        """
    return_obj = ()
    if isinstance(obj, dict):
        if len(obj) > 0:
            for k, v in obj.items():
                if isinstance(v, str):
                    new_list = list()
                    if ',' in v:
                        new_items = v.split(',')
                        for item in new_items:
                            new_list.append(item.strip())
                        obj[k] = new_list
            return_obj = obj
    elif isinstance(obj, str):
        return_obj = obj.replace(' ', '').split(',')
    return return_obj


def is_finite(builder, val):
    """
    Return a condition testing whether *val* is a finite.
    """
    val_minus_val = builder.fsub(val, val)
    return builder.fcmp_ordered('ord', val_minus_val, val_minus_val)


def genderdecode(genderTag):
    """
    one-hot decoding for the gender tag predicted by the classfier
    Dimension = 2.
    """
    if genderTag == [1, 0]:
        code = 'm'
    if genderTag == [0, 1]:
        code = 'f'
    if genderTag == [1, 1]:
        code = 'any'
    if genderTag == [0, 0]:
        code = 'num'
    return code


def Win32Input(prompt=None):
    """Provide input() for gui apps"""
    return eval(input(prompt))


def hasClosingPeriod(text: str) ->bool:
    """
    Return True if the text ends with a period or something like '.)'
    """
    if not text:
        return False
    for period in '.።':
        if text[-1] == period:
            return True
        for closingPunctuation in ')]"\'”’»›':
            if text.endswith(period + closingPunctuation):
                return True
    return False


@classmethod
def FromEventData(cls, event_data):
    """Creates a service object from event data.

    Args:
      event_data (EventData): event data.

    Returns:
      WindowsService: service.
    """
    if event_data.pathspec:
        source = event_data.pathspec.location, event_data.key_path
    else:
        source = 'Unknown', 'Unknown'
    return cls(event_data.name, event_data.service_type, event_data.
        image_path, event_data.start_type, event_data.object_name, source,
        service_dll=event_data.service_dll)


def upload_object(**kwargs):
    """Upload an object into bucket."""
    filename = kwargs.get('local_path', '')
    local_path = kwargs.get('local_path')
    if kwargs.get('object_name'):
        filename = kwargs.get('object_name')
    resource = kwargs.get('resource')
    bucket_name = kwargs.get('bucket_name')
    resource.Object(bucket_name, filename).upload_file(Filename=local_path)


def write_dict_to_cdf_attributes(netcdf_object, d, tag):
    """
    write a dictionary to netCDF attributes

    :param netcdf_object: netcdf file object
    :param dict d: dictionary of attribute names and values
    :param str tag: an identifier to prepend to the attribute name
    :return: the dictionary d with any strings that can be changed to numbers, as numbers
    """
    i = 0
    for key in iter(d):
        if type(d[key]) == str:
            try:
                d[key] = float(d[key])
            except ValueError:
                i += 1
    for key in iter(d):
        newkey = tag + key
        try:
            netcdf_object.setncattr(newkey, d[key])
        except:
            print("can't set %s attribute" % key)
    return d


def stroke_flip():
    """Change direction of the points of the selected strokes

    """
    pass


def get_metadata(name):
    """The named metadata resource as a string"""


def default_cryolo_v1_0_4():
    """
    Content of crYOLO version 1.0.4

    Arguments:
    None

    Return:
    Content items as list
    """
    items = [['WIDGETS MAIN', '5', int, '', 'PLAIN', '', ''], [
        'WIDGETS ADVANCED', '5', int, '', 'PLAIN', '', ''], ['WIDGETS RARE',
        '5', int, '', 'PLAIN', '', ''], ['--conf', '', str, '', 'FILE',
        'Main', '', 'Path to configuration file.'], ['--weights', '', str,
        '', 'FILE', 'Main', 'Path to pretrained weights.'], ['--threshold',
        '0.3', float, '', 'PLAIN', 'Main',
        'Confidence threshold. Have to be between 0 and 1. As higher, as more conservative.'
        ], ['Pixel size (A/px)', '1', float, 'Filter micrographs:True',
        'PLAIN', 'Main',
        'NOT A CRYOLO OPTION. Pixel size value. Only used for visual representation.'
        ], ['Box size', '200', int, '', 'PLAIN', 'Main',
        'NOT A CRYOLO OPTION. Box size value. Only used for visual representation.'
        ], ['Filter micrographs', ['True', 'False'], bool, '', 'COMBO',
        'Advanced',
        'NOT A CRYOLO OPTION. Box size value. Only used for visual representation.'
        ], ['Filter value high pass (A)', '9999', float,
        'Filter micrographs:True', 'PLAIN', 'Advanced',
        'NOT A CRYOLO OPTION. High-pass filter value in angstrom before running crYOLO.'
        ], ['Filter value low pass (A)', '10', float,
        'Filter micrographs:True', 'PLAIN', 'Advanced',
        'NOT A CRYOLO OPTION. Low-pass filter value in angstrom before running crYOLO.'
        ], ['--patch', '-1', int, '', 'PLAIN', 'Advanced',
        'Number of patches. (-1 uses the patch size specified in the configuration file.)'
        ], ['--gpu', '0', [int] * 99, '', 'PLAIN', 'Advanced',
        "Specifiy which gpu's should be used."], ['Split Gpu?', ['True',
        'False'], bool, '', 'COMBO', 'Advanced',
        'NOT A CRYOLO OPTION. Split the gpu values specified in --gpu to be able to run mutliple crYOLO jobs in parallel.'
        ]]
    return items


def string_to_num(s: str):
    """Converts a string to an int/float

    Returns ``None`` if it can't be converted

    >>> string_to_num('5')
    5
    >>> string_to_num('5.2')
    5.2
    >>> string_to_num(10)
    10
    >>> string_to_num(10.1)
    10.1
    >>> string_to_num('this is not a string') is None
    True
    """
    if isinstance(s, (int, float)):
        return s
    if s.isdigit():
        return int(s)
    try:
        return float(s)
    except ValueError:
        return None


def height2rate(height_of_rainfall, duration):
    """
    calculate the specific rain flow rate in [l/(s*ha)]
    if 2 array-like parameters are give, a element-wise calculation will be made.
    So the length of the array must be the same.

    Args:
        height_of_rainfall (float | np.ndarray | pd.Series): height_of_rainfall: in [mm]
        duration (float | np.ndarray | pd.Series): in minutes

    Returns:
        float | np.ndarray | pd.Series: specific rain flow rate in [l/(s*ha)]
    """
    return height_of_rainfall / duration * (1000 / 6)


def length(lst):
    """
    Implementation of Ramda length
    :param lst:
    :return:
    """
    return len(lst)


def generator(url, downloader='default', *args, **kwargs):
    """Parse an App and return a generator"""
    from rowgenerators import parse_app_url
    u = parse_app_url(url, downloader=downloader, **kwargs)
    r = u.get_resource()
    t = r.get_target()
    return t.generator


def get_haplotype_score(var):
    """
    Returns consistency of the site with two segregating haplotypes,
    or None if it isn't present in the VCF.
    """
    return var.INFO.get('HaplotypeScore')


@staticmethod
def _get_unique_key(obj):
    """Returns a unique key for passed object for data model building."""
    if obj.__class__.__name__ in ['Member', 'Pool', 'LoadBalancer',
        'Listener', 'Amphora', 'L7Policy', 'L7Rule', 'Flavor', 'FlavorProfile'
        ]:
        return obj.__class__.__name__ + obj.id
    if obj.__class__.__name__ in ['SessionPersistence', 'HealthMonitor']:
        return obj.__class__.__name__ + obj.pool_id
    if obj.__class__.__name__ in ['ListenerStatistics']:
        return obj.__class__.__name__ + obj.listener_id + obj.amphora_id
    if obj.__class__.__name__ in ['ListenerCidr']:
        return obj.__class__.__name__ + obj.listener_id + obj.cidr
    if obj.__class__.__name__ in ['VRRPGroup', 'Vip']:
        return obj.__class__.__name__ + obj.load_balancer_id
    if obj.__class__.__name__ in ['AmphoraHealth']:
        return obj.__class__.__name__ + obj.amphora_id
    if obj.__class__.__name__ in ['SNI']:
        return obj.__class__.__name__ + obj.listener_id + obj.tls_container_id
    if obj.__class__.__name__ in ['Quotas']:
        return obj.__class__.__name__ + obj.project_id
    raise NotImplementedError


def text_(s, encoding='latin-1', errors='strict'):
    """ If ``s`` is an instance of ``bytes``, return ``s.decode(encoding,
    errors)``, otherwise return ``s``"""
    if isinstance(s, bytes):
        return s.decode(encoding, errors)
    return s


def is_par(comm):
    """Check if or not in parallel environment
    """
    return comm and comm.size > 1


def stop(snd):
    """Stop playing Sound snd."""
    snd.stop()


def decimal_to_xyz(rgb):
    """
    Convert decimal format to xyz
    """
    red, green, blue = rgb[0], rgb[1], rgb[2]
    x = red * 0.649926 + green * 0.103455 + blue * 0.197109
    y = red * 0.234327 + green * 0.743075 + blue * 0.022598
    z = red * 0.0 + green * 0.053077 + blue * 1.035763
    return x, y, z


def fermat_factors(n):
    """
    Factor given number using Fermat approach, starting from sqrt(n)
    :param n: modulus to factor
    :return: p, q
    """
    assert n % 2 != 0
    import gmpy2
    a = gmpy2.isqrt(n)
    b2 = gmpy2.square(a) - n
    while not gmpy2.is_square(b2):
        a += 1
        b2 = gmpy2.square(a) - n
    factor1 = a + gmpy2.isqrt(b2)
    factor2 = a - gmpy2.isqrt(b2)
    print(n, factor1, factor2)
    return int(factor1), int(factor2)


def get_users_with_permissions(permissions):
    """Return a list of users that have any of the specified
        permissions.
        """


def __to_int(val):
    """Convert val into an integer value."""
    try:
        return int(val)
    except (ValueError, TypeError):
        return 0


@classmethod
def search_rec_name(cls, name, clause):
    """ Search for the name, lastname, PUID, any alternative IDs,
            and any family and / or given name from the person_names
        """
    if clause[1].startswith('!') or clause[1].startswith('not '):
        bool_op = 'AND'
    else:
        bool_op = 'OR'
    return [bool_op, ('ref',) + tuple(clause[1:]), ('alternative_ids.code',
        ) + tuple(clause[1:]), ('federation_account',) + tuple(clause[1:]),
        ('contact_mechanisms.value',) + tuple(clause[1:]), (
        'person_names.family',) + tuple(clause[1:]), ('person_names.given',
        ) + tuple(clause[1:]), ('name',) + tuple(clause[1:]), ('lastname',) +
        tuple(clause[1:])]


def popitem():
    """remove and return some (key, value) pair as a
        2-tuple; but raise KeyError if mapping is empty"""


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


def debug(*args, **kwargs):
    """
    Just a simple example which shows the view's json_data.

    """
    view = kwargs.get('view', None)
    if view is None:
        return 'MACRO: Debug did not get a view'
    result = 'Object dictionary: {} '.format(view.json_data)
    return result


def print_info(args):
    """
    CLI command to print merlin config info.

    :param `args`: parsed CLI arguments
    """
    from merlin import display
    display.print_info(args)


@classmethod
def epoch_to_dttm(cls) ->str:
    """
        SQL expression that converts epoch (seconds) to datetime that can be used in a
        query. The reference column should be denoted as `{col}` in the return
        expression, e.g. "FROM_UNIXTIME({col})"

        :return: SQL Expression
        """
    raise NotImplementedError()


@staticmethod
def _get_count_from_result_tuple(row):
    """ Get the count from the result row """
    return row[-1]


def rehydrate_plugin_instance(parent_class, class_name, options):
    """
    rehydrate an instance of a plugin based on JSON data

    as I document this, I wonder if it might be better to pickle the objects and
    store them in the db that way? I will consider this...

    args:
        - the parent class the child instance inherits from. Usually either
          ActionPluginBase or BlePluginBase.
        - the class name of the child we are rehydrating
        - init options for the child instance
    returns:
        an instance of a class, or None if instance could not be created.
    raises:
        none
    """
    for plugin in parent_class.plugins:
        if plugin.__name__ == class_name:
            obj = plugin(**options)
            return obj
    return None


def close():
    """Closes the message file.

        No further writes are allowed.  You can call ``close()`` before calling
        ``commit()`` or ``abort()`` to avoid having too many open files.

        Calling ``close()`` more than once is allowed.
        """


def get_icon(v, tcon):
    """Returns a list of indices that are to be contracted when contractions
    between the two tensors numbered in tcon are contracted.
    """
    inds1 = v[tcon[0]]
    inds2 = v[tcon[1]]
    icon = set(inds1).intersection(inds2)
    icon = list(icon)
    return icon


def subclassof(c, b):
    """Wrap issubclass to return True/False without throwing TypeError"""
    try:
        return issubclass(c, b)
    except TypeError:
        return False


@staticmethod
def file_put_contents(filename, contents):
    """
        Write content to a file
        """
    file = open(filename, 'w')
    file.write(contents)
    file.close()


def add_rotation(im, ccw_rotation_degrees: int=90):
    """Rotate an image CCW by `ccw_rotation_degrees` degrees.

    :param im: input image
    :type im: PIL image object
    :param ccw_rotation_degrees: number of degrees to rotate counter-clockwise
    :type ccw_rotation_degrees: int
    :return: rotated image
    :rtype: PIL image object
    """
    return im.rotate(ccw_rotation_degrees, expand=True)


def _dryrun(submit, returnStdout, returnStderr, returnExitcode, *args):
    """Used by the :func:`run` function when the :attr:`DRY_RUN` flag is
    active.
    """
    if submit:
        return '0',
    results = []
    stderr = ''
    stdout = ' '.join(args)
    if returnStdout:
        results.append(stdout)
    if returnStderr:
        results.append(stderr)
    if returnExitcode:
        results.append(0)
    if len(results) == 1:
        return results[0]
    else:
        return tuple(results)


def find_cfn_output(key, outputs):
    """Return CFN output value."""
    for i in outputs:
        if i['OutputKey'] == key:
            return i['OutputValue']
    return None


@classmethod
def normhash(cls, hash):
    """helper to normalize hash, correcting any bcrypt padding bits"""
    if cls.identify(hash):
        return cls.from_string(hash).to_string()
    else:
        return hash


def stress_scaling_area(sigma_old, a_old, a_new):
    """ Scale stresses using input area """
    if a_new <= a_old:
        sigma_new = sigma_old * (a_old / (a_old - abs(a_old - a_new)))
        assert sigma_new >= sigma_old, 'ERROR no stress increase: \nt_old ' + str(
            a_old) + ' sigma_old ' + str(sigma_old) + '\nt_new ' + str(a_new
            ) + ' sigma_new ' + str(sigma_new)
    else:
        sigma_new = sigma_old * (a_old / (a_old + 0.5 * abs(a_old - a_new)))
        assert sigma_new <= sigma_old, 'ERROR no stress reduction: \nt_old ' + str(
            a_old) + ' sigma_old ' + str(sigma_old) + '\nt_new ' + str(a_new
            ) + ' sigma_new ' + str(sigma_new)
    return sigma_new


def strip_repository_name(git_repo_url):
    """
        Strips the input and returns the text between rightmost '/' and '.git'
    """
    output = git_repo_url
    last_slash = output.rfind('/')
    if last_slash != -1:
        output = output[last_slash + 1:]
    dot_git = output.rfind('.git')
    if dot_git != -1:
        output = output[:dot_git]
    return output.lower()


def tensorvect2matrixform(tensorVect):
    """Converts a second order tensor from the vector form of to its matricial
    form.

    Parameters:
        tensorVect (`list` or `numpy.ndarray`): :math:`(n \\times 6)` tensor
            components written as column vector with the following order
            :math:`t_{11}, t_{22}, t_{33}, t_{12}, t_{23}, t_{13}`.

    Returns:
        (`numpy.ndarray`): :math:`(3 \\times 3)` second-order tensor expressed            as a :math:`3\\times 3` matrix.

    Examples:
        >>> from jelinekstat.tools import tensorvect2matrixform
        >>> tensorVect = [11, 22, 33, 12, 23, 13]
        >>> tensorvect2matrixform(tensorVect)
        array([[11, 12, 13],
               [12, 22, 23],
               [13, 23, 33]])
    """
    import numpy as np
    tensorVect = np.array(tensorVect)
    tensorMtxForm = np.array([[tensorVect[0], tensorVect[3], tensorVect[5]],
        [tensorVect[3], tensorVect[1], tensorVect[4]], [tensorVect[5],
        tensorVect[4], tensorVect[2]]])
    return tensorMtxForm


def d_orthographic_camera_d_shape_parameters(shape_pc_uv, camera):
    """
    Calculates the derivative of the orthographic projection with respect to
    the shape parameters.

    Parameters
    ----------
    shape_pc_uv : ``(n_points, 3, n_parameters)`` `ndarray`
        The (sampled) basis of the shape model.
    camera : `menpo3d.camera.OrthographicCamera`
        The camera object that is responsible of projecting the model to the
        image plane.

    Returns
    -------
    dw_da : ``(2, n_shape_parameters, n_points)`` `ndarray`
        The derivative of the perspective camera transform with respect to
        the shape parameters.
    """
    n_points, n_dims, n_parameters = shape_pc_uv.shape
    assert n_dims == 3
    dp_da_uv = camera.rotation_transform.apply(shape_pc_uv.transpose(0, 2, 1)
        ).T
    return camera.projection_transform.focal_length * dp_da_uv[:2]


def parse_contaminations(file):
    """
    Parse contamination file.
    example:
    ==============================
    Pirisoci	Alveolata	group
    DiplDSTH	GoniavonGEN	org
    Fucucera	Ochrophyta	subtax
    ==============================
    input: tab separated file with contaminations
    result: dictionary with organism as key and tuple with taxonomy
            and rank
    """
    cont_dict = {}
    for line in open(file):
        org, tax, rank = line.split('\t')
        cont_dict[org] = tax, rank.strip()
    return cont_dict


def getSquareSegmentDistance(p, p1, p2):
    """
    Square distance between point and a segment
    """
    x, y = p1
    dx, dy = p2 - p1
    if dx or dy:
        t = ((p.x - x) * dx + (p.y - y) * dy) / (dx * dx + dy * dy)
        if t > 1:
            x, y = p2
        elif t > 0:
            x += dx * t
            y += dy * t
    dx, dy = p.x - x, p.y - y
    return dx * dx + dy * dy


def cep(crossing_strand):
    """
    Returns the CrossingEntryPoint corresponding to the given
    CrossingStrand in the same crossing; that is, it orients the
    CrossingStrand without changing the crossing.
    """
    if crossing_strand == crossing_strand.oriented():
        return crossing_strand
    else:
        return crossing_strand.rotate(2)


def separate_on(iterable, separator):
    """Variation on group_on_separator yielding record content as a list.

    Faster than group_on_separator for small groups and avoiding the caveat of
    possibly invalid content iterators."""
    sep_len = len(separator)
    accum = None
    header = None
    for item in iterable:
        item = item.strip()
        if item[:sep_len] == separator:
            if accum is not None:
                yield header, accum
            header = item[sep_len:]
            accum = []
        else:
            try:
                accum.append(item)
            except AttributeError:
                accum = [item]
    yield header, accum


@classmethod
def fromkeys(cls, iterable, value=None):
    """OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
        and values equal to v (which defaults to None).

        """
    d = cls()
    for key in iterable:
        d[key] = value
    return d


@staticmethod
def monitor():
    """
        ``monitor <addr> <port> <status>``

        open a socket port to monitoring parameters

        e.g.::

            monitor localhost 12345 1

        * if ``status = 1`` start monitoring
        * if ``status = 0`` stop monitoring

        .. note::

            Not implemented yet
        """
    pass


def pad_line(line, pad_to):
    """
	Pad line with blanks until the line is ``pad_to``
	long.
	"""
    return line + ' ' * (pad_to - len(line))


def show_df(df, n=10):
    """Show the first `n` rows of a Spark DF formatted as a Pandas DF.

    This provides a pretty-printed alternative to Spark's `DF.head()` and
    `DF.show()`.

    Parameters
    ----------
    df : DataFrame
        A Spark DataFrame.
    n : int, optional
        The number of rows to show (defaults to 10).

    Returns
    -------
    DataFrame
        A Pandas DF containing the first `n` rows of `df`.
    """
    return df.limit(n).toPandas()


def device_memory_depends(devmem, *objs):
    """Add dependencies to the device memory.

    Mainly used for creating structures that points to other device memory,
    so that the referees are not GC and released.
    """
    depset = getattr(devmem, '_depends_', [])
    depset.extend(objs)


def verifyWriteMode(files):
    """
    Checks whether files are writable. It is up to the calling routine to raise
    an Exception, if desired.

    This function returns True, if all files are writable and False, if any are
    not writable.  In addition, for all files found to not be writable, it will
    print out the list of names of affected files.
    """
    if not isinstance(files, list):
        files = [files]
    not_writable = []
    writable = True
    for fname in files:
        try:
            f = open(fname, 'a')
            f.close()
            del f
        except:
            not_writable.append(fname)
            writable = False
    if not writable:
        print('The following file(s) do not have write permission!')
        for fname in not_writable:
            print('    ', fname)
    return writable


def delete():
    """Delete selected control points or splines

    """
    pass


def norm_range(vec, lower=0, upper=255, type=int):
    """
    clips vector to range [lower, upper] and a tuple with integers

    :param vec: vector
    :param lower: 0
    :param upper: 255
    :param type: int
    :return:
    """
    newvec = []
    upper = type(upper)
    lower = type(lower)
    for i in vec:
        if i > upper:
            newvec.append(upper)
        elif i < lower:
            newvec.append(lower)
        else:
            newvec.append(type(i))
    return tuple(newvec)


def update_nfs_file_share(FileShareARN=None, KMSEncrypted=None, KMSKey=None,
    NFSFileShareDefaults=None, DefaultStorageClass=None, ClientList=None,
    Squash=None, ReadOnly=None):
    """
    Updates a file share. This operation is only supported in the file gateway architecture.
    Updates the following file share setting:
    See also: AWS API Documentation

    :example: response = client.update_nfs_file_share(
        FileShareARN='string',
        KMSEncrypted=True|False,
        KMSKey='string',
        NFSFileShareDefaults={
            'FileMode': 'string',
            'DirectoryMode': 'string',
            'GroupId': 123,
            'OwnerId': 123
        },
        DefaultStorageClass='string',
        ClientList=[
            'string',
        ],
        Squash='string',
        ReadOnly=True|False
    )

    :type FileShareARN: string
    :param FileShareARN: [REQUIRED]
            The Amazon Resource Name (ARN) of the file share to be updated.

    :type KMSEncrypted: boolean
    :param KMSEncrypted: True to use Amazon S3 server side encryption with your own AWS KMS key, or false to use a key managed by Amazon S3. Optional.

    :type KMSKey: string
    :param KMSKey: The KMS key used for Amazon S3 server side encryption. This value can only be set when KmsEncrypted is true. Optional.

    :type NFSFileShareDefaults: dict
    :param NFSFileShareDefaults: The default values for the file share. Optional.
            FileMode (string) --The Unix file mode in the form 'nnnn'. For example, '0666' represents the default file mode inside the file share. The default value is 0666.
            DirectoryMode (string) --The Unix directory mode in the form 'nnnn'. For example, '0666' represents the default access mode for all directories inside the file share. The default value is 0777.
            GroupId (integer) --The default group ID for the file share (unless the files have another group ID specified). The default value is nfsnobody.
            OwnerId (integer) --The default owner ID for files in the file share (unless the files have another owner ID specified). The default value is nfsnobody.

    :type DefaultStorageClass: string
    :param DefaultStorageClass: The default storage class for objects put into an Amazon S3 bucket by a file gateway. Possible values are S3_STANDARD or S3_STANDARD_IA. If this field is not populated, the default value S3_STANDARD is used. Optional.

    :type ClientList: list
    :param ClientList: The list of clients that are allowed to access the file gateway. The list must contain either valid IP addresses or valid CIDR blocks.
            (string) --

    :type Squash: string
    :param Squash: The user mapped to anonymous user. Valid options are the following:
            'RootSquash' - Only root is mapped to anonymous user.
            'NoSquash' - No one is mapped to anonymous user
            'AllSquash' - Everyone is mapped to anonymous user.

    :type ReadOnly: boolean
    :param ReadOnly: Sets the write status of a file share: 'true' if the write status is read-only, and otherwise 'false'.

    :rtype: dict
    :return: {
        'FileShareARN': 'string'
    }

    :returns:
    FileShareARN (string) -- [REQUIRED]
    The Amazon Resource Name (ARN) of the file share to be updated.

    KMSEncrypted (boolean) -- True to use Amazon S3 server side encryption with your own AWS KMS key, or false to use a key managed by Amazon S3. Optional.
    KMSKey (string) -- The KMS key used for Amazon S3 server side encryption. This value can only be set when KmsEncrypted is true. Optional.
    NFSFileShareDefaults (dict) -- The default values for the file share. Optional.

    FileMode (string) --The Unix file mode in the form "nnnn". For example, "0666" represents the default file mode inside the file share. The default value is 0666.

    DirectoryMode (string) --The Unix directory mode in the form "nnnn". For example, "0666" represents the default access mode for all directories inside the file share. The default value is 0777.

    GroupId (integer) --The default group ID for the file share (unless the files have another group ID specified). The default value is nfsnobody.

    OwnerId (integer) --The default owner ID for files in the file share (unless the files have another owner ID specified). The default value is nfsnobody.

    DefaultStorageClass (string) -- The default storage class for objects put into an Amazon S3 bucket by a file gateway. Possible values are S3_STANDARD or S3_STANDARD_IA. If this field is not populated, the default value S3_STANDARD is used. Optional.
    ClientList (list) -- The list of clients that are allowed to access the file gateway. The list must contain either valid IP addresses or valid CIDR blocks.

    (string) --

    Squash (string) -- The user mapped to anonymous user. Valid options are the following:

    "RootSquash" - Only root is mapped to anonymous user.
    "NoSquash" - No one is mapped to anonymous user
    "AllSquash" - Everyone is mapped to anonymous user.

    ReadOnly (boolean) -- Sets the write status of a file share: "true" if the write status is read-only, and otherwise "false".

    """
    pass


def get_dynsym_datas(elf_data, elf_file, skip_import=True):
    """
    获取符号/方法的相关信息（符号名、符号数据）。
    """
    f = elf_data
    dynsym_datas = []
    symbol_table = elf_file.get_section_by_name('.dynsym')
    if symbol_table:
        for symbol in symbol_table.iter_symbols():
            if (skip_import and symbol.entry.st_size == 0 or symbol.entry.
                st_info.type != 'STT_FUNC'):
                continue
            f.seek(0)
            symbol_addr = symbol.entry.st_value & 65534
            f.seek(symbol_addr)
            symbol_hexs = ''
            size = symbol.entry.st_size
            if symbol.entry.st_size > 80:
                size = 80
            for x in f.read(size):
                op = str(hex(x)).upper()[2:]
                if len(op) == 1:
                    op = '0' + op
                symbol_hexs = symbol_hexs + op
            item = {}
            item['name'] = symbol.name
            item['data'] = symbol_hexs
            dynsym_datas.append(item)
    return dynsym_datas


def _utf8_chunk(bytestr):
    """If bytestr is a valid UTF-8 sequence, returns bytestr.
    If bytestr can be made a valid UTF-8 sequence by removing a few bytes
    from the end, returns a modified copy of bytestr.
    Otherwise, returns bytestr.

    The purpose of this method is to provide a safe way of reading chunks
    from the middle of a UTF-8 log file given an offset and length.
    Consider a caller reading a log file in 1MB chunks.  It's possible that
    a chunk would end in the middle of a UTF-8 encoded character, resulting
    in a broken string.  This method fixes up any such broken chunks."""
    try:
        bytestr.decode('utf-8')
        return bytestr
    except UnicodeDecodeError:
        pass
    idx = len(bytestr)
    while idx > 0:
        last_char = ord(bytestr[idx - 1:idx])
        if last_char < 128:
            break
        idx = idx - 1
        if last_char >= 192:
            break
    out = bytestr[:idx]
    try:
        out.decode('utf-8')
        return out
    except UnicodeDecodeError:
        return bytestr


def clear_matplotlib_ticks(ax=None, axis='both'):
    """
    Clears the default matplotlib axes, or the one specified by the axis
    argument.

    Parameters
    ----------
    ax: Matplotlib AxesSubplot, None
        The subplot to draw on.
    axis: string, "both"
        The axis to clear: "x" or "horizontal", "y" or "vertical", or "both"
    """
    if not ax:
        return
    if axis.lower() in ['both', 'x', 'horizontal']:
        ax.set_xticks([], [])
    if axis.lower() in ['both', 'y', 'vertical']:
        ax.set_yticks([], [])


def print_value(value, ndigits=3):
    """Prepare a parameter value for printing, used in CyclingParams.__str__"""
    if len(value) == 1:
        return format(value[0], '.%df' % ndigits)
    else:
        return 'array(%d)' % len(value)


@staticmethod
def argmax(tensor):
    """The argument of the max value in a tensor.

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

        Returns
        -------
        scalar
        """
    raise NotImplementedError


def power(x, y):
    """
    Takes the initial input and puts it to the power of the second value
    >>> power(2, 4)
    32
    """
    i = 0
    original_x = x
    while i < y:
        x = x * original_x
        i = i + 1
    return x


def truncate(length, text):
    """Truncate the given text to the given length.

    If the text is longer than the ``length``, return a new string that
    contains ``length - 1`` characters of text followed by an ellipsis.
    Otherwise return the given text unaltered.
    """
    if len(text) > length:
        return text[:length - 1] + '…'
    else:
        return text


def split_first(s, delims):
    """
    Given a string and an iterable of delimiters, split on the first found
    delimiter. Return two split parts and the matched delimiter.

    If not found, then the first part is the full input string.

    Example::

        >>> split_first('foo/bar?baz', '?/=')
        ('foo', 'bar?baz', '/')
        >>> split_first('foo/bar?baz', '123')
        ('foo/bar?baz', '', None)

    Scales linearly with number of delims. Not ideal for large number of delims.
    """
    min_idx = None
    min_delim = None
    for d in delims:
        idx = s.find(d)
        if idx < 0:
            continue
        if min_idx is None or idx < min_idx:
            min_idx = idx
            min_delim = d
    if min_idx is None or min_idx < 0:
        return s, '', None
    return s[:min_idx], s[min_idx + 1:], min_delim


def start_frame_set():
    """Set the start frame

    """
    pass


def unpack(Ham_obj):
    """
    Reduce a Hamiltonian object down to a list of matrix elements. Include the Hermitian conjugate terms

    *args*:

        - **Ham_obj**: Hamiltonian object, c.f. *chinook.TB_lib.H_me*

    *return*:

        - **Hlist**: list of Hamiltonian matrix elements

    ***
    """
    Hlist = []
    for hij in Ham_obj:
        for el in hij.H:
            Hlist.append([hij.i, hij.j, *el])
    return Hlist


def noop(*args, **kwargs):
    """No-op.  Does nothing.

    Args:
      args: list of arguments
      kwargs: keyword arguments dictionary

    Returns:
      ``None``
    """
    pass


@staticmethod
def _name_opts():
    """Returns command options in a form that can be handled by the
        command parser."""
    opts = {'-h': {'type': bool, 'default': False}, '-n': {'type': str,
        'default': None}}
    return opts


def require_minimum_pandas_version():
    """ Raise ImportError if minimum version of Pandas is not installed
    """
    minimum_pandas_version = '0.23.2'
    from distutils.version import LooseVersion
    try:
        import pandas
        have_pandas = True
    except ImportError:
        have_pandas = False
    if not have_pandas:
        raise ImportError(
            'Pandas >= %s must be installed; however, it was not found.' %
            minimum_pandas_version)
    if LooseVersion(pandas.__version__) < LooseVersion(minimum_pandas_version):
        raise ImportError(
            'Pandas >= %s must be installed; however, your version was %s.' %
            (minimum_pandas_version, pandas.__version__))


def _describe_source(d):
    """return either '<path>' or 'line N of <path>' or 'lines M-N of <path>'.
    """
    path = d.get('path') or ''
    if 'num_lines' in d and 'start_line' in d:
        if d['num_lines'] == 1:
            return 'line %d of %s' % (d['start_line'] + 1, path)
        else:
            return 'lines %d-%d of %s' % (d['start_line'] + 1, d[
                'start_line'] + d['num_lines'], path)
    else:
        return path


def m3_order(a, b):
    """
    The smallest non-distributive lattice.
    """
    if a == {0} or b == {1}:
        return True
    else:
        return False


def settings_value(value):
    """Returns the evaluated string."""
    try:
        return eval(value, {}, {})
    except (NameError, SyntaxError):
        return value


def ipow(a, b):
    """Same as a **= b."""
    a **= b
    return a


def check_object_permissions(permissions, context, obj):
    """
    Check if it's permitted for a given object.
    Raises an appropriate exception if it's is not permitted.
    """
    for permission in permissions:
        if not permission.has_object_permission(context, obj):
            return False
    return True


def humanize(module_name):
    """Transforms a module name into a pretty human-likable string."""
    module_name = module_name.lower()
    module_name = module_name.replace('_', ' ').replace('-', ' ')
    module_name = module_name.title()
    return module_name


def isstr(obj):
    """Return whether an object is instance of `str`."""
    return isinstance(obj, str)


def as_list(*whatever):
    """
        Returns a list containing all values given in whatever.
        Each list or tuple will be "unpacked", all other elements
        are added to the resulting list.

        Examples given

        >>> as_list('spam')
        ['spam']

        >>> as_list('spam', 'eggs')
        ['spam', 'eggs']

        >>> as_list(('spam', 'eggs'))
        ['spam', 'eggs']

        >>> as_list(['spam', 'eggs'])
        ['spam', 'eggs']

        >>> as_list(['spam', 'eggs'], ('spam', 'eggs'), 'foo', 'bar')
        ['spam', 'eggs', 'spam', 'eggs', 'foo', 'bar']
    """
    result = []
    for w in whatever:
        if w is None:
            continue
        elif isinstance(w, list):
            result += w
        elif isinstance(w, tuple):
            result += w
        else:
            result.append(w)
    return result


def remove_tors(tors1, tors2):
    """
    return the tors2 from tors 1
    """
    out_tors = []
    for torsion1 in tors1:
        found = 0
        for torsion2 in tors2:
            if torsion1 == torsion2:
                found = 1
        if found == 0:
            out_tors.append(torsion1)
    return out_tors


@classmethod
def length(cls, dataset):
    """
        Returns the length of the multi-tabular dataset making it appear
        like a single array of concatenated subpaths separated by NaN
        values.
        """
    if not dataset.data:
        return 0
    length = 0
    ds = cls._inner_dataset_template(dataset)
    for d in dataset.data:
        ds.data = d
        length += ds.interface.length(ds)
    return length + len(dataset.data) - 1


def from_name(name):
    """
        Return the class which matches ``name`` if it exists inside this
        module or raise an exception.
    """
    if name not in globals():
        raise NotImplementedError('IT of type %s is not supported' % name)
    return globals()[name]


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

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

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


def core_text_draw_func_basic(ticks, texts, level, f, g, dx_units, dy_units,
    angles, tick_lenght, text_distance, text_attrs, c, tick_info):
    """
    Core basic method to draw texts
    ticks: list of tick values to be drawn (not here)
    texts: list of text values to be drawn
    level: drawn level
    f,g: x,y functions
    dx_units, dy_units: unity vector components
    angles: angles of ticks
    tick_lenght: tick lenght
    text_distance: distance where text is drawn
    text_attr: attributes (alignment, etc.) provided to the function
    c: canvas to draw
    tick_info: general hook for axis dict
    """
    ti = tick_info
    n_texts = len(texts)
    if len(dx_units) < n_texts:
        print('too few dx_units !')
    if len(dy_units) < n_texts:
        print('too few dy_units !')
    if len(angles) < n_texts:
        print('too few angles !')
    for i, text_value in enumerate(texts):
        x = f(text_value) + text_distance * dy_units[i]
        y = g(text_value) - text_distance * dx_units[i]
        text_color = ti['text_color']
        if not ti['text_colors'] is None:
            text_color = ti['level_text_color'][level]
        text_size = ti['text_sizes'][level]
        if ti['text_format_func'] is None:
            text = ti['text_format'] % text_value
        else:
            text = ti['text_format_func'](text_value)
        c.text(x, y, text, text_attrs[i] + [text_color, text_size])


def join_host_strings(user, host, port=None):
    """
    Turns user/host/port strings into ``user@host:port`` combined string.

    This function is not responsible for handling missing user/port strings;
    for that, see the ``normalize`` function.

    If ``host`` looks like IPv6 address, it will be enclosed in square brackets

    If ``port`` is omitted, the returned string will be of the form
    ``user@host``.
    """
    if port:
        template = '%s@[%s]:%s' if host.count(':') > 1 else '%s@%s:%s'
        return template % (user, host, port)
    else:
        return '%s@%s' % (user, host)


def listRecords(metadataPrefix, set=None, from_=None, until=None):
    """Get a list of header, metadata and about information on records.

        metadataPrefix - identifies metadata set to retrieve
        set - set identifier; only return records in set (optional)
        from_ - only retrieve records from from_ date forward (optional)
        until - only retrieve records with dates up to and including
                until date (optional)

        Should raise error.CannotDisseminateFormatError if metadataPrefix
        is not supported by the repository.

        Should raise error.NoSetHierarchyError if the repository does not
        support sets.

        Returns an iterable of header, metadata, about tuples.
        """


def is_value_in(constants_group, value):
    """
    Checks whether value can be found in the given constants group, which in
    turn, should be a Django-like choices tuple.
    """
    for const_value, label in constants_group:
        if const_value == value:
            return True
    return False


@classmethod
def is_site_in_topic(cls) ->bool:
    """True if site id is in topic."""
    return True


@classmethod
def from_dict(cls, D):
    """
        Build a matrix from a dictionary from indexes to values.
        """
    N, M = cls.shape
    data = [0] * (N * M)
    for (i, j), value in D.items():
        if i >= cls.nrows or j >= cls.nrows:
            fmt = N, M, (i, j)
            raise IndexError('invalid index for %sx%s matrix: %r' % fmt)
        k = i * N + j
        data[k] = value
    return cls.from_flat(data)


def surface_density_toy_model(r, phi, param):
    """

    Surface density of the toy model matter blob.

    INPUT:

    - ``r`` -- Boyer-Lindquist radial coordinate `\\bar{r}` in the matter blob
    - ``phi`` -- Boyer-Lindquist azimuthal coordinate `\\bar{\\phi}` in the
      matter blob
    - ``param`` -- list of parameters defining the position and extent of the
      matter blob:

      - ``param[0]``: mean radius `r_0` (Boyer-Lindquist coordinate)
      - ``param[1]``: mean azimuthal angle `\\phi_0` (Boyer-Lindquist
        coordinate)
      - ``param[2]``: radial extent `\\lambda`
      - ``param[3]``: opening angle `\\Delta\\phi`
      - ``param[4]`` (optional): amplitude `\\Sigma_0`; if not provided,
        then `\\Sigma_0=1` is used

    OUTPUT:

    - surface density `\\Sigma(\\bar{r}, \\bar{\\phi})`

    EXAMPLES:

    Use with the default amplitude (`\\Sigma_0=1`)::

        sage: from kerrgeodesic_gw import surface_density_toy_model
        sage: param = [6.5, 0, 0.6, 0.1]
        sage: surface_density_toy_model(6.5, 0, param)
        1.0
        sage: surface_density_toy_model(6.7, -0.04, param)
        1.0
        sage: surface_density_toy_model(6.3, 0.04, param)
        1.0
        sage: surface_density_toy_model(7, -0.06, param)
        0.0
        sage: surface_density_toy_model(5., 0.06, param)
        0.0

    3D representation: `z=\\Sigma(\\bar{r}, \\bar{\\phi})` in terms of
    `x:=\\bar{r}\\cos\\bar\\phi` and `y:=\\bar{r}\\sin\\bar\\phi`::

        sage: s_plot = lambda r, phi: surface_density_toy_model(r, phi, param)
        sage: r, phi, z = var('r phi z')
        sage: plot3d(s_plot, (r, 6, 8), (phi, -0.4, 0.4),
        ....:        transformation=(r*cos(phi), r*sin(phi), z))
        Graphics3d Object

    .. PLOT::

        from kerrgeodesic_gw import surface_density_toy_model
        param = [6.5, 0, 0.6, 0.1]
        s_plot = lambda r, phi: surface_density_toy_model(r, phi, param)
        r, phi, z = var('r phi z')
        g = plot3d(s_plot, (r, 6, 8), (phi, -0.4, 0.4), \\
                   transformation=(r*cos(phi), r*sin(phi), z))
        sphinx_plot(g)

    Use with a non-default amplitude (`\\Sigma_0=2`)::

        sage: sigma0 = 2.
        sage: param = [6.5, 0, 0.6, 0.1, sigma0]
        sage: surface_density_toy_model(6.5, 0, param)
        2.0

    """
    r0, phi0 = param[0], param[1]
    Dr, Dphi = param[2], param[3]
    Sigma0 = float(param[4]) if len(param) == 5 else float(1)
    if abs(r - r0) < Dr / float(2) and abs(phi - phi0) < Dphi / float(2):
        return Sigma0
    return float(0)


def _code(code):
    """
    Suggar accessor to handle integers, exceptions and response
    objects"""
    return getattr(code, 'code', code)


def find_gist_by_id(github, _id):
    """Find a gist by _id"""
    dest = None
    for gist in github.iter_gists():
        if _id == gist.id or _id == gist.html_url:
            dest = gist
            break
    if dest is None:
        raise SystemExit('The gist ID or URL is not found, is it right?')
    return dest


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


def cluster_del_nodes(base, cluster_id, nodes, expected_status='SUCCEEDED',
    wait_timeout=None):
    """Utility function that delete nodes from cluster."""
    params = {'del_nodes': {'nodes': nodes}}
    res = base.client.trigger_action('clusters', cluster_id, params=params)
    action_id = res['location'].split('/actions/')[1]
    res = base.client.wait_for_status('actions', action_id, expected_status,
        wait_timeout)
    return res['body']['status_reason']


def architecture() ->str:
    """Returns the machine type, (e.g.: 'x86_64' or 'i386')"""
    from platform import machine
    return machine()


def is_agent_token_pregenerated(node):
    """Determines if the token was generated for out of band configuration.

    Ironic supports the ability to provide configuration data to the agent
    through the a virtual floppy or as part of the virtual media image
    which is attached to the BMC.

    This method helps us identify WHEN we did so as we don't need to remove
    records of the token prior to rebooting the token. This is important as
    tokens provided through out of band means presist in the virtual media
    image, are loaded as part of the agent ramdisk, and do not require
    regeneration of the token upon the initial lookup, ultimately making
    the overall usage of virtual media and pregenerated tokens far more
    secure.

    :param node: Node Object
    :returns: True if the token was pregenerated as indicated by the node's
              driver_internal_info field.
              False in all other cases.
    """
    return node.driver_internal_info.get('agent_secret_token_pregenerated',
        False)


def test():
    """
    The function ``is_valid_javascript_identifier`` validates a given
    identifier according to the latest draft of the ECMAScript 5 Specification:

      >>> is_valid_javascript_identifier('hello')
      True

      >>> is_valid_javascript_identifier('alert()')
      False

      >>> is_valid_javascript_identifier('a-b')
      False

      >>> is_valid_javascript_identifier('23foo')
      False

      >>> is_valid_javascript_identifier('foo23')
      True

      >>> is_valid_javascript_identifier('$210')
      True

      >>> is_valid_javascript_identifier(u'Straße')
      True

      >>> is_valid_javascript_identifier(r'b') # u'b'
      True

      >>> is_valid_javascript_identifier(r' ')
      False

      >>> is_valid_javascript_identifier('_bar')
      True

      >>> is_valid_javascript_identifier('some_var')
      True

      >>> is_valid_javascript_identifier('$')
      True

    But ``is_valid_jsonp_callback_value`` is the function you want to use for
    validating JSON-P callback parameter values:

      >>> is_valid_jsonp_callback_value('somevar')
      True

      >>> is_valid_jsonp_callback_value('function')
      False

      >>> is_valid_jsonp_callback_value(' somevar')
      False

    It supports the possibility of '.' being present in the callback name, e.g.

      >>> is_valid_jsonp_callback_value('$.ajaxHandler')
      True

      >>> is_valid_jsonp_callback_value('$.23')
      False

    As well as the pattern of providing an array index lookup, e.g.

      >>> is_valid_jsonp_callback_value('array_of_functions[42]')
      True

      >>> is_valid_jsonp_callback_value('array_of_functions[42][1]')
      True

      >>> is_valid_jsonp_callback_value('$.ajaxHandler[42][1].foo')
      True

      >>> is_valid_jsonp_callback_value('array_of_functions[42]foo[1]')
      False

      >>> is_valid_jsonp_callback_value('array_of_functions[]')
      False

      >>> is_valid_jsonp_callback_value('array_of_functions["key"]')
      False

    Enjoy!

    """


def get_status_string():
    """Active or Inactive in the specific locale"""


@classmethod
def from_dict(cls, data):
    """
        Construct DataFrame from dict of array-like or dicts.

        Parameters
        ----------
        data : dict
            Of the form {field : array-like} or {field : dict}.

        Returns
        -------
        DataFrame
        """
    return cls(data=data)


def egcd(a, b):
    """
    Extended Euclidean Algorithm
    returns x, y, gcd(a,b) such that ax + by = gcd(a,b)
    """
    u, u1 = 1, 0
    v, v1 = 0, 1
    while b:
        q = a // b
        u, u1 = u1, u - q * u1
        v, v1 = v1, v - q * v1
        a, b = b, a - q * b
    return u, v, a


@classmethod
def reset(cls):
    """ Reset the production index sequence to zero """
    cls._INDEX = 0


def is_number(data):
    """
    Check and return True if data is a number, else return False
    :param data: Input can be string, number or nan
    :return: True or False
    """
    try:
        data_cast = float(data)
        if data_cast >= 0 or data_cast <= 0:
            return True
        return False
    except ValueError:
        return False
    except TypeError:
        return False


@classmethod
def get(cls, driver_id):
    """
        Gets the driver.

        Parameters
        ----------
        driver_id : str
            the identifier of the driver.

        Returns
        -------
        driver : DataDriver
            the required driver.

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

            >>> import datarobot as dr
            >>> driver = dr.DataDriver.get('5ad08a1889453d0001ea7c5c')
            >>> driver
            DataDriver('PostgreSQL')
        """
    return cls.from_location('{}{}/'.format(cls._path, driver_id))


def extrude_move(ARMATURE_OT_extrude=None, TRANSFORM_OT_translate=None):
    """Create new bones from the selected joints and move them

    :param ARMATURE_OT_extrude: Extrude, Create new bones from the selected joints
    :param TRANSFORM_OT_translate: Translate, Translate (move) selected items
    """
    pass


def _upgrade(fields, sig):
    """Used by custom signatures in .from_dict, to keep common fields."""
    sig.update(chord_size=fields.get('chord_size'))
    return sig


def p_exclude(t):
    """exclude : EXCLUDE NOSPACESTRING"""
    t[0] = t[2]


def delta_percent(decimals=1):
    """A formatter to display the float delta as a percentage with a given number of decimals.
    It's different from the percent formatter in that it's prefixed with a sign (+ or -).

    Args:
        decimals: The number of decimals to display.

    Returns:
        A formatter function f returning f(a), being variable 'a' displayed as a signed percentage.
        Please note the formatter function will multiply the float by 100 to get a percentage.

    """
    return lambda a: '{:+.{prec}f}%'.format(100.0 * a, prec=decimals)


@classmethod
def write(cls, fname=None, outpath=None, atoms=None, comment_line=None):
    """Write structure data to file.

        Parameters
        ----------
        fname : str
        outpath : str, optional
            Output path for structure data file.
        atoms : :class:`~sknano.io.atoms.Atoms`
            An :class:`~sknano.io.atoms.Atoms` instance.
        comment_line : str, optional
            A string written to the first line of `json` file. If `None`,
            then it is set to the full path of the output `json` file.

        """
    pass


def __new__(mcs, name: str, bases: tuple, attrs: dict):
    """
        Meta class of search form
        :param name: name of current decorated class
        :param bases: base classes of current decorated class
        :param attrs: attributes of decorated class
        :return: an instance of the type class
        """
    mcs.init_meta_data(name, bases, attrs)
    mcs.set_columns(bases, attrs)
    return super().__new__(mcs, name, bases, attrs)


def rchop(string, ending):
    """Removes a substring at the end of a string."""
    if string.endswith(ending):
        return string[:-len(ending)]
    return string


def STR_LEN_CP(expression):
    """
    Returns the number of UTF-8 code points in the specified string.
    https://docs.mongodb.com/manual/reference/operator/aggregation/strLenCP/
    for more details
    :param expression: The string or expression of the string
    :return: Aggregation operator
    """
    return {'$strLenCP': expression}


def snake_case(name):
    """
    Converts CamelCase to snake_case.
    """
    chars = []
    upper_seq = 0
    for i, c in enumerate(name):
        if c.isupper():
            upper_seq += 1
            if i and name[i - 1].islower():
                chars.append('_')
        if c.islower():
            if upper_seq > 1:
                chars.insert(-1, '_')
            upper_seq = 0
        chars.append(c.lower())
    return ''.join(chars)


def get_repository_triggers(repositoryName=None):
    """
    Gets information about triggers configured for a repository.
    See also: AWS API Documentation

    :example: response = client.get_repository_triggers(
        repositoryName='string'
    )

    :type repositoryName: string
    :param repositoryName: [REQUIRED]
            The name of the repository for which the trigger is configured.

    :rtype: dict
    :return: {
        'configurationId': 'string',
        'triggers': [
            {
                'name': 'string',
                'destinationArn': 'string',
                'customData': 'string',
                'branches': [
                    'string',
                ],
                'events': [
                    'all'|'updateReference'|'createReference'|'deleteReference',
                ]
            },
        ]
    }

    :returns:
    (string) --

    """
    pass


def NB_calc(TP, FP, POP, w):
    """
    Calculate NB (Net Benefit).

    :param TP: true positive
    :type TP : int
    :param FP: false positive
    :type FP : int
    :param POP: population
    :type POP : int
    :param w: weight
    :type w: float
    :return: NB as float
    """
    try:
        NB = (TP - w * FP) / POP
        return NB
    except (ZeroDivisionError, TypeError):
        return 'None'


def nacl_bindings_pick_scrypt_params(opslimit, memlimit):
    """Python implementation of libsodium's pickparams"""
    if opslimit < 32768:
        opslimit = 32768
    r = 8
    if opslimit < memlimit // 32:
        p = 1
        maxn = opslimit // (4 * r)
        for n_log2 in range(1, 63):
            if 2 ** n_log2 > maxn // 2:
                break
    else:
        maxn = memlimit // (r * 128)
        for n_log2 in range(1, 63):
            if 2 ** n_log2 > maxn // 2:
                break
        maxrp = opslimit // 4 // 2 ** n_log2
        if maxrp > 1073741823:
            maxrp = 1073741823
        p = maxrp // r
    return n_log2, r, p


@staticmethod
def __clamp_percentage__(val):
    """
        clamp given percentage to a range from 0 to 100
        """
    if val > 100:
        val = 100
    elif val < 0:
        val = 0
    return val


def replace_in_tables(data, document, replacement):
    """
    Loops through tables in the document and replaces the field string with
    the replacement data from redcap form
    :param project: redcap.Project Object
    :param field: string object to search for in template document
    :param replacement: string of redcap field variable name
    :return: docx.Document object
    """
    for table in document.tables:
        for row in table.rows:
            for cell in row.cells:
                for para in cell.paragraphs:
                    para.text = para.text.replace(replacement, data.get(
                        replacement)) if not data.get(replacement
                        ) == None else para.text.replace(replacement, 'NA')
    return document


@classmethod
def static_header_len(cls, height):
    """Given a header height return its length."""
    return cls.static_header_offset(height + 1) - cls.static_header_offset(
        height)


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


def concat(*args):
    """concat(1, 2, 3) -> (1, 2, 3)"""
    return args


def unique_everseen(iterable, key=None):
    """List unique elements, preserving order. Remember all elements ever seen."""
    from future.moves.itertools import filterfalse
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element


def get_interface_type(interface):
    """Gets the type of interface
    """
    if interface.upper().startswith('ET'):
        return 'ethernet'
    elif interface.upper().startswith('VL'):
        return 'svi'
    elif interface.upper().startswith('LO'):
        return 'loopback'
    elif interface.upper().startswith('MG'):
        return 'management'
    elif interface.upper().startswith('MA'):
        return 'management'
    elif interface.upper().startswith('PO'):
        return 'portchannel'
    elif interface.upper().startswith('NV'):
        return 'nve'
    else:
        return 'unknown'


def extrinsic(func):
    """@extrinsic marks methods as invokable from templates."""
    func._extrinsic = True
    return func


@classmethod
def get(cls, storage_pool, _type, name):
    """Get a StorageVolume by type and name.

        Implements GET /1.0/storage-pools/<pool>/volumes/<type>/<name>

        The `_type` param can only (currently) be one of 'container', 'image'
        or 'custom'.  This was determined by read the LXD source.

        :param storage_pool: a storage pool object on which to fetch resources
        :type storage_pool: :class:`pylxd.models.storage_pool.StoragePool`
        :param _type: the type; one of 'container', 'image', 'custom'
        :type _type: str
        :param name: the name of the storage volume to get
        :type name: str
        :returns: a storage pool if successful, raises NotFound if not found
        :rtype: :class:`pylxd.models.storage_pool.StorageVolume`
        :raises: :class:`pylxd.exceptions.NotFound`
        :raises: :class:`pylxd.exceptions.LXDAPIExtensionNotAvailable` if the
            'storage' api extension is missing.
        """
    storage_pool.client.assert_has_api_extension('storage')
    response = storage_pool.api.volumes[_type][name].get()
    volume = cls(storage_pool.client, storage_pool=storage_pool, **response
        .json()['metadata'])
    return volume


def pytest_addoption(parser):
    """
    pytest hook used to add command line options used by this plugin
    """
    group = parser.getgroup('repo_health')
    group.addoption('--repo-path', action='store', dest='repo_path',
        default=None, help='path of repository on which to perform checks')
    group.addoption('--repo-health-path', action='store', dest=
        'repo_health_path', default=None, help=
        'path to repository where the checks are located. Even with this set, plugin will check in current dir'
        )
    group.addoption('--repo-health', action='store_true', dest=
        'repo_health', default=False, help=
        'if true, only repository health checks will be run')
    group.addoption('--output-path', action='store', dest='output_path',
        default='repo_health.yaml', help=
        'path to where yaml file should be stored')