def varLen(value):
    """
    Returns the the number of bytes an integer will be when
    converted to varlength
    >>> varLen(0)
    1
    >>> varLen(2097154)
    4
    """
    if value <= 127:
        return 1
    elif value <= 16383:
        return 2
    elif value <= 2097151:
        return 3
    else:
        return 4


def genstis(outname):
    """ Generate TestCases from cmdfile according to the pattern in patternfile"""
    pattern = """class stisS%d(countrateCase):
    def setUp(self):
        self.obsmode="%s"
        self.spectrum="%s"
        self.setglobal(__file__)
        self.runpy()
"""
    speclist = ['/grp/hst/cdbs/calspec/gd71_mod_005.fits',
        '/grp/hst/cdbs/calspec/gd153_mod_004.fits',
        '/grp/hst/cdbs/calspec/g191b2b_mod_004.fits']
    glist = {'g140l': 'fuvmama', 'g230l': 'nuvmama', 'g430l': 'ccd',
        'g750l': 'ccd', 'g230lb': 'ccd'}
    out = open(outname, 'a')
    out.write(
        """from pytools import testutil
import sys
from basecase import calcphotCase, calcspecCase, countrateCase,SpecSourcerateSpecCase

"""
        )
    count = 0
    for g in glist:
        for sp in speclist:
            obsmode = 'stis,%s,fuvmama,s52x2' % g
            defn = pattern % (count, obsmode, sp)
            out.write(defn)
            count += 1
    out.write(
        """

if __name__ == '__main__':
    if 'debug' in sys.argv:
        testutil.debug(__name__)
    else:
        testutil.testall(__name__,2)
"""
        )
    out.close()


@staticmethod
def extract(s, **params):
    """Extract the given property with given parameters from an Atoms
        object.

        | Args:
        |   s (ase.Atoms): the structure from which to extract the property
        |   params: named arguments specific to this type of property
        |

        | Returns:
        |   property: the value of the property for the given structure and
        |             parameters
        |

        """
    pass


@staticmethod
def hover(element):
    """ hover/move cursor to element
        :type element: WebElement
        :rtype: WebDriver
        """
    return element.hover()


def stsci(hdulist):
    """For STScI GEIS files, need to do extra steps."""
    instrument = hdulist[0].header.get('INSTRUME', '')
    if instrument in ('WFPC2', 'FOC'):
        rootname = hdulist[0].header.get('ROOTNAME', '')
        filetype = hdulist[0].header.get('FILETYPE', '')
        for i in range(1, len(hdulist)):
            hdulist[i].name = filetype
            hdulist[i]._extver = i
            hdulist[i].header['EXPNAME'
                ] = rootname, '9 character exposure identifier'
            hdulist[i].header['EXTVER'] = i, 'extension version number'
            hdulist[i].header['EXTNAME'] = filetype, 'extension name'
            hdulist[i].header['INHERIT'] = True, 'inherit the primary header'
            hdulist[i].header['ROOTNAME'
                ] = rootname, 'rootname of the observation set'


def invalidate():
    """Invalidate the session, giving a fresh one.
        """


@classmethod
def name_from_sl(cls, name):
    """
        Translate a field name from States Language.
        """
    if name in cls._FIELDS.inv:
        return cls._FIELDS.inv[name]
    elif name in cls._OUR_FIELDS.inv:
        return cls._OUR_FIELDS.inv[name]
    raise KeyError(name)


@classmethod
def from_hex(cls, hex_str):
    """Instantiate from a hexadecimal string."""
    return cls(bytes.fromhex(hex_str))


def getSkipUnknownChrString():
    """Necessary for various genotyping steps"""
    return """if [ "$coords" == "unmapped:no_mapped_reads" ]; then
	echo "Input is the unmapped bam... exiting" >> $logFile
	echo no_mapped_reads > $outVcf
	exit 0
else
	echo "Input is not the unmapped bam... continuing" >> $logFile 2>&1
fi

"""


def isAlphanum(c):
    """return true if the character is a letter, digit, underscore,
           dollar sign, or non-ASCII character.
    """
    return (c >= 'a' and c <= 'z' or c >= '0' and c <= '9' or c >= 'A' and
        c <= 'Z' or c == '_' or c == '$' or c == '\\' or c is not None and
        ord(c) > 126)


def generate_presigned_url(ClientMethod=None, Params=None, ExpiresIn=None,
    HttpMethod=None):
    """
    Generate a presigned url given a client, its method, and arguments

    :type ClientMethod: string
    :param ClientMethod: The client method to presign for

    :type Params: dict
    :param Params: The parameters normally passed to
            ClientMethod.

    :type ExpiresIn: int
    :param ExpiresIn: The number of seconds the presigned url is valid
            for. By default it expires in an hour (3600 seconds)

    :type HttpMethod: string
    :param HttpMethod: The http method to use on the generated url. By
            default, the http method is whatever is used in the method's model.

    """
    pass


def get_channel_config_command(channel, power_down, gain, input_type, bias,
    srb2, srb1):
    """Get command string for the given parameters.

    See
    :func:`Cyton.configure_channel<openbci_interface.cyton.Cyton.configure_channel>`
    """
    command = [b'x']
    vals = {(1): b'1', (9): b'Q', (2): b'2', (10): b'W', (3): b'3', (11):
        b'E', (4): b'4', (12): b'R', (5): b'5', (13): b'T', (6): b'6', (14):
        b'Y', (7): b'7', (15): b'U', (8): b'8', (16): b'I'}
    if channel not in vals:
        raise ValueError('`channel` value must be one of %s' % vals.keys())
    command.append(vals[channel])
    vals = {(0): b'0', 'ON': b'0', (1): b'1', 'OFF': b'1'}
    if power_down not in vals:
        raise ValueError('`power_down` must be one of %s' % vals.keys())
    command.append(vals[power_down])
    vals = {(1): b'0', (2): b'1', (4): b'2', (6): b'3', (8): b'4', (12):
        b'5', (24): b'6'}
    if gain not in vals:
        raise ValueError('`gain` value must be one of %s' % vals.keys())
    command.append(vals[gain])
    vals = {(0): b'0', 'NORMAL': b'0', (1): b'1', 'SHORTED': b'1', (2):
        b'2', 'BIAS_MEAS': b'2', (3): b'3', 'MVDD': b'3', (4): b'4', 'TEMP':
        b'4', (5): b'5', 'TESTSIG': b'5', (6): b'6', 'BIAS_DRP': b'6', (7):
        b'7', 'BIAS_DRN': b'7'}
    if input_type not in vals:
        raise ValueError('`input_type` type value must be one of %s.' %
            vals.keys())
    command.append(vals[input_type])
    vals = {(0): b'0', (1): b'1'}
    if bias not in vals.keys():
        raise ValueError('`bias` must be either 0 or 1.')
    command.append(vals[bias])
    vals = {(0): b'0', (1): b'1'}
    if srb2 not in vals.keys():
        raise ValueError('`srb2` must be either 0 or 1.')
    command.append(vals[srb2])
    vals = {(0): b'0', (1): b'1'}
    if srb1 not in vals.keys():
        raise ValueError('`srb1` must be either 0 or 1.')
    command.append(vals[srb1])
    command.append(b'X')
    return b''.join(command)


def TERM(executable, execopt='-e', execfmt='expanded', titleopt='-T'):
    """Helper to declare a terminal in the hardcoded list"""
    if execfmt not in ('expanded', 'string'):
        raise RuntimeError('Invalid execfmt')
    fmt = executable
    if titleopt is not None:
        fmt += ' ' + titleopt + ' {title}'
    fmt += ' {} {{{}}}'.format(execopt, execfmt)
    return fmt


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 swapext(filename, extension, delimiter='.'):
    """Return filename replacing its extension, adding if it has none.

    >>> swapext('spam.eggs', 'ham')
    'spam.ham'

    >>> swapext('spam', 'ham')
    'spam.ham'
    """
    name, delim, ext = filename.rpartition(delimiter)
    if not delim:
        name = ext
    return '%s%s%s' % (name, delimiter, extension)


def log2(ic):
    """
        Element-wise base 2 log of an `ImageCollection`.

        If the `ImageCollection` is empty, returns the empty `ImageCollection`.

        Example
        -------
        >>> import descarteslabs.workflows as wf
        >>> col = wf.ImageCollection.from_id("landsat:LC08:01:RT:TOAR",
        ...     start_datetime="2017-01-01", end_datetime="2017-05-30")
        >>> col.log2().compute(geoctx) # doctest: +SKIP
        ImageCollectionResult of length 2:
        ...
        """
    from ..math import arithmetic
    return arithmetic.log2(ic)


def save_migration(connection, basename):
    """ Save a migration in `migrations_applied` table """
    sql = 'INSERT INTO migrations_applied (name, date) VALUES (%s, NOW())'
    with connection.cursor() as cursor:
        cursor.execute(sql, (basename,))
        connection.commit()
    return True


def NOT_FOUND_FILE():
    """
    Hardcoded CSS file
    """
    return """
<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>404 Page not found</title>
    <link rel="shortcut icon" href="https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/160/google/223/hugging-face_1f917.png">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css">
    <link href="https://fonts.googleapis.com/css?family=Montserrat:900&display=swap" rel="stylesheet">

            Oops!

            404 PAGE NOT FOUND

                Go back home

"""


@classmethod
def by_name(cls, name: str):
    """Get service type by its name."""
    if name is None:
        return cls.GITHUB
    name = name.lower()
    if name == 'github':
        return cls.GITHUB
    elif name == 'gitlab':
        return cls.GITLAB
    else:
        raise NotImplementedError(
            f"Unsupported service {name!r}, available ones are 'github' and 'gitlab'"
            )


def pretty_string_time(t):
    """Custom printing of elapsed time"""
    if t > 4000:
        s = 't=%.1fh' % (t / 3600)
    elif t > 300:
        s = 't=%.0fm' % (t / 60)
    else:
        s = 't=%.0fs' % t
    return s


def find_root_and_group(ds):
    """Find the root and group name of a netCDF4/h5netcdf dataset."""
    hierarchy = ()
    while ds.parent is not None:
        hierarchy = (ds.name.split('/')[-1],) + hierarchy
        ds = ds.parent
    group = '/' + '/'.join(hierarchy)
    return ds, group


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

    See _handlers.doc_handle_echo for detailed documentation.
    """
    return 0


def auto_untype(arg):
    """ The oposite of auto_type : takes a python base object and tries to
    convert it to XML typed string.
    """
    if arg is True:
        return 'TRUE'
    elif arg is False:
        return 'FALSE'
    else:
        return arg


def get_axis_vector(axis_name, offset=1):
    """
    Returns axis vector from its name
    :param axis_name: name of the axis ('X', 'Y' or 'Z')
    :param offset: float, offset to the axis, by default is 1
    :return: list (1, 0, 0) = X | (0, 1, 0) = Y | (0, 0, 1) = Z
    """
    if axis_name in ['X', 'x']:
        return offset, 0, 0
    elif axis_name in ['Y', 'y']:
        return 0, offset, 0
    elif axis_name in ['Z', 'z']:
        return 0, 0, 1


def ecran_attends(cls, millisecondes):
    """Le programme attend 'millisecondes' millisecondes"""
    cls.ecran.delay(millisecondes)


def merge_dicts(*dict_args):
    """
    Given any number of dicts, shallow copy and merge into a new dict,
    precedence goes to key value pairs in latter dicts.
    """
    result = {}
    for dictionary in dict_args:
        result.update(dictionary)
    return result


@staticmethod
def short_name_type():
    """
        Returns the short name type for this port.

        :returns: string
        """
    return 's'


def _const_compare_digest_backport(a, b):
    """
    Compare two digests of equal length in constant time.

    The digests must be of type str/bytes.
    Returns True if the digests match, and False otherwise.
    """
    result = abs(len(a) - len(b))
    for l, r in zip(bytearray(a), bytearray(b)):
        result |= l ^ r
    return result == 0


def in_colab():
    """Check if the code is running in Google Colaboratory"""
    try:
        from google import colab
        return True
    except:
        return False


def validate_cronjob_schedule(schedule):
    """ Kontrollerer brukerinput for cronjob schedule
            Format på cronjob schedule string: "* * * * *"
            "minutt" "time" "dag i måned" "måned i år" "ukedag"
             (0-59)  (0-23)    (1-31)        (1-12)     (0-6)
    """
    schedule_list = schedule.split(' ')
    if not len(schedule_list) is 5:
        raise ValueError(
            f'Schedule {schedule} har ikke riktig format. Må ha formatet: "<minutt> <time> <dag i måned> <måned> <ukedag>". F.eks. "0 12 * * 2,4" vil gi: Hver tirsdag og torsdag kl 12.00 UTC'
            )
    if not schedule_list[0] is '*':
        for minute in schedule_list[0].split(','):
            if not int(minute) in range(0, 60):
                raise ValueError(
                    f'I schedule {schedule} er ikke {minute} en gyldig verdi for minutt innenfor time. Gyldige verdier er 0-59, eller *'
                    )
    if not schedule_list[1] is '*':
        for hour in schedule_list[1].split(','):
            if not int(hour) in range(0, 24):
                raise ValueError(
                    f'I schedule {schedule} er ikke {hour} en gyldig verdi for time. Gyldige verdier er 0-23, eller *'
                    )
    if not schedule_list[2] is '*':
        for day in schedule_list[2].split(','):
            if not int(day) in range(1, 32):
                raise ValueError(
                    f'I schedule {schedule} er ikke {day} en gyldig verdi for dag i måned. Gyldige verdier er 1-31, eller *'
                    )
    if not schedule_list[3] is '*':
        for month in schedule_list[3].split(','):
            if not int(month) in range(1, 13):
                raise ValueError(
                    f'I schedule {schedule} er ikke {month} en gyldig verdi for måned. Gyldige verdier er 1-12, eller *'
                    )
    if not schedule_list[4] is '*':
        for weekday in schedule_list[4].split(','):
            if not int(weekday) in range(0, 7):
                raise ValueError(
                    f'I schedule {schedule} er ikke {weekday} en gyldig verdi for ukedag. Gyldige verdier er 0-6 (søn-lør), eller *'
                    )


def convert_log_level(level=26):
    """
    Get a numeric log level from a string. The default 26 is for SHORT logs.

    :param level
    :return level
    """
    if not level:
        level = 26
    levels = {'notset': 0, 'debug': 10, 'info': 20, 'minimal': 22, 'short':
        26, 'warning': 30, 'error': 40, 'critical': 50}
    if isinstance(level, str):
        level = levels.get(level)
    return level


def transpose_axes(image, axes, asaxes=None):
    """Return image with its axes permuted to match specified axes.

    A view is returned if possible.

    >>> transpose_axes(numpy.zeros((2, 3, 4, 5)), 'TYXC', asaxes='CTZYX').shape
    (5, 2, 1, 3, 4)

    """
    for ax in axes:
        if ax not in asaxes:
            raise ValueError('unknown axis %s' % ax)
    if asaxes is None:
        asaxes = 'CTZYX'
    shape = image.shape
    for ax in reversed(asaxes):
        if ax not in axes:
            axes = ax + axes
            shape = (1,) + shape
    image = image.reshape(shape)
    image = image.transpose([axes.index(ax) for ax in asaxes])
    return image


def add_node(doc, parent, name, value=None):
    """
    Adds a node to the DOM document.

    :param doc: the DOM document
    :type doc: minidom.Document
    :param parent: the parent node to add the new node to
    :type parent: minidom.Element
    :param name: the name of the node
    :type name: str
    :param value: the text value, ignored if None
    :type value: str
    :return: the generated node
    :rtype: minidom.Element
    """
    node = doc.createElement(name)
    parent.appendChild(node)
    if value is not None:
        text = doc.createTextNode(value)
        node.appendChild(text)
    return node


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

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


def _print_if(condition, *args):
    """Print only if condition is True."""
    if condition:
        print(*args)


def setup_models(dbsession):
    """
    Add or update models / fixtures in the database.

    """
    pass


def uninstall(context):
    """Uninstall script"""


@staticmethod
def ticker(data, *args, **kwargs):
    """
        Returns list of ticker data in following format:
            [bid_price, ask_price, high, low, open, close, last, 24h_vol, ts]
        :param data: requests.response() obj
        :param args:
        :param kwargs:
        :return: list
        """
    return data


def isMuon(pid):
    """Determine if the PID is that of an muon or antimuon"""
    return abs(pid) == 13


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 do_code_hilite(md, what='all'):
    """
    "inverse" mode for source code highlighting:
    the file contains mainly code and md is within docstrings
    what in  all, code, doc, mod
    """
    if what not in ('all', 'code', 'doc', 'mod'):
        what = 'all'
    code_mode, md_mode = 1, 2
    blocks, block, mode = [], [], code_mode
    blocks.append([mode, block])
    lines = ('\n' + md).splitlines()
    mdstart = '\x01'
    while lines:
        line = lines.pop(0)
        if mode == code_mode:
            if line.rstrip() in ('"""_', "'''_", '/*_'):
                mdstart = line.rstrip()[:-1]
                mode = md_mode
                block = []
                if mdstart == '/*':
                    mdstart = '*/'
                blocks.append([md_mode, block])
                continue
        elif line.rstrip() == mdstart:
            if what == 'doc':
                break
            mode = code_mode
            block = []
            blocks.append([code_mode, block])
            continue
        if mode == code_mode:
            if what in ('all', 'code'):
                block.append(line)
        elif what != 'code':
            block.append(line)
    out = []
    for mode, block in blocks:
        b = '\n'.join(block)
        if not b:
            continue
        if mode == code_mode:
            out.append('```\n%s\n```' % b)
        else:
            out.append('\n'.join(block))
    return '\n'.join(out)


def strip(input_string):
    """Strip trailing whitespace, single/double quotes."""
    return input_string.strip().rstrip(';').strip('"').strip("'")


def is_timestamp(value):
    """Check if value is a valid timestamp."""
    if isinstance(value, bool):
        return False
    if not (isinstance(value, int) or isinstance(value, float) or
        isinstance(value, str)):
        return False
    try:
        float(value)
        return True
    except ValueError:
        return False


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

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

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


@staticmethod
def lusolve3(c, d, e, b):
    """
        x = LUsolve3(c, d, e, b)
        solves [c\\d\\e]{x} = {b}, where {c}, {d} and {e} are the vectors returned
        from LUdecomp3.
        """
    n = len(d)
    for k in range(1, n):
        b[k] = b[k] - c[k - 1] * b[k - 1]
    b[n - 1] = b[n - 1] / d[n - 1]
    for k in range(n - 2, -1, -1):
        b[k] = (b[k] - e[k] * b[k + 1]) / d[k]
    return b


def is_number(s):
    """
    Take a string and determin if it is a number

    Arguments:
        s (str): A string

    Returns:
        bool: True if it is a number, False otherwise
    """
    try:
        float(s)
        return True
    except ValueError:
        return False


def get_name_columns(column_defs):
    """ return a list of column_name where is_name is True """
    output = []
    for column_name in column_defs:
        metadata = column_defs[column_name]
        is_name = metadata.get('is_name')
        if is_name:
            output.append(column_name)
    return output


def to_python(value, state=None):
    """
        Convert `value` from its foreign representation to its Python
        representation.  `state` is for application-specific hooks.
        """


@staticmethod
def shell(sh):
    """Return Dockerfile SHELL instruction to set shell."""
    return 'SHELL ["{}", "-c"]'.format(sh)


def _zaxpy_no_blas(y, x, a=1.0):
    """Non-BLAS version of zaxpy for use when BLAS breaks."""
    y += a * x
    return y


@staticmethod
def pre_save(sender, instance, **kwargs):
    """
        If there is no state set, default to the start.
        """
    if instance.state is None:
        instance.state = instance.start


@classmethod
def _get_default_options(cls, options='default'):
    """ Default options structure for Collocation. """
    if options == 'default':
        return [1, 10]
    elif options == 'quiet':
        return [0, 10]


def encode(x):
    """
    Encode the integer `x` using a 7-bit+continuation-bit encoding,
    and return the list of 8-bit code words.
    """
    r = []
    while True:
        r.append(x & 127)
        x >>= 7
        if x == 0:
            break
    r = r[::-1]
    n = len(r) - 1
    i = 0
    while i < n:
        r[i] |= 128
        i += 1
    return r


def inline(text: str) ->str:
    """Get the given text as inline code.

    Parameters
    ----------
    text : str
        The text to be marked up.

    Returns
    -------
    str
        The marked up text.

    """
    if '`' in text:
        return '``{}``'.format(text)
    else:
        return '`{}`'.format(text)


def decorator_apply(dec, fun):
    """Rewrap `dec` to preserve function signature."""
    import decorator
    return decorator.FunctionMaker.create(fun,
        'return decorated(%(signature)s)', dict(decorated=dec(fun)),
        __wrapped__=fun)


@classmethod
def from_model(cls, model, url_type_registry=None):
    """
        Convert a model value to this object.
        """
    if url_type_registry is None:
        from any_urlfield.models.fields import AnyUrlField
        url_type_registry = AnyUrlField._static_registry
    url_type = url_type_registry.get_for_model(model.__class__)
    if url_type is None:
        raise ValueError('Unregistered model for AnyUrlValue: {0}'.format(
            model.__class__))
    return cls(url_type.prefix, model.pk, url_type_registry)


def is_namespace_mutable(context, namespace):
    """Return True if the namespace is mutable in this context."""
    if context.is_admin:
        return True
    if context.owner is None:
        return False
    return namespace.owner == context.owner


def get_is_ntuples(dic):
    """
    Determine data class from dic: XYDATA or NTUPLES
    """
    is_ntuples = False
    try:
        dataclass = dic['DATACLASS'][0]
        if dataclass.strip() == 'NTUPLES':
            is_ntuples = True
    except KeyError:
        pass
    return is_ntuples


@staticmethod
def remove_spaces(text):
    """Remove espaços em branco da str"""
    return text.replace('\r', '').replace('\n', '').replace('\t', '')


def nth_combination(iterable, r, index):
    """Equivalent to ``list(itertools.combinations(iterable, r))[index]``.

    .. versionadded:: 0.9.0

    Parameters
    ----------
    iterable : iterable
        The `iterable` to combine with :py:func:`itertools.combinations`.

    r : :py:class:`int`
        The number of elements to combine.

    index : :py:class:`int`
        The index of the combination.

    Returns
    -------
    random_combination : tuple
        The nth combination.

    Examples
    --------
    >>> from iteration_utilities import nth_combination
    >>> nth_combination([1,2,3,4,5,6], r=4, index=2)
    (1, 2, 3, 6)
    """
    pool = tuple(iterable)
    n = len(pool)
    if r < 0 or r > n:
        raise ValueError
    c = 1
    k = min(r, n - r)
    for i in range(1, k + 1):
        c = c * (n - k + i) // i
    if index < 0:
        index += c
    if index < 0 or index >= c:
        raise IndexError
    result = []
    while r:
        c, n, r = c * r // n, n - 1, r - 1
        while index >= c:
            index -= c
            c, n = c * (n - r) // n, n - 1
        result.append(pool[-1 - n])
    return tuple(result)


def abortConnection():
    """
        Close the connection abruptly.

        Discards any buffered data, stops any registered producer,
        and, if possible, notifies the other end of the unclean
        closure.

        @since: 11.1
        """


@staticmethod
def compare(power_1, power_2):
    """ Comparator object - Compares two Power objects

            :param power_1: The first Power object to compare
            :param power_2: The second Power object to compare
            :return: 1 if self is greater, -1 if other is greater, 0 if they are equal
        """
    cmp = lambda power_1, power_2: (power_1 > power_2) - (power_1 < power_2)
    xstr = lambda string: string or ''
    cmp_type = cmp(xstr(power_1.role), xstr(power_2.role))
    cmp_name = cmp(xstr(power_1.name), xstr(power_2.name))
    return cmp_type or cmp_name


def _create_ansi_color_dict(color_cls):
    """ Create a table that maps the 16 named ansi colors to their Windows code. """
    return {'ansidefault': color_cls.BLACK, 'ansiblack': color_cls.BLACK,
        'ansigray': color_cls.GRAY, 'ansibrightblack': color_cls.BLACK |
        color_cls.INTENSITY, 'ansiwhite': color_cls.GRAY | color_cls.
        INTENSITY, 'ansired': color_cls.RED, 'ansigreen': color_cls.GREEN,
        'ansiyellow': color_cls.YELLOW, 'ansiblue': color_cls.BLUE,
        'ansimagenta': color_cls.MAGENTA, 'ansicyan': color_cls.CYAN,
        'ansibrightred': color_cls.RED | color_cls.INTENSITY,
        'ansibrightgreen': color_cls.GREEN | color_cls.INTENSITY,
        'ansibrightyellow': color_cls.YELLOW | color_cls.INTENSITY,
        'ansibrightblue': color_cls.BLUE | color_cls.INTENSITY,
        'ansibrightmagenta': color_cls.MAGENTA | color_cls.INTENSITY,
        'ansibrightcyan': color_cls.CYAN | color_cls.INTENSITY}


def escape_rdn(rdn):
    """
    Escape rdn characters to prevent injection according to RFC 4514.
    """
    for char in ['\\', ',', '+', '"', '<', '>', ';', '=', '\x00']:
        rdn = rdn.replace(char, '\\' + char)
    if rdn[0] == '#' or rdn[0] == ' ':
        rdn = ''.join(('\\', rdn))
    if rdn[-1] == ' ':
        rdn = ''.join((rdn[:-1], '\\ '))
    return rdn


def replaceSuffix(rawname, suffix, new_suffix):
    """Replace the suffix in a raw file name.

    Parameters
    ----------
    rawname: str
        Name of a raw input file.

    suffix: str
        Suffix (last part of root name) that is expected to be found in
        the raw file name.

    new_suffix: str
        String to replace suffix to create an output file name.

    Returns
    -------
    newname: str
        rawname with suffix replaced by new_suffix.

    Examples
    --------
    >>> print replaceSuffix("rootname_rawtag.fits", "_rawtag", "_flt")
    rootname_flt.fits

    >>> print replaceSuffix("rootname_rawtag_a.fits", "_rawtag", "_flt")
    rootname_flt_a.fits
    """
    lenraw = len(rawname)
    lensuffix = len(suffix)
    i = rawname.rfind(suffix)
    if i >= 0:
        newname = rawname[0:i] + new_suffix + rawname[i + lensuffix:]
    else:
        raise RuntimeError('File name ' + rawname +
            ' was expected to have suffix ' + suffix)
    return newname


def unsplit(splitted_iter):
    """
	catenate a split string. This is needed to handle the special
	cases created by pg.string.split(). (Run-away quotations, primarily)
	"""
    s = ''
    quoted = False
    i = iter(splitted_iter)
    endq = ''
    for x in i:
        s += endq + x
        try:
            q, qtext = next(i)
            s += q + qtext
            if q == "E'":
                endq = "'"
            else:
                endq = q
        except StopIteration:
            break
    return s


def version_tuple(v):
    """Get an integer version tuple from a string."""
    return tuple(map(int, str(v).split('.')))


@classmethod
def _incref(cls, store):
    """ Record that a client is using the specified store. """
    try:
        cls._stores[store] += 1
    except KeyError:
        cls._stores[store] = 1


@classmethod
def _studio_response_to_kolibri_response(cls, studioresp):
    """
        This modifies the JSON response returned by Kolibri Studio,
        and then transforms its keys that are more in line with the keys
        we return with /api/channels.
        """
    included_languages = {}
    for code in studioresp.get('included_languages', []):
        included_languages[code] = cls._get_lang_native_name(code)
    channel_lang_name = cls._get_lang_native_name(studioresp.get('language'))
    resp = {'id': studioresp['id'], 'description': studioresp.get(
        'description'), 'name': studioresp['name'], 'lang_code': studioresp
        .get('language'), 'lang_name': channel_lang_name, 'thumbnail':
        studioresp.get('icon_encoding'), 'public': studioresp.get('public',
        True), 'total_resources': studioresp.get('total_resource_count', 0),
        'total_file_size': studioresp.get('published_size'), 'version':
        studioresp.get('version', 0), 'included_languages':
        included_languages, 'last_updated': studioresp.get('last_published'
        ), 'version_notes': studioresp.get('version_notes')}
    return resp


@staticmethod
def _getridof_double_peaks(data):
    """
        Small hack function to eliminate double peak values from a timeserie

        Parameters
        -----------
        data : pd.DataFrame
        """
    diff = data.diff()
    data[diff == 0.0] = data[diff == 0.0] - 0.001
    return data


def atom_formal_charge(atom):
    """Get formal charge for an atom.

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

    Returns
    -------
    list
        List containing one int only.
    """
    return [atom.GetFormalCharge()]


def invite_account_to_organization(Target=None, Notes=None):
    """
    Sends an invitation to another account to join your organization as a member account. Organizations sends email on your behalf to the email address that is associated with the other account's owner. The invitation is implemented as a  Handshake whose details are in the response.
    This operation can be called only from the organization's master account.
    See also: AWS API Documentation

    :example: response = client.invite_account_to_organization(
        Target={
            'Id': 'string',
            'Type': 'ACCOUNT'|'ORGANIZATION'|'EMAIL'
        },
        Notes='string'
    )

    :type Target: dict
    :param Target: [REQUIRED]
            The identifier (ID) of the AWS account that you want to invite to join your organization. This is a JSON object that contains the following elements:
            { 'Type': 'ACCOUNT', 'Id': '* **account id number** * ' }
            If you use the AWS CLI, you can submit this as a single string, similar to the following example:
            --target id=123456789012,type=ACCOUNT
            If you specify 'Type': 'ACCOUNT' , then you must provide the AWS account ID number as the Id . If you specify 'Type': 'EMAIL' , then you must specify the email address that is associated with the account.
            --target id=bill@example.com,type=EMAIL
            Id (string) --The unique identifier (ID) for the party.
            The regex pattern for handshake ID string requires 'h-' followed by from 8 to 32 lower-case letters or digits.
            Type (string) --The type of party.

    :type Notes: string
    :param Notes: Additional information that you want to include in the generated email to the recipient account owner.

    :rtype: dict
    :return: {
        'Handshake': {
            'Id': 'string',
            'Arn': 'string',
            'Parties': [
                {
                    'Id': 'string',
                    'Type': 'ACCOUNT'|'ORGANIZATION'|'EMAIL'
                },
            ],
            'State': 'REQUESTED'|'OPEN'|'CANCELED'|'ACCEPTED'|'DECLINED'|'EXPIRED',
            'RequestedTimestamp': datetime(2015, 1, 1),
            'ExpirationTimestamp': datetime(2015, 1, 1),
            'Action': 'INVITE'|'ENABLE_ALL_FEATURES'|'APPROVE_ALL_FEATURES',
            'Resources': [
                {
                    'Value': 'string',
                    'Type': 'ACCOUNT'|'ORGANIZATION'|'ORGANIZATION_FEATURE_SET'|'EMAIL'|'MASTER_EMAIL'|'MASTER_NAME'|'NOTES'|'PARENT_HANDSHAKE',
                    'Resources': {'... recursive ...'}
                },
            ]
        }
    }

    :returns:
    REQUESTED : This handshake was sent to multiple recipients (applicable to only some handshake types) and not all recipients have responded yet. The request stays in this state until all recipients respond.
    OPEN : This handshake was sent to multiple recipients (applicable to only some policy types) and all recipients have responded, allowing the originator to complete the handshake action.
    CANCELED : This handshake is no longer active because it was canceled by the originating account.
    ACCEPTED : This handshake is complete because it has been accepted by the recipient.
    DECLINED : This handshake is no longer active because it was declined by the recipient account.
    EXPIRED : This handshake is no longer active because the originator did not receive a response of any kind from the recipient before the expiration time (15 days).

    """
    pass


def flatten_material(material):
    """
    Flattens a given material.

    Args:
        material (dict): material config.

    Returns:
        list
    """
    lattice = material['lattice']
    return [material['_id'], material['name'], ', '.join(material['tags']),
        len(material['basis']['coordinates']), lattice['a'], lattice['b'],
        lattice['c'], lattice['alpha'], lattice['beta'], lattice['gamma']]


def kin2dyn(kin, density):
    """

    Convert from kinematic to dynamic viscosity.

    Parameters
    ----------
    kin: ndarray, scalar
        The kinematic viscosity of the lubricant.
    density: ndarray, scalar
        The density of the lubricant.

    Returns
    -------
    dyn: ndarray, scalar
        The dynamic viscosity of the lubricant.

    """
    dyn = kin * density
    return dyn


def cleanup(first_I, first_Z):
    """
     cleans up unbalanced steps
     failure can be from unbalanced final step, or from missing steps,
     this takes care of  missing steps
    """
    cont = 0
    Nmin = len(first_I)
    if len(first_Z) < Nmin:
        Nmin = len(first_Z)
    for kk in range(Nmin):
        if first_I[kk][0] != first_Z[kk][0]:
            print('\n WARNING: ')
            if first_I[kk] < first_Z[kk]:
                del first_I[kk]
            else:
                del first_Z[kk]
            print('Unmatched step number: ', kk + 1, '  ignored')
            cont = 1
        if cont == 1:
            return first_I, first_Z, cont
    return first_I, first_Z, cont


@staticmethod
def from_predictions(experiment, dmin=None, dmax=None, margin=1,
    force_static=False, padding=0):
    """
        Construct a reflection table from predictions.

        :param experiment: The experiment to predict from
        :param dmin: The maximum resolution
        :param dmax: The minimum resolution
        :param margin: The margin to predict around
        :param force_static: Do static prediction with a scan varying model
        :param padding: Padding in degrees
        :return: The reflection table of predictions

        """
    if experiment.profile is not None:
        return experiment.profile.predict_reflections(experiment.imageset,
            experiment.crystal, experiment.beam, experiment.detector,
            experiment.goniometer, experiment.scan, dmin=dmin, dmax=dmax,
            margin=margin, force_static=force_static, padding=padding)
    from dials.algorithms.spot_prediction.reflection_predictor import ReflectionPredictor
    predict = ReflectionPredictor(experiment, dmin=dmin, dmax=dmax, margin=
        margin, force_static=force_static, padding=padding)
    return predict()


def concat_keys_and_values(keys, vals):
    """ Format keys and values in string.
  e.g.
    keys = ['a', 'b', 'c']
    vals = [4, 5, 6]
    str = 'a:4, b:5, c:6'
  """
    fmt = ''
    for tup in zip(keys, vals):
        fmt += ', {0}: {1}'.format(tup[0], tup[1])
    return fmt


def isfilename(name):
    """
    returns True if name looks like a Mediawiki filename
    """
    if name[0].isalnum() and name[-3:].isalpha():
        return True
    return False


def get_glove_vocab(filename):
    """Load vocab from file

    Args:
        filename: path to the glove vectors

    Returns:
        vocab: set() of strings
    """
    print('Building vocab...')
    vocab = set()
    with open(filename) as f:
        for line in f:
            word = line.strip().split(' ')[0]
            vocab.add(word)
    print('- done. {} tokens'.format(len(vocab)))
    return vocab


def add_location(ax, name, lon, lat, crs, text_color=None):
    """
    Add a geodesic location to the plot axis
    """
    import matplotlib.patheffects as pe
    xy_point = xy_text = lon, lat
    ax.plot(*xy_point, marker='o', markersize=8, color='white')
    color = 'white'
    path_effects = None
    if text_color:
        color = text_color
        ax.plot(*xy_point, marker='o', markersize=4, color=text_color)
        patheffects = [pe.withStroke(linewidth=3.0, foreground='white')]
    ax.annotate(name, xy=xy_text, xycoords=crs._as_mpl_transform(ax), color
        =color, ha='left', va='center', path_effects=patheffects)
    return ax


def get(isdsAppliance, check_mode=False, force=False):
    """
    Retrieve existing fixpacks.
    """
    return isdsAppliance.invoke_get('Retrieving fixpacks', '/fixpacks')


def _get_bounds(z, b, wl, x0, xRes):
    """
    Gets the indices of range of wavelength that the wavelength wl is in
    with the size of some initial wavelength range.

    Used for checking if species with multiple lines (as in the OVI doublet)
    fit all lines appropriately.

    **Parameters**

    :z: float

        redshift

    :b: (3) ndarray/list

        initial bounds in form [i0,i1,i2] where i0 is the index of the
        minimum flux for the complex, i1 is index of the lower wavelength
        edge of the complex, and i2 is the index of the higher wavelength
        edge of the complex.

    :wl: float

        unredshifted wavelength of the peak of the new region

    :x0: float

        wavelength of the index 0

    :xRes: float

        difference in wavelength for two consecutive indices

    **Returns**

    :indices: (2) tuple

        Tuple (i1,i2) where i1 is the index of the lower wavelength bound of
        the new region and i2 is the index of the higher wavelength bound of
        the new region
    """
    r = [-b[1] + 100 + b[0], b[2] + 100 - b[0]]
    redWl = (z + 1) * wl
    iRedWl = int((redWl - x0) / xRes)
    indices = iRedWl - r[0], iRedWl + r[1]
    return indices


def retractboundary(repo, tr, targetphase, nodes):
    """Set nodes back to a phase changing other nodes phases if
    necessary.

    This function move boundary *backward* this means that all nodes
    are set in the target phase or kept in a *higher* phase.

    Simplify boundary to contains phase roots only."""
    phcache = repo._phasecache.copy()
    phcache.retractboundary(repo, tr, targetphase, nodes)
    repo._phasecache.replace(phcache)


def _filter_index_pages(docnames, base_dir):
    """Filter docnames to only yield paths of the form
    ``<base_dir>/<name>/index``

    Parameters
    ----------
    docnames : `list` of `str`
        List of document names (``env.found_docs``).
    base_dir : `str`
        Base directory of all sub-directories containing index pages.

    Yields
    ------
    docname : `str`
        Document name that meets the pattern.
    """
    for docname in docnames:
        parts = docname.split('/')
        if len(parts) == 3 and parts[0] == base_dir and parts[2] == 'index':
            yield docname


def read_decorrelation_terms(sub_block_size, actual_size_1_less, sub_block_data
    ):
    """returns a list of decorrelation terms
    and a list of decorrelation deltas per decorrelation pass

    term[pass] , delta[pass]"""
    if actual_size_1_less == 0:
        passes = sub_block_size * 2
    else:
        passes = sub_block_size * 2 - 1
    if passes > 16:
        raise ValueError('invalid decorrelation passes count')
    decorrelation_terms = []
    decorrelation_deltas = []
    for i in range(passes):
        decorrelation_terms.append(sub_block_data.read(5) - 5)
        if not (1 <= decorrelation_terms[-1] and decorrelation_terms[-1] <=
            18 or -3 <= decorrelation_terms[-1] and decorrelation_terms[-1] <=
            -1):
            raise ValueError('invalid decorrelation term')
        decorrelation_deltas.append(sub_block_data.read(3))
    decorrelation_terms.reverse()
    decorrelation_deltas.reverse()
    return decorrelation_terms, decorrelation_deltas


def HydrogenBondEnergy(distance, dpka_max, cutoff, f_angle=1.0):
    """
    returns a hydrogen-bond interaction pKa shift
    """
    if distance < cutoff[0]:
        value = 1.0
    elif distance > cutoff[1]:
        value = 0.0
    else:
        value = 1.0 - (distance - cutoff[0]) / (cutoff[1] - cutoff[0])
    dpKa = dpka_max * value * f_angle
    return abs(dpKa)


@staticmethod
def _step_one(iterator):
    """Step an iter_entries_by_dir iterator.

        :return: (has_more, path, ie)
            If has_more is False, path and ie will be None.
        """
    try:
        path, ie = next(iterator)
    except StopIteration:
        return False, None, None
    else:
        return True, path, ie


def reset():
    """Set the configuration back to the default state. Useful for testing."""
    global __context_name
    global __stores
    global __cache
    global __obfuscator
    __context_name = 'Default'
    __stores = None
    __cache = None
    __obfuscator = None


@staticmethod
def get_value_from_nested_dict(data_dict, map_str, separator='.'):
    """
            Get value from nested dict
        :param data_dict:
        :param map_str: key1.key2.key3
        :param separator: for split map string of path. Default: '.'
        :return:
        Ex: list_dict={{'id1': {'value':'1'}},
                       {'id2': {'value':'2'}},
                       {'id3': {'value':'3'}}
             map_str='id1.value'
          => return '1'
        """
    map_list = str(map_str).split(separator)
    pointer = data_dict
    value = None
    try:
        for ind in range(len(map_list)):
            key = map_list[ind]
            if isinstance(pointer, list):
                if ind == len(map_list) - 1:
                    value = pointer[int(key[1:-1])]
                    return value
                pointer = pointer[int(key[1:-1])]
            elif ind == len(map_list) - 1:
                value = pointer[key]
                return value
            elif key in pointer:
                pointer = pointer[key]
        return value
    except (KeyError, TypeError, IndexError):
        return None


def _values_sanity_check(values):
    """
    Ensures that values from the INSERT statement meet basic checks.
    """
    assert values
    assert values[0] == '('
    return True


def get_with_prefix(d, k, default=None, delimiter=':'):
    """    Retrieve a value from the dictionary, falling back to using its
    prefix, denoted by a delimiter (default ':'). Useful for cases
    such as looking up `raven-java:logback` in a dict like
    {"raven-java": "7.0.0"}.
    """
    prefix = k.split(delimiter, 1)[0]
    for key in [k, prefix]:
        if key in d:
            return d[key]
        key = key.lower()
        if key in d:
            return d[key]
    return default


def resolveRelationshipToken(token):
    """Returns a relationship for the given token"""


def Kv_to_K(Kv, D):
    """Convert valve flow coefficient from common metric units to regular
    loss coefficients.

    .. math::
        K = 1.6\\times 10^9 \\frac{D^4}{K_v^2}

    Parameters
    ----------
    Kv : float
        Metric Kv valve flow coefficient (flow rate of water at a pressure drop
        of 1 bar) [m^3/hr]
    D : float
        Inside diameter of the valve [m]

    Returns
    -------
    K : float
        Loss coefficient, [-]

    Notes
    -----
    Crane TP 410 M (2009) gives the coefficient of 0.04 (with diameter in mm).

    It also suggests the density of water should be found between 5-40°C.
    Older versions specify the density should be found at 60 °F, which is
    used here, and the pessure for the appropriate density is back calculated.

    .. math::
        \\Delta P = 1 \\text{ bar} = \\frac{1}{2}\\rho V^2\\cdot K

        V = \\frac{\\frac{K_v\\cdot \\text{ hour}}{3600 \\text{ second}}}{\\frac{\\pi}{4}D^2}

        \\rho = 999.29744568 \\;\\; kg/m^3  \\text{ at } T=60° F, P = 703572 Pa

    The value of density is calculated with IAPWS-95; it is chosen as it makes
    the coefficient a very convenient round number. Others constants that have
    been used are 1.604E9, and 1.60045E9.

    Examples
    --------
    >>> Kv_to_K(2.312, .015)
    15.153374600399898

    References
    ----------
    .. [1] ISA-75.01.01-2007 (60534-2-1 Mod) Draft
    """
    return 1600000000.0 * D ** 4 * Kv ** -2


def validate_string_dict(dct):
    """Validate that the input is a dict with string keys and values.

    Raises ValueError if not."""
    for k, v in dct.items():
        if not isinstance(k, str):
            raise ValueError('key %r in dict must be a string' % k)
        if not isinstance(v, str):
            raise ValueError('value %r in dict must be a string' % v)


def bech32_polymod(values):
    """Internal function that computes the Bech32 checksum."""
    generator = [996825010, 642813549, 513874426, 1027748829, 705979059]
    chk = 1
    for value in values:
        top = chk >> 25
        chk = (chk & 33554431) << 5 ^ value
        for i in range(5):
            chk ^= generator[i] if top >> i & 1 else 0
    return chk


def progress_bar(logger, percentage, final_text=''):
    """Very simple, multiline, logger-compatible progress bar, with increments of 5%."""
    progress = int(percentage / 5)
    logger.info(' |%s| %3d%% %s', '@' * progress + '-' * (20 - progress),
        percentage, final_text)


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

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


@staticmethod
def _w3c_name(name):
    """
        Generate a W3C Name from a string.
        """
    name = name.replace(':', '-')
    name = name.replace(' ', '_')


def convert2boolean(arg):
    """convert2boolean is used for environmental variables
    that must be returned as boolean"""
    if not isinstance(arg, bool):
        return arg.lower() in ('yes', 'true', 't', '1', 'y')
    return arg


@staticmethod
def format_exact(seconds):
    """Format a time delta in a human readable format.

        Examples
        --------
        >>> from ptvpy._cli_utils import CliTimer
        >>> CliTimer.format_exact(0.5)
        '0.50 s'
        >>> CliTimer.format_exact(1276)
        '21 min 16 s'
        >>> CliTimer.format_exact(2 ** 14)
        '4 h 33 min 04 s'
        """
    if seconds < 1:
        return f'{seconds:.2f} s'
    if seconds < 60:
        return f'{seconds:.1f} s'
    minutes, seconds = divmod(round(seconds), 60)
    if minutes < 60:
        return f'{minutes:d} min {seconds:02d} s'
    hours, minutes = divmod(minutes, 60)
    return f'{hours:d} h {minutes:02d} min {seconds:02d} s'


def describe_network_interface_attribute(DryRun=None, NetworkInterfaceId=
    None, Attribute=None):
    """
    Describes a network interface attribute. You can specify only one attribute at a time.
    See also: AWS API Documentation

    Examples
    This example describes the attachment attribute of the specified network interface.
    Expected Output:
    This example describes the description attribute of the specified network interface.
    Expected Output:
    This example describes the groupSet attribute of the specified network interface.
    Expected Output:
    This example describes the sourceDestCheck attribute of the specified network interface.
    Expected Output:

    :example: response = client.describe_network_interface_attribute(
        DryRun=True|False,
        NetworkInterfaceId='string',
        Attribute='description'|'groupSet'|'sourceDestCheck'|'attachment'
    )

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

    :type NetworkInterfaceId: string
    :param NetworkInterfaceId: [REQUIRED]
            The ID of the network interface.

    :type Attribute: string
    :param Attribute: The attribute of the network interface. This parameter is required.

    :rtype: dict
    :return: {
        'NetworkInterfaceId': 'string',
        'Description': {
            'Value': 'string'
        },
        'SourceDestCheck': {
            'Value': True|False
        },
        'Groups': [
            {
                'GroupName': 'string',
                'GroupId': 'string'
            },
        ],
        'Attachment': {
            'AttachmentId': 'string',
            'InstanceId': 'string',
            'InstanceOwnerId': 'string',
            'DeviceIndex': 123,
            'Status': 'attaching'|'attached'|'detaching'|'detached',
            'AttachTime': datetime(2015, 1, 1),
            'DeleteOnTermination': True|False
        }
    }

    """
    pass


def __new__(cls, *args, **kwargs):
    """
        Makes sure NotificationCenter is a singleton
        """
    if cls._instance is None:
        cls._instance = object.__new__(cls, *args, **kwargs)
    return cls._instance


def _tensor_max(*args):
    """Elementwise maximum of a sequence of tensors"""
    maximum, *rest = args
    for arg in rest:
        maximum = maximum.max(arg)
    return maximum


def _number(string):
    """
        Extracts an int from a string.
        Returns a 0 if None or an empty string was passed.
    """
    if not string:
        return 0
    elif string == '':
        return 0
    else:
        try:
            return int(string)
        except ValueError:
            return float(string)


def full_1d(length, fill_value, dtype, ctx):
    """Create a 1D tensor full of the fill_value.

    Parameters
    ----------
    shape : int
        The length of the vector.
    fill_value : int
        The filled value.
    dtype : data type
        It should be one of the values in the data type dict.
    ctx : context
        The device of the result tensor.

    Returns
    -------
    Tensor
        A result 1D tensor
    """
    pass


def _get_pfs_version():
    """
    Indicate the version of PFS XML you are using
    """
    return '4.0'


def generate_schema(primary_keys) ->object:
    """Generate singer schema for kafka messages

    MESSAGE_TIMESTAMP: Automatically will extract from kafka metadata
    MESSAGE: The original kafka message
    DYNAMIC_COLUMNS_FOR_PK: optional
    """
    schema = {'type': 'object', 'properties': {'message_timestamp': {'type':
        ['integer', 'string', 'null']}, 'message_offset': {'type': [
        'integer', 'null']}, 'message_partition': {'type': ['integer',
        'null']}, 'message': {'type': ['object', 'array', 'string', 'null']}}}
    for key in primary_keys:
        schema['properties'][key] = {'type': ['string', 'null']}
    return schema


def _line_segment_with_colons(linefmt, align, colwidth):
    """Return a segment of a horizontal line with optional colons which
    indicate column's alignment (as in `pipe` output format)."""
    fill = linefmt.hline
    w = colwidth
    if align in ['right', 'decimal']:
        return fill[0] * (w - 1) + ':'
    elif align == 'center':
        return ':' + fill[0] * (w - 2) + ':'
    elif align == 'left':
        return ':' + fill[0] * (w - 1)
    else:
        return fill[0] * w


def rename_label(labels, old, new):
    """Rename a label in a parcellation

    Parameters
    ----------
    labels : list of Label
        The labels
    old, new : str
        Old and new names without hemi affix.

    Notes
    -----
    Modifies ``labels`` in-place, returns None.
    """
    delim = '-'
    for hemi in ('lh', 'rh'):
        old_ = delim.join((old, hemi))
        for label in labels:
            if label.name == old_:
                new_ = delim.join((new, hemi))
                label.name = new_


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 inline(text: str) ->str:
    """Get the given text as inline code.

    Parameters
    ----------
    text : str
        The text to be marked up.

    Returns
    -------
    str
        The marked up text.

    """
    if '`' in text:
        return '``{}``'.format(text)
    else:
        return '`{}`'.format(text)


@classmethod
def from_properties_container(cls, properties_container):
    """
        Create StarContainer from properties container.

        :param properties_container:
        :return: elisa.base.container.StarContainer
        """
    container = cls()
    container.__dict__.update(properties_container.__dict__)
    return container


def _check_csv(data):
    """
    Returns a string representing an error message if data is malformed [INTERNAL FUNCTION]

    If the data is a properly formed CSV value, this function returns the empty string.

    Parameter data: The Python value to encode as a CSV file
    Precondition: None
    """
    from functools import reduce
    if type(data) not in [tuple, list]:
        return 'CSV data is neither a tuple nor a list'
    if not (type(data[0]) in [tuple, list] and reduce(lambda a, b: a and
        type(b) == str, data[0])):
        return 'Row %s is not a valid CSV header' % repr(data[0])
    headlen = len(data[0])
    for pos in range(1, len(data)):
        if type(data[pos]) not in [tuple, list]:
            return 'Row %d is malformed' % pos
        elif len(data[pos]) != headlen:
            return 'Row %d does not match the header length' % pos
    return ''


def state_length(state, size):
    """Check that the state is the given size."""
    if len(state) != size:
        raise ValueError(
            'Invalid state: there must be one entry per node in the network; this state has {} entries, but there are {} nodes.'
            .format(len(state), size))
    return True


def gaia_dr2_conesearch_query(ra=165.86, dec=34.829694, radius=3.0, max=100000
    ):
    """
    Generate a query string for the TAP servers
    TBD

    Parameters
    ----------
    ra, dec : float
        RA, Dec in decimal degrees

    radius : float
        Search radius, in arc-minutes.

    Returns
    -------
    query : str
        Query string

    """
    query = (
        "SELECT TOP {3} * FROM gaiadr2.gaia_source  WHERE CONTAINS(POINT('ICRS',gaiadr2.gaia_source.ra,gaiadr2.gaia_source.dec),CIRCLE('ICRS',{0},{1},{2:.2f}))=1"
        .format(ra, dec, radius / 60.0, max))
    return query


def get_slanted_adjacent_coords(x, y):
    """
    returns the six adjacent coordinates on a standard keyboard, where each row is slanted to the right from the last.
    adjacencies are clockwise, starting with key to the left, then two keys above, then right key, then two keys below.
    (that is, only near-diagonal keys are adjacent, so g's coordinate is adjacent to those of t,y,b,v, but not those of r,u,n,c.)
    """
    return [(x - 1, y), (x, y - 1), (x + 1, y - 1), (x + 1, y), (x, y + 1),
        (x - 1, y + 1)]


def _add_doc(func, doc):
    """Add documentation to a function."""
    func.__doc__ = doc


def is_null_slice(obj) ->bool:
    """
    We have a null slice.
    """
    return isinstance(obj, slice
        ) and obj.start is None and obj.stop is None and obj.step is None


def removeUnderscores(source):
    """This function replaces the underscores in a string with spaces, and is
    used for formatting unit output."""
    result = ''
    for c in source:
        if c == '_':
            result += ' '
        else:
            result += c
    return result


def _mask_dict(in_dict, mask):
    """Given a dict and a list of fields removes all fields not in the list"""
    for key in (set(in_dict.keys()) - set(mask)):
        in_dict.pop(key)
    return in_dict


@classmethod
def get_extended_resources(cls, version):
    """Retrieve the extended resource map for the API definition.

        :param version: The API version to retrieve the resource attribute
            map for.
        :returns: The extended resource map for the underlying API definition
            if the version is 2.0. The extended resource map returned includes
            both the API definition's RESOURCE_ATTRIBUTE_MAP and
            SUB_RESOURCE_ATTRIBUTE_MAP where applicable. If the version is
            not 2.0, an empty dict is returned.
        """
    if version == '2.0':
        cls._assert_api_definition('RESOURCE_ATTRIBUTE_MAP')
        cls._assert_api_definition('SUB_RESOURCE_ATTRIBUTE_MAP')
        sub_attrs = cls.api_definition.SUB_RESOURCE_ATTRIBUTE_MAP or {}
        return dict(list(cls.api_definition.RESOURCE_ATTRIBUTE_MAP.items()) +
            list(sub_attrs.items()))
    else:
        return {}


def remove_tags(LoadBalancerNames=None, Tags=None):
    """
    Removes one or more tags from the specified load balancer.
    See also: AWS API Documentation

    Examples
    This example removes the specified tag from the specified load balancer.
    Expected Output:

    :example: response = client.remove_tags(
        LoadBalancerNames=[
            'string',
        ],
        Tags=[
            {
                'Key': 'string'
            },
        ]
    )

    :type LoadBalancerNames: list
    :param LoadBalancerNames: [REQUIRED]
            The name of the load balancer. You can specify a maximum of one load balancer name.
            (string) --

    :type Tags: list
    :param Tags: [REQUIRED]
            The list of tag keys to remove.
            (dict) --The key of a tag.
            Key (string) --The name of the key.

    :rtype: dict
    :return: {}

    """
    pass


@staticmethod
def p_loc_measurment_optional_list_optional(p):
    """loc_measurement_optional_list_optional : empty
                                                  | loc_measurement_optional_list"""
    p[0] = tuple() if p[1] is None else p[1]


def str2bool(S):
    """convert a string to a boolean
    we use only the first letter"""
    return {'0': False, 'n': False, 'N': False, 'f': False, 'F': False, '1':
        True, 'y': True, 'Y': True, 't': True, 'T': True}[S[0]]


def func_hierarchy(args):
    """not implemented yet"""
    url = 'http://punx.readthedocs.io/en/latest/analyze.html'
    print('A chart of the NeXus hierarchy is in the **punx** documentation.')
    print('see: ' + url)


@classmethod
def puppet_module_list(cls, options):
    """List content view puppet modules"""
    cls.command_sub = 'puppet-module list'
    return cls.execute(cls._construct_command(options), output_format='csv')


def get_metafield(doc, metafield):
    """For fields like _parent and _routing es1.x requires you to request them
    in 'fields', and they're returned as such. ES2.x always returns them but
    at the root document level (like _id). This function copes with both.
    """
    return doc.get(metafield, doc.get('fields', {}).get(metafield))


def add_polygon(pic, point_list, col):
    """Draw an empty polygon of Color col with corners for every vertex
    in list point_list on Picture pic.

    Note:
    point_list is a list containing vertices xy coordinates
    (ex. [x1,y1,x2,y2,x3,y3]) It should contain at least
    three coordinate pairs."""
    pic.add_polygon(col, point_list)


def rename():
    """Rename file or file directory

    """
    pass


def focal_rf(radius):
    """Usage: focal point with radius for concave and convex mirrors"""
    return radius / 2


def check_nbits(nbits):
    """Given a number of bits per sample check to make sure
    `filterbank.py` can cope with it.

    Parameters
    ----------
    nbits : int
        Number of bits per sample, as recorded in the filterbank file's
        header.

    Raises
    ------
    ValueError
        If `filterbank.py` cannot cope.

    """
    if nbits not in [32, 16, 8]:
        raise ValueError(
            '`filterbank.py` only supports files with 8- or 16-bit integers, or 32-bit floats (nbits provided: {})!'
            .format(nbits))


def get_account_id(context):
    """
    Return the AWS account id for the executing lambda function

    Args:
        context: AWS lambda Context Object http://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns:
        str : AWS Account ID

    """
    return str(context.invoked_function_arn.split(':')[4])


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 send(dest, msg, transactionid=None, content_type='text/plain'):
    """STOMP send command.

    dest:
        This is the channel we wish to subscribe to

    msg:
        This is the message body to be sent.

    transactionid:
        This is an optional field and is not needed
        by default.

    """
    transheader = ''
    if transactionid:
        transheader = 'transaction:%s\n' % transactionid
    return 'SEND\ndestination:%s\ncontent-type:%s\n%s\n%s\x00\n' % (dest,
        content_type, transheader, msg)


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

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

    """
    pass


@classmethod
def json_dump_default(cls, o):
    """
        Override this to implement custom JSON encoding. Passed to json.dump method.
        :param o: Object which cannot be JSON-serialized.
        :return: JSON-serializable object (or throw TypeError)
        """
    raise TypeError("Can't JSON serialize {}".format(type(o).__name__))


def lengthOf(obj, names, kwargs):
    """
    A validator to test whether or not some named properties have a
    specific length.  The length is specified in one of two ways: either
    a C{range} keyword set with a C{range} / C{xrange} / C{list} object
    containing valid values, or a C{length} keyword with the exact length
    allowed.

    For those named properties that do not have the specified length
    (or that are C{None}), an error will be recorded in C{obj.errors}.

    @param obj: The object whose properties need to be tested.
    @param names: The names of the properties to test.
    @param kwargs: Keyword arguments.  Right now, all but
    C{message}, C{range}, and C{length} values are ignored.
    """
    xr = kwargs.get('range', [kwargs.get('length', 1)])
    minmax = str(min(xr)), str(max(xr))
    if minmax[0] == minmax[1]:
        message = kwargs.get('message', 'must have a length of %s.' % minmax[0]
            )
    else:
        message = kwargs.get('message',
            'must have a length between %s and %s (inclusive).' % minmax)
    for name in names:
        val = getattr(obj, name, '')
        if val is None or not len(val) in xr:
            obj.errors.add(name, message)


def split_before(iterable, pred, maxsplit=-1):
    """Yield lists of items from *iterable*, where each list ends just before
    an item for which callable *pred* returns ``True``:

        >>> list(split_before('OneTwo', lambda s: s.isupper()))
        [['O', 'n', 'e'], ['T', 'w', 'o']]

        >>> list(split_before(range(10), lambda n: n % 3 == 0))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

    At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
    then there is no limit on the number of splits:

        >>> list(split_before(range(10), lambda n: n % 3 == 0, maxsplit=2))
        [[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
    """
    if maxsplit == 0:
        yield list(iterable)
        return
    buf = []
    it = iter(iterable)
    for item in it:
        if pred(item) and buf:
            yield buf
            if maxsplit == 1:
                yield [item] + list(it)
                return
            buf = []
            maxsplit -= 1
        buf.append(item)
    yield buf


def screen(image1, image2):
    """
    Superimposes two inverted images on top of each other. At least one of the
    images must have mode "1".

    .. code-block:: python

        out = MAX - ((MAX - image1) * (MAX - image2) / MAX)

    :rtype: :py:class:`~PIL.Image.Image`
    """
    image1.load()
    image2.load()
    return image1._new(image1.im.chop_screen(image2.im))


@classmethod
def _from_dict(cls, _dict):
    """Initialize a AnalyticsEngineLoggingServer object from a json dictionary."""
    return cls.from_dict(_dict)


def is_mutating(status):
    """Determines if the statement is mutating based on the status."""
    if not status:
        return False
    mutating = set(['insert', 'update', 'delete', 'alter', 'create', 'drop',
        'replace', 'truncate', 'load'])
    return status.split(None, 1)[0].lower() in mutating


def plot_overflow(ax, x, y, ylim, overflow_params):
    """
    Plots labels with values greater than ylim

    This function plots labels with values greater than ylim.

    @param ax (Axis): axis where to plot
    @param x (number): x value
    @param y (number): y value
    @param ylim (number): maximum y value in the figure
    @param overflow_params (dict): dictionary of parameters to be used for the labels
    """
    if y >= ylim[1]:
        ax.text(x, ylim[1] + ylim[1] * 0.01, '%.2f' % y, **overflow_params[
            'label'])


def read_settings(path):
    """
    Read settings from an external file.

    The external file must be simply formatted like:
        # These are settings.
        a = 0
        b = "one"
        c = {"two": 2, "three": True, "four": None}
        ""\"
        A long comment.
        ""\"
        d = 5
    A dictionary equivalent to the global namespace of the external file is
    returned.

    path is a string that specifies the path to the external settings file.
    """
    import ast
    literal_eval = ast.literal_eval
    settings_dict = {}
    with open(path) as f:
        open_tri_quote = False
        for n, line in enumerate(f):
            if open_tri_quote:
                if '"""' in line:
                    open_tri_quote = False
                    continue
                continue
            bare_line = line.strip()
            if bare_line.startswith('#') or not bare_line:
                continue
            if bare_line.startswith('"""'):
                open_tri_quote = True
                continue
            var_name, _, val = bare_line.partition('=')
            try:
                settings_dict[var_name.rstrip()] = literal_eval(val.lstrip())
            except:
                raise TypeError(
                    'settings file is not correctly formatted on line {}: {}'
                    .format(n, path))
    return settings_dict


def iter_chunk(sequence, size):
    """
    Iterate sequence as chunks

    :param sequence: iterable sequence
    :param size: size of every chunk
    """
    length = len(sequence)
    for i in range(0, length, size):
        yield sequence[i:i + size]


def conf_int(x, p=0.05):
    """Confidence interval of a normally distributed array."""
    x = sorted(x)
    l = len(x)
    i1 = int(round(p / 2 * l + 0.5))
    i2 = int(round((1 - p / 2) * l - 0.5))
    ci1 = x[i1]
    ci2 = x[i2]
    return ci1, ci2


def sphere_bulk_velocity(halo):
    """
    Set the bulk velocity for the sphere.

    Parameters
    ----------
    halo : Halo object
        The Halo object to be provided by the HaloCatalog.

    """
    halo.data_object.set_field_parameter('bulk_velocity', halo.data_object.
        quantities.bulk_velocity(use_particles=True))


def getInstructionPointer(registerMap):
    """
        Return the instruction pointer value from the given register map

        @type registerMap: map
        @param registerMap: Map of register names to value

        @rtype: int
        @return: The value of the instruction pointer
    """
    for reg in ['rip', 'eip', 'pc']:
        if reg in registerMap:
            return registerMap[reg]
    raise RuntimeError(
        'Register map does not contain a usable instruction pointer!')


def display_ruleset_list(rulesets):
    """display function for listing rulesets"""
    activation_messages = ['(INACTIVE)', '(ACTIVE)']
    print('Rulesets:')
    i = 1
    for ruleset in rulesets:
        print('\t%s.\t%s\t\t%s' % (i, ruleset[0], activation_messages[
            ruleset[1]]))
        i += 1


def urlify(url):
    """Strip a string to return a valid URL."""
    return url.strip().replace(' ', '_')


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

        :param account.SetProfilePhotoError val:
        :rtype: MembersSetProfilePhotoError
        """
    return cls('photo_error', val)


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

    """
    pass


@classmethod
def instance(cls, *args, **kwargs):
    """ Singleton getter """
    if cls._instance is None:
        cls._instance = cls(*args, **kwargs)
        _ = cls._instance.reload()
    return cls._instance


def gen_italic(text, alternative=False):
    """Creates text in italics.

    Args:
      text (string): The text to set to italics.
      alternative (bool): Use alternative format '_' instead of '*'

    Returns:
        string: The text formatted as italics.

    """
    if alternative:
        return '_' + text + '_'
    else:
        return '*' + text + '*'


def trailing_blank_lines(physical_line, lines, line_number):
    """
    JCR: Trailing blank lines are superfluous.

    >>> trailing_blank_lines('\\n', ['SELECT 1','\\n'], 2)
    (0, 'W391 blank line at end of file')
    """
    if physical_line.strip() == '' and line_number == len(lines):
        return 0, 'W391 blank line at end of file'


def set_local_storage(driver, key, value):
    """Sets value in browsers local storage"""
    driver.execute_script("localStorage.setItem('%s', '%s')" % (key, value))


def remove_doubles(threshold: float=0.0002):
    """Remove selected particles close enough of others

    :param threshold: Merge Distance, Threshold distance withing which particles are removed
    :type threshold: float
    """
    pass


@staticmethod
def get_active_custom(plot):
    """ Return the active custom parameter which belongs to the custom parameters list

        Args:
            plot:

        Returns:

        """
    return plot.active_custom


def assign_variable(robot_instance, variable_name, args):
    """Assign a robotframework variable."""
    variable_value = robot_instance.run_keyword(*args)
    robot_instance._variables.__setitem__(variable_name, variable_value)
    return variable_value


def rule_move_up():
    """Move boid rule up in the list

    """
    pass


def show_del_me_code(called_by_inspect_vars=False):
    """Prints code to copy and paste into a cell to delete vars using a list of their names.
    Companion function inspect_variables(locals(),print_names=True) will provide var names tocopy/paste """
    from pprint import pprint
    if called_by_inspect_vars == False:
        print(
            '#[i]Call: `inspect_variables(locals(), print_names=True)` for list of var names'
            )
    del_me = """
    del_me= []#list of variable names
    for me in del_me:
        try:
            exec(f'del {me}')
            print(f'del {me} succeeded')
        except:
            print(f'del {me} failed')
            continue
        """
    print(del_me)


def _page(q, chunk=1000):
    """ Quick utility to page a query, 1000 items at a time.
    We need this so we don't OOM (out of memory) ourselves loading the world.
    """
    offset = 0
    while True:
        r = False
        for elem in q.limit(chunk).offset(offset):
            r = True
            yield elem
        offset += chunk
        if not r:
            break


@classmethod
def is_key_have(cls, dicts, key):
    """
        判断key 是否存在,但只能判断一个层次
        :param dicts:
        :param key:
        :return:
        """
    if key in dicts.keys():
        return True
    else:
        return False


def set_start_datetime(value):
    """Sets the start datetime to value (DateTime)"""


@classmethod
def _create_pseudo_member_(cls, value):
    """
        Create a composite member iff value contains only members.
        Contrary to Flag implementation, don't raise an error if there are extra bits.

        """
    pseudo_member = cls._value2member_map_.get(value, None)
    if pseudo_member is None:
        pseudo_member = object.__new__(cls)
        pseudo_member._name_ = None
        pseudo_member._value_ = value
        pseudo_member = cls._value2member_map_.setdefault(value, pseudo_member)
    return pseudo_member


def gen_section():
    """Create a new section.

    Markdown uses two line breaks to create a new section.

    Returns:
      string: The string with the characters for a new section.

    """
    return '\n\n'


def lookupWellKnownServices(name, timeout=None):
    """
        Perform a WKS record lookup.

        @type name: L{bytes} or L{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 plot_folium_time_value(x, y, value, name, num, **kwargs):
    """
    Visualise donnee numerique geolocalisee sur une annee
    par une jolie carte

    :param x: longitudes (vecteur)
    :param y: latitudes (vecteur)
    :param value: valeurs numeriques a representer (Dataframe ou vecteur de taille n_observations)
    :param name: noms des lieux  (vecteur)
    :param kwargs: parametres additionnels
    """
    import folium, branca
    assert type(x
        ) == list, 'Erreur : vous devez entrer une liste, pensez a utiliser list()'
    assert type(y
        ) == list, 'Erreur : vous devez entrer une liste, pensez a utiliser list()'
    assert len(x) == len(y), 'Erreur, x et y doit etre de meme taille'
    assert type(value
        ) == list, 'Erreur : vous devez entrer une liste, pensez a utiliser list()'
    assert type(name
        ) == list, 'Erreur : vous devez entrer une liste, pensez a utiliser list()'
    assert type(num
        ) == int, 'Erreur : vous devez entrer un nombre entier, pensez a utiliser int()'
    coords = 46.6299767, 1.8489683
    map = folium.Map(location=coords, tiles='OpenStreetMap', zoom_start=6)
    cm = branca.colormap.LinearColormap(['blue', 'yellow', 'red'], vmin=min
        (value), vmax=max(value))
    map.add_child(cm)
    f = folium.map.FeatureGroup()
    for lat, lng, size, color in zip(y, x, value, value):
        f.add_child(folium.CircleMarker(location=[lat, lng], radius=num *
            size, color=None, fill=True, fill_color=cm(color), fill_opacity
            =0.6))
    map.add_child(f)
    map.save(outfile='map.html')
    return map


def get_paginator(operation_name=None):
    """
    Create a paginator for an operation.

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

    :rtype: L{botocore.paginate.Paginator}
    """
    pass


@staticmethod
def _get_identifier(model):
    """Extract the identifier from a pathway mode.

        :param Pathway model: The model to convert
        :rtype: str
        """
    return model.reactome_id


@classmethod
def start_coroutine(cls, method):
    """
        Add a method to be run simultaneously along the game
        :param method: The async method that will be added to the task list
        """
    cls.tasks.append(cls.ioloop.create_task(method()))


@classmethod
def get_listening_sockets(cls):
    """Return a list of all listening sockets

        >>> host.socket.get_listening_sockets()
        ['tcp://0.0.0.0:22', 'tcp://:::22', 'unix:///run/systemd/private', ...]
        """
    sockets = []
    for sock in cls(None)._iter_sockets(True):
        if sock[0] == 'unix':
            sockets.append('unix://' + sock[1])
        else:
            sockets.append('%s://%s:%s' % (sock[0], sock[1], sock[2]))
    return sockets


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

        :param SharedLinkShareDetails val:
        :rtype: EventDetails
        """
    return cls('shared_link_share_details', val)


def select_auth_type(path, subpath, config=None):
    """Selects authentication type based on path and subpath.

    Currently are only basic and oauth supported. Peer auth is automatic if an Authorization Bearer <token> header is
    included in the http request.
    """
    if path == 'oauth':
        return 'oauth'
    if path == 'www':
        return config.www_auth
    if subpath == 'oauth':
        return 'oauth'
    return 'basic'


@classmethod
def property_mapping(cls):
    """
        A map of property name to json key name for properties that can be simply serialized to/from json
        (no objects, etc.)
        """
    raise NotImplementedError('Resource objects must define a property_mapping'
        )


def utcoffset():
    """Return the timezone offset in minutes east of UTC (negative west of
        UTC).

        If tzinfo is None, returns None, else returns
        self.tzinfo.utcoffset(None), and raises an exception if the latter
        doesn't return None or a timedelta object representing a whole number
        of minutes with magnitude less than one day.
        """


@staticmethod
def get_main_menubar():
    """
        Returns Qt object that references to the main DCC menubar
        :return:
        """
    return None


def get_num_label_vols(md):
    """
    Get the number of volumes used for labelling - e.g. 2 for tag-control pair data
    """
    iaf = md.get('iaf', 'tc')
    if iaf in ('tc', 'ct'):
        return 2
    elif iaf == 'diff':
        return 1
    elif iaf == 'mp':
        return md.get('nphases', 8)
    elif iaf == 've':
        return md.get('nenc', 8)


def configure(conf):
    """
	Detects the *bison* program
	"""
    conf.find_program('bison', var='BISON')
    conf.env.BISONFLAGS = ['-d']


def tag_sibling_ordinal(tag):
    """
    Given a beautiful soup tag, count the same tags in its siblings
    to get a sibling "local" ordinal value. This is useful in counting
    child figures within a fig-group, for example
    """
    tag_count = 0
    return len(tag.find_previous_siblings(tag.name)) + 1


def extract_pos(positions, cash):
    """Extract position values from backtest object as returned by
    get_backtest() on the Quantopian research platform.

    Parameters
    ----------
    positions : pd.DataFrame
        timeseries containing one row per symbol (and potentially
        duplicate datetime indices) and columns for amount and
        last_sale_price.
    cash : pd.Series
        timeseries containing cash in the portfolio.

    Returns
    -------
    pd.DataFrame
        Daily net position values.
         - See full explanation in tears.create_full_tear_sheet.
    """
    positions = positions.copy()
    positions['values'] = positions.amount * positions.last_sale_price
    cash.name = 'cash'
    values = positions.reset_index().pivot_table(index='index', columns=
        'sid', values='values')
    values = values.join(cash).fillna(0)
    return values


def find_all_overlapping(string, occurrence):
    """Find all overlapping occurrences.

    :param string: String to be searched.
    :type string: string

    :param occurrence: Occurrence to search.
    :type occurrence: string

    :return: generator yielding *positions of occurence*
    :rtype: generator of int

    """
    found = 0
    while True:
        found = string.find(occurrence, found)
        if found != -1:
            yield found
        else:
            return
        found += 1


def MIKEarc2cst(file, output):
    """
    Read in a set of MIKE arc files and export to CST format compatible with
    SMS.

    MIKE format is:

        x, y, position, z(?), ID

    where position is 1 = along arc and 0 = end of arc.

    In the CST format, the depth is typically zero, but we'll read it from the
    MIKE z value and add it to the output file nevertheless. For the
    conversion, we don't need the ID, so we can ignore that.

    Parameters
    ----------
    file : str
        Full path to the DHI MIKE21 arc files.
    output : str
        Full path to the output file.

    """
    with open(file, 'r') as file_in:
        lines = file_in.readlines()
    with open(output, 'w') as file_out:
        file_out.write('COAST\n')
        num_arcs = 0
        for line in lines:
            x, y, pos, z, arc_id = line.strip().split(' ')
            if int(pos) == 0:
                num_arcs += 1
        file_out.write('{}\n'.format(int(num_arcs)))
        arc = []
        n = 1
        for line in lines:
            x, y, pos, z, arc_id = line.strip().split(' ')
            if int(pos) == 1:
                arc.append([x, y])
                n += 1
            elif int(pos) == 0:
                arc.append([x, y])
                file_out.write('{}\t{}\n'.format(int(n), float(z)))
                for arc_position in arc:
                    file_out.write('\t{}\t{}\t{}\n'.format(float(
                        arc_position[0]), float(arc_position[1]), float(z)))
                n = 1
                arc = []


def author_structure(user):
    """
    An author structure.
    """
    return {'user_id': user.pk, 'user_login': user.get_username(),
        'display_name': user.__str__(), 'user_email': user.email}


def format_for_single_line_log(text: str) ->str:
    """
    Formats a text for log
    :param text:
    :return:
    """
    text = '' if text is None else text
    return ' '.join(text.split())


def aliases(mlist):
    """Generate all the aliases for the mailing list.

        This method is a generator.  The posting address will be returned
        first, followed by the rest of the aliases in alphabetical order.

        :param mlist: The mailing list.
        :type mlist: An `IMailingList` or an object with `list_name`,
            `mail_host`, and `posting_address` attributes.
        :return: The set of fully qualified common aliases for the mailing
            list.
        :rtype: string
        """


def get_summary(result):
    """ get summary from test result
    """
    summary = {'success': result.wasSuccessful(), 'stat': {'testsRun':
        result.testsRun, 'failures': len(result.failures), 'errors': len(
        result.errors), 'skipped': len(result.skipped), 'expectedFailures':
        len(result.expectedFailures), 'unexpectedSuccesses': len(result.
        unexpectedSuccesses)}}
    summary['stat']['successes'] = summary['stat']['testsRun'] - summary['stat'
        ]['failures'] - summary['stat']['errors'] - summary['stat']['skipped'
        ] - summary['stat']['expectedFailures'] - summary['stat'][
        'unexpectedSuccesses']
    if getattr(result, 'records', None):
        summary['time'] = {'start_at': result.start_at, 'duration': result.
            duration}
        summary['records'] = result.records
    else:
        summary['records'] = []
    return summary


@staticmethod
def compose_word(key, value):
    """
        Create a attribute word from key, value pair.
        Values are casted to api equivalents.
        """
    return '={0}={1}'.format(key, value)


def query(object, default=None):
    """Query the value of the field for the given object.

        Return the default if the value hasn't been set.
        """


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


@staticmethod
def _clean_name(name):
    """
        Returns lowercase version of a string, with spaces replaced with underscores
        :param name: string to clean
        :return: cleaned version of string
        """
    return name.lower().replace(' ', '_')


@classmethod
def get_table(cls, name):
    """Return the boto3 Table object for this model, create it if it doesn't exist

        The Table is stored on the class for each model, so it is shared between all instances of a given model.
        """
    if cls._table is None:
        cls._table = cls.get_resource().Table(name)
    return cls._table


def listSubtopics():
    """Return a list of our subtopics.
        """


def set_default_app(app):
    """Set default app."""
    global default_app
    default_app = app


def handle_config(args, configs):
    """Handle `view` subcommand

    :param args: parsed arguments
    :type args: :py:class:`argparse.Namespace`
    :param configs: configurations object
    :type configs: :py:class:`sfftk.core.configs.Configs`
    :return exit_status: exit status
    :rtype exit_status: int
    """
    if args.config_subcommand == 'get':
        from .core.configs import get_configs
        return get_configs(args, configs)
    elif args.config_subcommand == 'set':
        from .core.configs import set_configs
        return set_configs(args, configs)
    elif args.config_subcommand == 'del':
        from .core.configs import del_configs
        return del_configs(args, configs)


def extract_full_artifact_map_path(artifact_map, basepath, locale):
    """Find the artifact map entry from the given path."""
    for entry in artifact_map:
        if entry['locale'] != locale:
            continue
        for path in entry['paths']:
            if path.endswith(basepath):
                return path


def validateMoveValue(channel_value):
    """
    Determine if the channel value is valid or not
    :param channel_value:
    :return:
    """
    if channel_value < 0:
        return False
    elif channel_value > 30:
        return False
    return True


def _render_condition_value(value, field_type):
    """Render a query condition value.

    Parameters
    ----------
    value : Union[bool, int, float, str, datetime]
        The value of the condition
    field_type : str
        The data type of the field

    Returns
    -------
    str
        A value string.
    """
    if field_type == 'BOOLEAN':
        value = 1 if value else 0
    elif field_type in ('STRING', 'INTEGER', 'FLOAT'):
        value = "'%s'" % value
    elif field_type in 'TIMESTAMP':
        value = "'%s'" % str(value)
    return '%s(%s)' % (field_type, value)


def describe_events(filter=None, nextToken=None, maxResults=None, locale=None):
    """
    Returns information about events that meet the specified filter criteria. Events are returned in a summary form and do not include the detailed description, any additional metadata that depends on the event type, or any affected resources. To retrieve that information, use the  DescribeEventDetails and  DescribeAffectedEntities operations.
    If no filter criteria are specified, all events are returned. Results are sorted by lastModifiedTime , starting with the most recent.
    See also: AWS API Documentation

    :example: response = client.describe_events(
        filter={
            'eventArns': [
                'string',
            ],
            'eventTypeCodes': [
                'string',
            ],
            'services': [
                'string',
            ],
            'regions': [
                'string',
            ],
            'availabilityZones': [
                'string',
            ],
            'startTimes': [
                {
                    'from': datetime(2015, 1, 1),
                    'to': datetime(2015, 1, 1)
                },
            ],
            'endTimes': [
                {
                    'from': datetime(2015, 1, 1),
                    'to': datetime(2015, 1, 1)
                },
            ],
            'lastUpdatedTimes': [
                {
                    'from': datetime(2015, 1, 1),
                    'to': datetime(2015, 1, 1)
                },
            ],
            'entityArns': [
                'string',
            ],
            'entityValues': [
                'string',
            ],
            'eventTypeCategories': [
                'issue'|'accountNotification'|'scheduledChange',
            ],
            'tags': [
                {
                    'string': 'string'
                },
            ],
            'eventStatusCodes': [
                'open'|'closed'|'upcoming',
            ]
        },
        nextToken='string',
        maxResults=123,
        locale='string'
    )

    :type filter: dict
    :param filter: Values to narrow the results returned.
            eventArns (list) --A list of event ARNs (unique identifiers). For example: 'arn:aws:health:us-east-1::event/AWS_EC2_MAINTENANCE_5331', 'arn:aws:health:us-west-1::event/AWS_EBS_LOST_VOLUME_xyz'
            (string) --
            eventTypeCodes (list) --A list of unique identifiers for event types. For example, 'AWS_EC2_SYSTEM_MAINTENANCE_EVENT','AWS_RDS_MAINTENANCE_SCHEDULED'
            (string) --
            services (list) --The AWS services associated with the event. For example, EC2 , RDS .
            (string) --
            regions (list) --A list of AWS regions.
            (string) --
            availabilityZones (list) --A list of AWS availability zones.
            (string) --
            startTimes (list) --A list of dates and times that the event began.
            (dict) --A range of dates and times that is used by the EventFilter and EntityFilter objects. If from is set and to is set: match items where the timestamp (startTime , endTime , or lastUpdatedTime ) is between from and to inclusive. If from is set and to is not set: match items where the timestamp value is equal to or after from . If from is not set and to is set: match items where the timestamp value is equal to or before to .
            from (datetime) --The starting date and time of a time range.
            to (datetime) --The ending date and time of a time range.

            endTimes (list) --A list of dates and times that the event ended.
            (dict) --A range of dates and times that is used by the EventFilter and EntityFilter objects. If from is set and to is set: match items where the timestamp (startTime , endTime , or lastUpdatedTime ) is between from and to inclusive. If from is set and to is not set: match items where the timestamp value is equal to or after from . If from is not set and to is set: match items where the timestamp value is equal to or before to .
            from (datetime) --The starting date and time of a time range.
            to (datetime) --The ending date and time of a time range.

            lastUpdatedTimes (list) --A list of dates and times that the event was last updated.
            (dict) --A range of dates and times that is used by the EventFilter and EntityFilter objects. If from is set and to is set: match items where the timestamp (startTime , endTime , or lastUpdatedTime ) is between from and to inclusive. If from is set and to is not set: match items where the timestamp value is equal to or after from . If from is not set and to is set: match items where the timestamp value is equal to or before to .
            from (datetime) --The starting date and time of a time range.
            to (datetime) --The ending date and time of a time range.

            entityArns (list) --A list of entity ARNs (unique identifiers).
            (string) --
            entityValues (list) --A list of entity identifiers, such as EC2 instance IDs (i-34ab692e ) or EBS volumes (vol-426ab23e ).
            (string) --
            eventTypeCategories (list) --A list of event type category codes (issue , scheduledChange , or accountNotification ).
            (string) --
            tags (list) --A map of entity tags attached to the affected entity.
            (dict) --
            (string) --
            (string) --

            eventStatusCodes (list) --A list of event status codes.
            (string) --

    :type nextToken: string
    :param nextToken: If the results of a search are large, only a portion of the results are returned, and a nextToken pagination token is returned in the response. To retrieve the next batch of results, reissue the search request and include the returned token. When all results have been returned, the response does not contain a pagination token value.

    :type maxResults: integer
    :param maxResults: The maximum number of items to return in one batch, between 10 and 100, inclusive.

    :type locale: string
    :param locale: The locale (language) to return information in. English (en) is the default and the only supported value at this time.

    :rtype: dict
    :return: {
        'events': [
            {
                'arn': 'string',
                'service': 'string',
                'eventTypeCode': 'string',
                'eventTypeCategory': 'issue'|'accountNotification'|'scheduledChange',
                'region': 'string',
                'availabilityZone': 'string',
                'startTime': datetime(2015, 1, 1),
                'endTime': datetime(2015, 1, 1),
                'lastUpdatedTime': datetime(2015, 1, 1),
                'statusCode': 'open'|'closed'|'upcoming'
            },
        ],
        'nextToken': 'string'
    }

    """
    pass


def scan_setup_py():
    """Validate the contents of setup.py against Versioneer's expectations."""
    found = set()
    setters = False
    errors = 0
    with open('setup.py', 'r') as f:
        for line in f.readlines():
            if 'import versioneer' in line:
                found.add('import')
            if 'versioneer.get_cmdclass()' in line:
                found.add('cmdclass')
            if 'versioneer.get_version()' in line:
                found.add('get_version')
            if 'versioneer.VCS' in line:
                setters = True
            if 'versioneer.versionfile_source' in line:
                setters = True
    if len(found) != 3:
        print('')
        print('Your setup.py appears to be missing some important items')
        print('(but I might be wrong). Please make sure it has something')
        print('roughly like the following:')
        print('')
        print(' import versioneer')
        print(' setup( version=versioneer.get_version(),')
        print('        cmdclass=versioneer.get_cmdclass(),  ...)')
        print('')
        errors += 1
    if setters:
        print("You should remove lines like 'versioneer.VCS = ' and")
        print("'versioneer.versionfile_source = ' . This configuration")
        print('now lives in setup.cfg, and should be removed from setup.py')
        print('')
        errors += 1
    return errors


@classmethod
def set_celery_app(cls, celery_app):
    """Set celery application that should be used.

        :param celery_app: celery app instance
        """
    from .dispatcher import Dispatcher
    from .task_envelope import SelinonTaskEnvelope
    cls._logger.debug('Registering Selinon to Celery context')
    cls.celery_app = celery_app
    celery_app.tasks.register(Dispatcher())
    celery_app.tasks.register(SelinonTaskEnvelope())


def subkeys(original, key):
    """
    Takes a list of dot-hierarchical values and keeps only matching subkeys.

    Example:

    >>> subkeys(['one.two', 'one.three', 'four'], 'one')
    ['two', 'three']
    """
    new_keys = filter(lambda s: s.startswith(key + '.'), original)
    new_keys = list(map(lambda s: s[len(key) + 1:], new_keys))
    return new_keys