def get_byte_array(integer):
    """Return the variable length bytes corresponding to the given int"""
    return int.to_bytes(integer, (integer.bit_length() + 8 - 1) // 8,
        byteorder='big', signed=False)


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

        :param MemberSpaceLimitsAddCustomQuotaDetails val:
        :rtype: EventDetails
        """
    return cls('member_space_limits_add_custom_quota_details', val)


def next_batch(mgr, batch_size, qname='input'):
    """*DEPRECATED*. Use TFNode.DataFeed class instead."""
    raise Exception('DEPRECATED: Use TFNode.DataFeed class instead')


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


def _set_dyn_play_at_home(params, name: str, index: int, value: float):
    """Adjust the Parameters.dyn_play_at_home parameter"""
    if index is not None:
        raise IndexError('You cannot index the dyn_play_at_home parameter')
    params.dyn_play_at_home = value


def prettify_alignment(aln):
    """
    Converts all bases to uppercase and removes auto reverse-complement prefix (_R_).
    This modifies the alignment in place.

    Parameters
    ----------
    aln : MultipleSeqAlign
        Biopython Alignment
    """
    for seq in aln:
        seq.seq = seq.seq.upper()
        if seq.id.startswith('_R_'):
            seq.id = seq.id[3:]
            print(
                'Sequence "{}" was reverse-complemented by the alignment program.'
                .format(seq.id))
        if seq.name.startswith('_R_'):
            seq.name = seq.name[3:]
        if seq.description.startswith('_R_'):
            seq.description = seq.description[3:]


def get_bases_at_site(alignment_obj, chromosome, position):
    """

    So to convert INS from 0 to 1-based system:
    start = start + 1; end = end + 1
    and to convert INS from 1 to 0-based system:
    start = start - 1; end = end - 1

    :param alignment_obj:
    :param chromosome:
    :param position:
    :return:
    """
    position = int(position)
    read_list = alignment_obj.pileup(chromosome, position, position + 1)
    base_list = []
    for pileupcolumn in read_list:
        if pileupcolumn.pos == position:
            for pileupread in pileupcolumn.pileups:
                if not pileupread.is_del and not pileupread.is_refskip:
                    base_list.append(pileupread.alignment.query_sequence[
                        pileupread.query_position])
    return base_list


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


@classmethod
def get(cls, name, context=None):
    """Return Variable instance of name.

        `name`
            Variable name string.
        `context`
            Optional variable context.
        """
    name = str(name)
    context = cls._get_context(context)
    return cls(name, context.get(name), context)


@classmethod
def green(cls):
    """A factory method that returns a :class:`Colour` with a value of ``0x2ecc71``."""
    return cls(3066993)


def dict2tuples(d):
    """helper to split comp names"""
    tuples = []
    for key in d:
        tuples += list(zip(['_'.join(key.split())] * len(d[key]), d[key]))
    return tuples


def _egi_find_edge_face(u, v, egi):
    """ same as duality.algorithms.find_edge_faces... using 'sorted_nbrs' instead
    """
    cycle = [u]
    while True:
        cycle.append(v)
        nbrs = egi.vertex[v]['sorted_nbrs']
        nbr = nbrs[nbrs.index(u) - 1]
        u, v = v, nbr
        if v == cycle[0]:
            cycle.append(v)
            break
    return cycle


def create_qtr_list(time_range):
    """
    From a given time_range, create the list of qtr contained in it. Includes both qtr in the time_range. time_range
    is of the form [(year, QTR), (year, QTR)].

    :param time_range: a list of two tuples representing the start and finish qtr
    :return: a list of all the qtr included in the time_range.
    """
    assert len(time_range) == 2
    assert 1994 <= time_range[0][0] and 1994 <= time_range[1][0]
    assert 1 <= time_range[0][1] <= 4 and 1 <= time_range[1][1] <= 4
    assert time_range[1][0] >= time_range[0][0]
    if time_range[1][0] == time_range[0][0]:
        assert time_range[1][1] >= time_range[0][1]
    list_qtr = []
    for year in range(time_range[0][0], time_range[1][0] + 1):
        for qtr in range(1, 5):
            if year == time_range[0][0]:
                if qtr < time_range[0][1]:
                    continue
            if year == time_range[1][0]:
                if qtr > time_range[1][1]:
                    break
            list_qtr.append((year, qtr))
    assert list_qtr[0] == time_range[0]
    assert list_qtr[-1] == time_range[1]
    return list_qtr


@classmethod
def key_list(cls):
    """ returns a list of all enum members that are omitted from the .json file if all of their array's values are 0
        """
    return [cls.E, cls.G1, cls.G2, cls.G3, cls.G4]


@staticmethod
def _subscribe(sub_id, channel, callback, **kwargs):
    """Listen to a queue, notify via callback function.
        :param sub_id: ID for this subscription in the transport layer
        :param channel: Queue name to subscribe to
        :param callback: Function to be called when messages are received
        :param **kwargs: Further parameters for the transport layer. For example
               exclusive: Attempt to become exclusive subscriber to the queue.
               acknowledgement: If true receipt of each message needs to be
                                acknowledged.
        """
    raise NotImplementedError('Transport interface not implemented')


def quadrant(coord, liste_coord):
    """Évite 2 points dans le même quadrant"""
    rep = True
    for c in liste_coord:
        if coord[0] * c[0] >= 0 and coord[1] * c[1] >= 0:
            rep = False
            break
    return rep


def _gcd(a, b):
    """Computes the greatest common divisor of two numbers using Euclid's Algorithm.

    Example:
        >>> _gcd(30, 18)
        6

    Args:
        a (int): The first parameter.
        b (int): The second parameter.

    Returns:
        int: The greatest common divisor of a and b.

    """
    while b:
        a, b = b, a % b
    return a


def get_device_mac(run_command_fn, dev_name, netns_name=None):
    """Find device MAC address"""
    if netns_name:
        command_prefix = 'ip netns exec %s ' % netns_name
    else:
        command_prefix = ''
    output, _ = run_command_fn('%scat /sys/class/net/%s/address' % (
        command_prefix, dev_name))
    return output[0]


def _escape_regexp(s):
    """Escape characters with specific regexp use"""
    return str(s).replace('|', '\\|').replace('.', '\\.').replace('*', '.*'
        ).replace('+', '\\+').replace('(', '\\(').replace(')', '\\)').replace(
        '$', '\\$')


def prtOptions():
    """Print a list of command-line options and arguments."""
    print('The command-line arguments and options are:')
    print('  -q (quiet)')
    print('  -v (very verbose)')
    print('  -u (update keywords in input corrtag files)')
    print('  -o outdir (output directory name)')
    print('  --find yes (find Y location of spectrum)')
    print('  --find no (use Y location of spectrum from 1dx file and wavecal)')
    print('  --find cutoff (find Y location if sigma <= cutoff)')
    print('  --location Y location(s) at which to extract spectra')
    print('  --extrsize height(s) of extraction region(s)')
    print('  one or more corrtag file names')


def get_json_logging():
    """
        get_json_logging

        Return True if JSON logging mode is enabled, False otherwise.

        @return: boolean
        """


def dedup(l, suffix='__'):
    """De-duplicates a list of string by suffixing a counter

    Always returns the same number of entries as provided, and always returns
    unique values.

    >>> print(','.join(dedup(['foo', 'bar', 'bar', 'bar'])))
    foo,bar,bar__1,bar__2
    """
    new_l = []
    seen = {}
    for s in l:
        if s in seen:
            seen[s] += 1
            s += suffix + str(seen[s])
        else:
            seen[s] = 0
        new_l.append(s)
    return new_l


@classmethod
def _autodoc(cls, func):
    """getinput : list or callable
            If it is a list, it corresponds to a list of user inputs that is
            read sequentially. If it is a callable, it must be a function that
            asks for user input when called with no arguments.
        printline : callable
            Prints data to user. The default implementation simply writes data
            directly to `sys.stdout`.
        error : callable
            Function that prints error messages to the user. The default
            implementation simply calls the printline function supplied by the
            callee.

        Examples"""
    doc = getattr(cls, func.__name__).__doc__
    head, _, tail = doc.partition('Examples')
    if 'Parameters' in head:
        doc = head + cls._autodoc.__doc__ + tail
    func.__doc__ = doc
    return func


def group_kinetic_energy(kin_molec, nmolecs, molec_group=None):
    """
    Sums up the partitioned kinetic energy for a
    given group or the entire system.

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

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


def weight_paint_toggle():
    """Toggle weight paint mode in 3D view

    """
    pass


def mean(qualities):
    """Calculates the average of a list which might be empty.

    Parameters
    ----------
    qualtiies : list
        list of numbers

    Returns
    -------
    float
        Float representing the mean numbers in the the list; zero if the list is empty.
    """
    if len(qualities) == 0:
        return 0
    de_phred = []
    for x in qualities:
        de_phred.append(100 - 100 * 10 ** (-1.0 * x / 10.0))
    return sum(de_phred) / float(len(de_phred))


def default_parents_inspection(element, parent):
    """
    Check if the element has the specified parent
    :param element: the element to check
    :param parent: the expected parent
    :return: the check result
    """
    return parent in element.mro()


def __check_args_type(args):
    """Check if it is a tuple-like object."""
    if args is None or args == ():
        return None
    elif isinstance(args, int) or isinstance(args, str) or isinstance(args,
        list):
        return args,
    elif not isinstance(args, tuple):
        raise TypeError(
            'Second item of the tuple (func, args, cols) must be tuple-like object not a {} object'
            .format(type(args)))
    else:
        return args


def remove_pipes(pipes, pipes_selection):
    """
    Remove the selected pipes (*pipes_selection*) from the dataframe *pipes* ;
    in-place

    Parameters
    ----------
    pipes: DataFrame
        Dataframe of the TST pipes.
    pipes_selection:
        Dataframe of the selected pipes (same load as the first pipe).
    """
    pipes.drop(index=pipes_selection.index, inplace=True)
    pipes.reset_index(inplace=True, drop=True)


def channels_select_box(xmin: int=0, xmax: int=0, ymin: int=0, ymax: int=0,
    wait_for_input: bool=True, deselect: bool=False, extend: bool=True):
    """Select all animation channels within the specified region

    :param xmin: X Min
    :type xmin: int
    :param xmax: X Max
    :type xmax: int
    :param ymin: Y Min
    :type ymin: int
    :param ymax: Y Max
    :type ymax: int
    :param wait_for_input: Wait for Input
    :type wait_for_input: bool
    :param deselect: Deselect, Deselect rather than select items
    :type deselect: bool
    :param extend: Extend, Extend selection instead of deselecting everything first
    :type extend: bool
    """
    pass


def atomic_number(atom):
    """Get the atomic number for an atom.

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

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


def writefile(name, instream, start=None, end=None, append=False):
    """Write data to a file.

        If start or end is not None, then only part of the file is
        written. The remainder of the file is unchanged.
        If start or end are specified, they must ne non-negative.

        If end is None, then the file is truncated after the data are
        written.  If end is not None, parts of the file after end, if
        any, are unchanged.  If end is not None and there isn't enough
        data in instream to fill out the file, then the missing data
        are undefined.

        If neither start nor end are specified, then the file contents
        are overwritten.

        If start is specified and the file doesn't exist or is shorter
        than start, the file will contain undefined data before start.

        If append is true, start and end are ignored.
        """


def _check_missing_inputs(dataset, model):
    """Check if all model inputs have their corresponding variables
    in the input Dataset.
    """
    missing_xr_vars = []
    for p_name, var_name in model.input_vars:
        xr_var_name = p_name + '__' + var_name
        if xr_var_name not in dataset:
            missing_xr_vars.append(xr_var_name)
    if missing_xr_vars:
        raise KeyError(f'Missing variables {missing_xr_vars} in Dataset')


def shorten(s, l):
    """Return given string truncated to given length."""
    if len(s) > l:
        return s[:l - 2] + '..'
    return s


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 __iter__():
    """See `get_members()`."""


def get_instances(cls):
    """Return all instances from Model class"""
    for inst_ref in cls.__refs__:
        inst = inst_ref()
        if inst is not None:
            yield inst


def movePluginsTop(plugin_type, ids_to_move):
    """ Move a set of plugins to the "top" in their list.

        o 'plugin_type' must be one of the known types, else raise KeyError.

        o 'ids_to_move' must be a sequence of ids of current plugins
          for that type.

          - If any item is not the ID of a current plugin, raise ValueError.
          - Moving one plugin to top has obvious result;
            moving more than one plugin to top puts them one by one at the top
            iow, last in the list gets to top
        """


def backward_elimination(variables, train_model, score_model, verbose=False):
    """ Variable selection using backward elimination

    Input:
        variables: complete list of variables to consider in model building
        train_model: function that returns a fitted model for a given set of variables
        score_model: function that returns the score of a model; better models have lower scores

    Returns:
        (best_model, best_variables)
    """
    best_variables = list(variables)
    best_model = train_model(best_variables)
    best_score = score_model(best_model, best_variables)
    if verbose:
        print('Variables: ' + ', '.join(variables))
        print('Start: score={:.2f}'.format(best_score))
    while len(best_variables) > 1:
        step = [(best_score, None, best_model)]
        for removeVar in best_variables:
            step_var = list(best_variables)
            step_var.remove(removeVar)
            step_model = train_model(step_var)
            step_score = score_model(step_model, step_var)
            step.append((step_score, removeVar, step_model))
        step.sort(key=lambda x: x[0])
        best_score, removed_step, best_model = step[0]
        if verbose:
            print('Step: score={:.2f}, remove {}'.format(best_score,
                removed_step))
        if removed_step is None:
            break
        best_variables.remove(removed_step)
    return best_model, best_variables


def manage_copyObjects(ids=None, REQUEST=None, RESPONSE=None):
    """Put a reference to the objects named in ids in the clip board"""


def rgb2html(colour):
    """
    Transforms a RGB triplet into an html hex string.

    :param `colour`: a tuple of red, green, blue integers.
    """
    hexColour = '#%02x%02x%02x' % (colour.r, colour.g, colour.b)
    return hexColour.upper()


@classmethod
def is_valid(cls, value):
    """Check whether a value is one of the pre-defined colours.

        Args:
            value (str): the name of the colour.

        Returns:
            True if the value equals one of the constants, False otherwise.

        """
    return value in cls._values


def empty_ndarray(arr, method):
    """
    Check if *arr* is a not empty np.ndarray.
    """
    if arr.size == 0:
        raise RuntimeError('\n\nRun method {} first\n'.format(method))


def rhosat(phi, sw, rhomin, rhow, rhohc):
    """
    Density of partially saturated rock.

    """
    a = rhomin * (1 - phi)
    b = rhow * sw * phi
    c = rhohc * (1 - sw) * phi
    return a + b + c


def describe_import_image_tasks(DryRun=None, ImportTaskIds=None, NextToken=
    None, MaxResults=None, Filters=None):
    """
    Displays details about an import virtual machine or import snapshot tasks that are already created.
    See also: AWS API Documentation

    :example: response = client.describe_import_image_tasks(
        DryRun=True|False,
        ImportTaskIds=[
            'string',
        ],
        NextToken='string',
        MaxResults=123,
        Filters=[
            {
                'Name': 'string',
                'Values': [
                    'string',
                ]
            },
        ]
    )

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

    :type ImportTaskIds: list
    :param ImportTaskIds: A list of import image task IDs.
            (string) --

    :type NextToken: string
    :param NextToken: A token that indicates the next page of results.

    :type MaxResults: integer
    :param MaxResults: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.

    :type Filters: list
    :param Filters: Filter tasks using the task-state filter and one of the following values: active, completed, deleting, deleted.
            (dict) --A filter name and value pair that is used to return a more specific list of results. Filters can be used to match a set of resources by various criteria, such as tags, attributes, or IDs.
            Name (string) --The name of the filter. Filter names are case-sensitive.
            Values (list) --One or more filter values. Filter values are case-sensitive.
            (string) --

    :rtype: dict
    :return: {
        'ImportImageTasks': [
            {
                'ImportTaskId': 'string',
                'Architecture': 'string',
                'LicenseType': 'string',
                'Platform': 'string',
                'Hypervisor': 'string',
                'Description': 'string',
                'SnapshotDetails': [
                    {
                        'DiskImageSize': 123.0,
                        'Description': 'string',
                        'Format': 'string',
                        'Url': 'string',
                        'UserBucket': {
                            'S3Bucket': 'string',
                            'S3Key': 'string'
                        },
                        'DeviceName': 'string',
                        'SnapshotId': 'string',
                        'Progress': 'string',
                        'StatusMessage': 'string',
                        'Status': 'string'
                    },
                ],
                'ImageId': 'string',
                'Progress': 'string',
                'StatusMessage': 'string',
                'Status': 'string'
            },
        ],
        'NextToken': 'string'
    }

    """
    pass


def get_keywords():
    """Get the keywords needed to look up the version information."""
    git_refnames = '$Format:%d$'
    git_full = '$Format:%H$'
    git_date = '$Format:%ci$'
    keywords = {'refnames': git_refnames, 'full': git_full, 'date': git_date}
    return keywords


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

        :param SharedContentClaimInvitationType val:
        :rtype: EventType
        """
    return cls('shared_content_claim_invitation', val)


def _check(isamAppliance, username):
    """
    TODO: Code the idempotency check logic
    """
    return False


def symbol_from_number(number, symbol):
    """
    Returns the H-M symbol for a given international group number
    """
    pass


@classmethod
def validate_required_configuration(cls):
    """ Validate that all required configuration has been provided

        :rtype: bool: False if any expected configuration parameter was not provided

        """
    valid = True
    for key in cls.required_configuration:
        if getattr(cls, key) is None:
            print(key)
            valid = False
    return valid


def verify_options(value, options):
    """Check if value is within the options."""
    if value in options:
        return value
    return None


def print2(summary, string):
    """ Show the message on the console and also save in summary. """
    print(string)
    summary.append(string)


def avg_class_statistics(total, component, number_of_evaluations):
    """Adds a new set of per class evaluation measures to the total average

    """
    special_keys = ['class_name', 'present_in_test_data', 'occurrences']
    remove_keys = ['ks_statistic', 'max_phi',
        'per_threshold_confusion_matrices', 'roc_curve', 'pr_curve',
        'negative_cdf', 'max_phi', 'lift_curve', 'ks_statistic', 'gain_curve']
    for class_info in component:
        for key in remove_keys:
            if key in class_info:
                del class_info[key]
        class_name = class_info['class_name']
        found = False
        for total_class_info in total:
            if class_name == total_class_info['class_name']:
                found = True
                flag = class_info['present_in_test_data']
                if not flag:
                    total_class_info['occurrences'] -= 1
                    occurrences = float(total_class_info['occurrences'])
                    for key in total_class_info:
                        try:
                            if not (isinstance(key, tuple) or key in
                                special_keys):
                                total_class_info[key] *= (occurrences + 1
                                    ) / occurrences
                        except (ValueError, TypeError):
                            pass
                if not total_class_info['present_in_test_data']:
                    total_class_info['present_in_test_data'] = flag
                occurrences = float(total_class_info['occurrences'])
                for key in class_info:
                    try:
                        if not (isinstance(key, tuple) or key in special_keys):
                            new_key = key if key.startswith('average_'
                                ) else 'average_%s' % key
                            if new_key in total_class_info:
                                total_class_info[new_key] += class_info[key
                                    ] / occurrences
                            else:
                                total_class_info[new_key] = class_info[key
                                    ] / occurrences
                            sd_key = '%s_standard_deviation' % key
                            if not (sd_key, new_key) in total_class_info:
                                total_class_info[sd_key, new_key] = []
                            total_class_info[sd_key, new_key].append(class_info
                                [key])
                    except (ValueError, TypeError):
                        pass
                break
        if not found:
            flag = class_info['present_in_test_data']
            class_info['occurrences'] = int(number_of_evaluations)
            if not flag:
                class_info['occurrences'] -= 1
            keys = class_info.keys()
            for key in keys:
                try:
                    if not key in special_keys:
                        sd_key = '%s_standard_deviation' % key
                        if not key.startswith('average_'):
                            new_key = 'average_%s' % key
                            class_info[new_key] = float(class_info[key]
                                ) / class_info['occurrences']
                            if not (sd_key, new_key) in class_info:
                                class_info[sd_key, new_key] = []
                            class_info[sd_key, new_key].append(class_info[key])
                            del class_info[key]
                        else:
                            new_key = key
                            class_info[key] = float(class_info[key]
                                ) / class_info['occurrences']
                            if not (sd_key, new_key) in class_info:
                                class_info[sd_key, new_key] = []
                            class_info[sd_key, new_key].append(class_info[key])
                except (ValueError, TypeError):
                    pass
            total.append(class_info)
    return total


@classmethod
def get_reader(cls, informat):
    """Get a reader based on reader name"""
    return cls.formats[informat]['class']


def normalize(resources_by_categories, largest_epoch):
    """
    Organize all timeseries by the serie with the longest duration
    """
    for resource_axis in resources_by_categories.values():
        number_of_missing_values = largest_epoch - len(resource_axis[0])
        if not number_of_missing_values:
            continue
        resource_axis[0].extend(list(range(largest_epoch -
            number_of_missing_values, largest_epoch)))
        resource_axis[1].extend([resource_axis[1][-1]] *
            number_of_missing_values)


def userid_for(key):
    """
        Given key as login name or a user object, return
        the internal user id for that user.
        """


@staticmethod
def get_subtype(object_dictionary):
    """
        Given the hash representation of a subtype of this class,
        use the info in the hash to return the class of the subtype.
        """
    type = object_dictionary['actionType']
    if type == 'OSS':
        return 'CreateStreamingServiceActionDetails'
    if type == 'FAAS':
        return 'CreateFaaSActionDetails'
    if type == 'ONS':
        return 'CreateNotificationServiceActionDetails'
    else:
        return 'ActionDetails'


def makeopendir(fs, directory):
    """ Creates and opens the given directory in the given PyFilesystem. """
    if not fs.isdir(directory):
        fs.makedir(directory)
    return fs.opendir(directory)


def create_ssd_filename(band, eclipse):
    """
    Returns the Stim Separation Data (SSD) calibration file name.

    :param band: The band to create the SSD for, either 'FUV' or 'NUV'.

    :type band: str

    :param eclipse: The eclipse number to create the SSD file for.

    :type eclipse: int

    :returns: str -- The name of the SSD file to create.
    """
    return 'SSD_' + band.lower() + '_' + str(eclipse) + '.tbl'


def pipe(data, *functions):
    """pipe data trough a pipeline of functions.

    Think of unix pipes or elixir's pipes.
    ``pipe`` assumes that data is the first argument of a function.

    ``pipe`` tries to be smart and automatically cerates partial functions if
    you pass a tuple instead of a callable:

    - ``pipe(data, (pow, 2, 5))`` --> ``pow(data, 2, 5)``.

    - ``pipe(data, (sorted, {"reverse": True}))`` -->
      ``sorted(data, reverse=True)``

    Args:
        data (whatever): the data that is passed into the first function.
        functions (callables): functions that create the pipeline.

    Returns:
        The result of your pipeline.

    Examples:
        ``pipe`` allows you to turn something which is hard to read:

        >>> from math import ceil, sqrt
        >>> sqrt(pow(int(ceil(float("2.1"))), 2))
        3.0

        into something that is easy to read:

        >>> pipe("2.1", float, ceil, int, lambda x: x*x, sqrt)
        3.0

        Genrate your own partial functions with lambda

        >>> pipe("2.1", float, ceil, int, lambda x: pow(x, 2), sqrt)
        3.0

        But there is a shortcut: tuples are interpreted as as
        ``(functions, arguments, ...)``.
        The data passed from the previous function is the first argument of the
        punction, followed by the arguments from the tuple.

        >>> pipe("2.1", float, ceil, int, (pow, 2), sqrt)
        3.0

        To make this clearer ``pipe(3, (pow, 2))`` is equivalent to
        ``pow(3, 2)``.
        Of course you can pass multiple arguments with the tuple:

        >>> pipe(3, (pow, 2, 8))  # pow(2, 3, 8) -> pow(2, 3) % 8
        1

        It can be convenient to use the following notation if the function
        names are longer:

        >>> text = "atababsatsatsastatbadstssdhhhnbb"
        >>> pipe(text,
        ...      set,
        ...      sorted)
        ['a', 'b', 'd', 'h', 'n', 's', 't']

        It's also possible to use named arguments by using a dict:

        >>> pipe(text,
        ...      set,
        ...      (sorted, {"reverse": True}))
        ['t', 's', 'n', 'h', 'd', 'b', 'a']

    """
    for f in functions:
        if isinstance(f, tuple):
            if isinstance(f[1], dict):
                data = f[0](data, **f[1])
            else:
                data = f[0](data, *f[1:])
        else:
            data = f(data)
    return data


def start_schema_extension(DirectoryId=None,
    CreateSnapshotBeforeSchemaExtension=None, LdifContent=None, Description
    =None):
    """
    Applies a schema extension to a Microsoft AD directory.
    See also: AWS API Documentation

    :example: response = client.start_schema_extension(
        DirectoryId='string',
        CreateSnapshotBeforeSchemaExtension=True|False,
        LdifContent='string',
        Description='string'
    )

    :type DirectoryId: string
    :param DirectoryId: [REQUIRED]
            The identifier of the directory for which the schema extension will be applied to.

    :type CreateSnapshotBeforeSchemaExtension: boolean
    :param CreateSnapshotBeforeSchemaExtension: [REQUIRED]
            If true, creates a snapshot of the directory before applying the schema extension.

    :type LdifContent: string
    :param LdifContent: [REQUIRED]
            The LDIF file represented as a string. To construct the LdifContent string, precede each line as it would be formatted in an ldif file with n. See the example request below for more details. The file size can be no larger than 1MB.

    :type Description: string
    :param Description: [REQUIRED]
            A description of the schema extension.

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

    """
    pass


@staticmethod
def time_to_str(time):
    """
        Convert time to formated string with the appropriate time units.
        """
    if time < 60:
        return '{:>2}sec '.format(round(time))
    elif time > 60 and time < 3600:
        return '{:>2}min '.format(round(time / 60))
    else:
        return '{:>2}h{:>2}m'.format(round(time / 3600), round(time % 3600 /
            60))


def calculate_course_mau(mau_ids):
    """
    Returns the count of distinct MAU user ids

    Starting as a one liner function, purpose is to decouple each of the three
    ETL steps

    If we need to filter on staff add `courselike` argument and a kwarg for
    `filter_staff` and implement this function:
        ```
        def get_staff_for_course(courselike)
        ```

    Where `courselike` is an object that can return a unique course id

    Add conditional operation to filter out staff ids from the mau_ids queryset
    """
    return mau_ids.count()


@staticmethod
def concat_url(endpoint, url):
    """Concatenate endpoint and final URL.

        E.g., "http://keystone/v2.0/" and "/tokens" are concatenated to
        "http://keystone/v2.0/tokens".

        :param endpoint: the base URL
        :param url: the final URL
        """
    return '%s/%s' % (endpoint.rstrip('/'), url.strip('/'))


def blast_to_cigar(query_seq, match_seq, subject_seq, cigar_age='new'):
    """converts BLAST alignment into a old or new CIGAR line

    Args:
        query_seq (str): Aligned portion of query sequence

        match_seq (str): Alignment sequence

        subject_seq (str): Aligned portion of subject/reference sequence

        cigar_age (str): ['old', 'new'] CIGAR format to use, new is highly
            detailed while old is fairly minimalistic

    Returns:
        str: CIGAR string

    Raises:
        ValueError: If query_seq, match_seq, and match_seq not same length

    Examples:
        >>> query = 'AAGGG--CCTTGTA'
        >>> subject = 'AAGCCTTCCAGGTA'
        >>> alignment_old = '|||||  |||||||'
        >>> alignment_new = 'AAG++  CC++GTA'
        >>> blast_to_cigar(query, alignment_new, subject)
        3=2X2D2=2X3=
        >>> blast_to_cigar(query, alignment_old, subject, cigar_age='old')
        5M2D7M
    """
    if not len(query_seq) == len(match_seq) or not len(query_seq) == len(
        subject_seq) or not len(subject_seq) == len(match_seq):
        raise ValueError(
            'query_seq, match_seq, and subject_seq not same lengths.')
    cigar_line_raw = []
    for query, match, subject in zip(query_seq, match_seq, subject_seq):
        if query == '-':
            cigar_line_raw.append('D')
            continue
        elif subject == '-':
            cigar_line_raw.append('I')
            continue
        elif match == '+' or match == '|' or match.isalpha():
            if match != '+' and cigar_age == 'new':
                cigar_line_raw.append('=')
                continue
            elif match == '+' and cigar_age == 'new':
                cigar_line_raw.append('X')
                continue
            else:
                cigar_line_raw.append('M')
                continue
        elif cigar_age == 'new':
            cigar_line_raw.append('X')
            continue
        else:
            cigar_line_raw.append('M')
    cigar_line = []
    last_position = ''
    repeats = 1
    cigar_len = len(cigar_line_raw)
    for letter in enumerate(cigar_line_raw):
        if letter[1] == last_position:
            repeats += 1
        else:
            if repeats != 1:
                cigar_line.append(str(repeats))
                repeats = 1
            cigar_line.append(last_position)
        if letter[0] == cigar_len - 1:
            if repeats != 1:
                cigar_line.append(str(repeats))
                repeats = 1
            cigar_line.append(letter[1])
        last_position = letter[1]
    return ''.join(cigar_line)


@classmethod
def create_empty_info(cls, sample, sequencing_object=None):
    """
        Creates an empty SampleSistrInfo object (no SISTR results).
        :param sample: The sample this object refers to.
        :param sequencing_object: The sequencing object (default None).
        :return: An empty SampleSistrInfo.
        """
    data = {'sample': sample, 'has_results': False}
    if sequencing_object is not None:
        data['paired_files'] = sequencing_object
    reportable_serovars = []
    return cls(data, reportable_serovars)


def numatoms(mol) ->int:
    """
    Number of atoms.

    Parameters
    ----------
    mol:
        Molecule

    Returns
    -------
    int
        Number of atoms
    """
    return mol.GetNumAtoms()


def progress(status_code):
    """Translate PROGRESS status codes from GnuPG to messages."""
    lookup = {'pk_dsa': 'DSA key generation', 'pk_elg':
        'Elgamal key generation', 'primegen': 'Prime generation',
        'need_entropy': 'Waiting for new entropy in the RNG', 'tick':
        'Generic tick without any special meaning - still working.',
        'starting_agent': 'A gpg-agent was started.', 'learncard':
        'gpg-agent or gpgsm is learning the smartcard data.', 'card_busy':
        'A smartcard is still working.'}
    for key, value in lookup.items():
        if str(status_code) == key:
            return value


def get_state_color(state):
    """
    Get right color for the state

    :param state: the state
    :type state: str
    :return: the color related of the state
    :rtype: str
    """
    state_color = '#27ae60'
    state = state.upper()
    if state == 'WARNING':
        state_color = '#e67e22'
    if state in ['CRITICAL', 'DOWN']:
        state_color = '#e74c3c'
    if state == 'UNKNOWN':
        state_color = '#2980b9'
    if state == 'UNREACHABLE':
        state_color = '#9b59b6'
    if state == 'ACKNOWLEDGE':
        state_color = '#f39c12'
    if state == 'DOWNTIME':
        state_color = '#f1c40f'
    return state_color


def path_reference_copy(copy_set: set, report='print'):
    """Execute copying files of path_reference

    :param copy_set: set of (from, to) pairs to copy.
    :type copy_set: set
    :param report: function used for reporting warnings, takes a string argument.
    """
    pass


@classmethod
def init(cls):
    """
        Init sound subsystem.
        """
    if not cls._has_init:
        cls._init()


@classmethod
def coerce(cls, key, value):
    """Given a value, coerce it into the target type.

        Can be overridden by custom subclasses to coerce incoming
        data into a particular type.

        By default, raises ``ValueError``.

        This method is called in different scenarios depending on if
        the parent class is of type :class:`.Mutable` or of type
        :class:`.MutableComposite`.  In the case of the former, it is called
        for both attribute-set operations as well as during ORM loading
        operations.  For the latter, it is only called during attribute-set
        operations; the mechanics of the :func:`.composite` construct
        handle coercion during load operations.

        :param key: string name of the ORM-mapped attribute being set.
        :param value: the incoming value.
        :return: the method should return the coerced value, or raise
         ``ValueError`` if the coercion cannot be completed.

        """
    if value is None:
        return None
    msg = "Attribute '%s' does not accept objects of type %s"
    raise ValueError(msg % (key, type(value)))


def get_sequence(lines):
    """Returns sequence string.
    """
    if lines:
        seq_line = ''.join(lines)
        seq = seq_line.split('(')[1].split(') def')[0].strip('\n\\')
    else:
        seq = ''
    return seq


def _rotate_buff(buff):
    """
    Rotate buffer (for each ``buff[i] = buff[i-1]``).

    Example:
        assert _rotate_buff([1, 2, 3, 4]) == [4, 1, 2, 3]

    Args:
        buff (list): Buffer which will be rotated.

    Returns:
        list: Rotated buffer.
    """
    return [buff[-1]] + buff[:-1]


def eliminate_self_loops(A):
    """Remove self-loops from the adjacency matrix."""
    A = A.tolil()
    A.setdiag(0)
    A = A.tocsr()
    A.eliminate_zeros()
    return A


def _bytes2str(num):
    """
    this function will convert bytes to MB.... GB... etc
    """
    for x in [' B', 'KB', 'MB', 'GB', 'TB']:
        if num < 1024.0:
            return '%3.2f %s' % (num, x)
        num /= 1024.0


def __new__(cls, category, unit, unknown_unit_caption=None):
    """
        Overridden because we don't want to call the Quantity.__new__ (which would result
        in a StackOverflowError).
        """
    return object.__new__(cls)


def transcripts_in_window(df, window, feature='transcript'):
    """
    Return the transcript names for which
    either the end or the begin of an exon is within the window
    """
    return df.loc[df['begin'].between(window.begin, window.end) | df['end']
        .between(window.begin, window.end), feature].unique()


def absdeg(deg):
    """Change from signed degrees to 0-180 or 0-360 ranges

    deg: ndarray
        Movement data in pitch, roll, yaw (degrees)

    Returns
    -------
    deg_abs: ndarray
        Movement translated from -180:180/-90:90 degrees to 0:360/0:180 degrees

    Example
    -------
    deg = numpy.array([-170, -120, 0, 90])
    absdeg(deg) # returns array([190, 240,   0,  90])
    """
    import numpy
    d = numpy.copy(deg)
    if numpy.max(numpy.abs(deg)) > 90.0:
        d[deg < 0] = 360 + deg[deg < 0]
    else:
        d[deg < 0] = 180 + deg[deg < 0]
    return d


def ceildiv(dividend, divisor):
    """ How to divide two possibly-integer numbers and round up.
    """
    assert divisor > 0
    q, r = divmod(dividend, divisor)
    return int(q) + (r != 0)


def load():
    """
        Load a template suitable for rendering.

        @return: a C{list} of C{list}s, C{unicode} objects, C{Element}s and
            other L{IRenderable} providers.
        """


def __experimental_range(start, stop, var, cond, loc={}):
    """Utility function made to reproduce range() with unit integer step
       but with the added possibility of specifying a condition
       on the looping variable  (e.g. var % 2  == 0)
    """
    locals().update(loc)
    if start < stop:
        for __ in range(start, stop):
            locals()[var] = __
            if eval(cond, globals(), locals()):
                yield __
    else:
        for __ in range(start, stop, -1):
            locals()[var] = __
            if eval(cond, globals(), locals()):
                yield __


def v110_deprecations(defaults, runtime, harmonization, dry_run):
    """
    Checking for deprecated runtime configurations (stomp collector, cymru parser, ripe expert)
    """
    mapping = {'intelmq.bots.collectors.n6.collector_stomp':
        'intelmq.bots.collectors.stomp.collector',
        'intelmq.bots.parsers.cymru_full_bogons.parser':
        'intelmq.bots.parsers.cymru.parser_full_bogons'}
    changed = None
    for bot_id, bot in runtime.items():
        if bot['module'] in mapping:
            bot['module'] = mapping[bot['module']]
            changed = True
        if bot['module'
            ] == 'intelmq.bots.experts.ripencc_abuse_contact.expert':
            bot['module'] = 'intelmq.bots.experts.ripe.expert'
            changed = True
        if bot['module'] == 'intelmq.bots.experts.ripe.expert':
            if bot['parameters'].get('query_ripe_stat'):
                if 'query_ripe_stat_asn' not in bot['parameters']:
                    bot['parameters']['query_ripe_stat_asn'] = bot['parameters'
                        ]['query_ripe_stat']
                if 'query_ripe_stat_ip' not in bot['parameters']:
                    bot['parameters']['query_ripe_stat_ip'] = bot['parameters'
                        ]['query_ripe_stat']
                del bot['parameters']['query_ripe_stat']
                changed = True
        if bot['group'] == 'Collector' and bot['parameters'].get('feed'
            ) and not bot['parameters'].get('name'):
            try:
                bot['parameters']['name'] = bot['parameters']['feed']
                del bot['parameters']['feed']
            except KeyError:
                pass
            else:
                changed = True
    return changed, defaults, runtime, harmonization


def speaker_add(view_align: bool=False, enter_editmode: bool=False,
    location: float=(0.0, 0.0, 0.0), rotation: float=(0.0, 0.0, 0.0),
    layers: bool=(False, False, False, False, False, False, False, False,
    False, False, False, False, False, False, False, False, False, False,
    False, False)):
    """Add a speaker object to the scene

    :param view_align: Align to View, Align the new object to the view
    :type view_align: bool
    :param enter_editmode: Enter Editmode, Enter editmode when adding this object
    :type enter_editmode: bool
    :param location: Location, Location for the newly added object
    :type location: float
    :param rotation: Rotation, Rotation for the newly added object
    :type rotation: float
    :param layers: Layer
    :type layers: bool
    """
    pass


@classmethod
def get_format_string(cls):
    """See RepositoryFormat.get_format_string()."""
    return (
        b'Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n'
        )


def truncate(size):
    """Truncate the file. See Python documentation for :class:`io.IOBase` for
        details.
        """


def strip_trailing_slashes(path):
    """    Remove trailing slashes from the given path.

    :param path: a path, eg ``'/foo/bar/'``
    :return: The path with trailing slashes removed, eg ``'/foo/bar'``
    """
    while path and path[-1] == '/':
        path = path[:-1]
    return path


def set_coordinates(atoms, V, title='', decimals=8):
    """
    Print coordinates V with corresponding atoms to stdout in XYZ format.
    Parameters
    ----------
    atoms : list
        List of atomic types
    V : array
        (N,3) matrix of atomic coordinates
    title : string (optional)
        Title of molecule
    decimals : int (optional)
        number of decimals for the coordinates

    Return
    ------
    output : str
        Molecule in XYZ format

    """
    N, D = V.shape
    fmt = '{:2s}' + (' {:15.' + str(decimals) + 'f}') * 3
    out = list()
    out += [str(N)]
    out += [title]
    for i in range(N):
        atom = atoms[i]
        atom = atom[0].upper() + atom[1:]
        out += [fmt.format(atom, V[i, 0], V[i, 1], V[i, 2])]
    return '\n'.join(out)


def get_current_authuser():
    """
    Gets kallithea user from threadlocal tmpl_context variable if it's
    defined, else returns None.
    """
    from tg import tmpl_context
    try:
        return getattr(tmpl_context, 'authuser', None)
    except TypeError:
        return None


def mean(seq):
    """Return the average of the elements of a sequence."""
    return float(sum(seq)) / len(seq) if len(seq) > 0 else float('nan')


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

    The ".dev0" means dirty.

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


def advance_surf_cov(surf, Csurf, x):
    """
    Explicit integration of the covariance term, using scipy's sparse matrix for Csurf
    surf - density function along the surface
    Csurf - transition matrix
    x - grid
    """
    surf = (Csurf * surf.reshape(len(x) ** 2)).reshape(len(x), len(x))
    return surf


def gwh_to_twh(gwh):
    """Convert GWh to TWh

    Arguments
    ---------
    gwh : float
        GWh

    Returns
    -------
    twh : str
        TWh
    """
    twh = gwh / 1000.0
    return twh


def lru_items():
    """ -> a sequence of tuples (oid, value) for cached objects.

        o Tuples will be in LRU order.

        o Only includes items in the ring (no ghosts or p-classes).
        """


def maybe_type(obj, class_or_tuple):
    """
    A type monid. Return transfered type of obj or None if type cannot assign to given obj.
    """
    if obj is None:
        return None
    if isinstance(obj, str) and class_or_tuple is iter:
        """Trick treat str as non-iterable."""
        return None
    try:
        transfered_obj = None
        transfered_obj = class_or_tuple(obj)
    except:
        pass
    if transfered_obj is not None:
        return transfered_obj
    else:
        try:
            return class_or_tuple(obj)
        except:
            return


def make_log_request_dict(direction='reverse', specific_fileids=None,
    start_revision=None, end_revision=None, limit=None, message_search=None,
    levels=None, generate_tags=True, delta_type=None, diff_type=None,
    _match_using_deltas=True, exclude_common_ancestry=False, match=None,
    signature=False, omit_merges=False):
    """Convenience function for making a logging request dictionary.

    Using this function may make code slightly safer by ensuring
    parameters have the correct names. It also provides a reference
    point for documenting the supported parameters.

    :param direction: 'reverse' (default) is latest to earliest;
      'forward' is earliest to latest.

    :param specific_fileids: If not None, only include revisions
      affecting the specified files, rather than all revisions.

    :param start_revision: If not None, only generate
      revisions >= start_revision

    :param end_revision: If not None, only generate
      revisions <= end_revision

    :param limit: If set, generate only 'limit' revisions, all revisions
      are shown if None or 0.

    :param message_search: If not None, only include revisions with
      matching commit messages

    :param levels: the number of levels of revisions to
      generate; 1 for just the mainline; 0 for all levels, or None for
      a sensible default.

    :param generate_tags: If True, include tags for matched revisions.
`
    :param delta_type: Either 'full', 'partial' or None.
      'full' means generate the complete delta - adds/deletes/modifies/etc;
      'partial' means filter the delta using specific_fileids;
      None means do not generate any delta.

    :param diff_type: Either 'full', 'partial' or None.
      'full' means generate the complete diff - adds/deletes/modifies/etc;
      'partial' means filter the diff using specific_fileids;
      None means do not generate any diff.

    :param _match_using_deltas: a private parameter controlling the
      algorithm used for matching specific_fileids. This parameter
      may be removed in the future so breezy client code should NOT
      use it.

    :param exclude_common_ancestry: Whether -rX..Y should be interpreted as a
      range operator or as a graph difference.

    :param signature: show digital signature information

    :param match: Dictionary of list of search strings to use when filtering
      revisions. Keys can be 'message', 'author', 'committer', 'bugs' or
      the empty string to match any of the preceding properties.

    :param omit_merges: If True, commits with more than one parent are
      omitted.

    """
    if message_search:
        if match:
            if 'message' in match:
                match['message'].append(message_search)
            else:
                match['message'] = [message_search]
        else:
            match = {'message': [message_search]}
    return {'direction': direction, 'specific_fileids': specific_fileids,
        'start_revision': start_revision, 'end_revision': end_revision,
        'limit': limit, 'levels': levels, 'generate_tags': generate_tags,
        'delta_type': delta_type, 'diff_type': diff_type,
        'exclude_common_ancestry': exclude_common_ancestry, 'signature':
        signature, 'match': match, 'omit_merges': omit_merges,
        '_match_using_deltas': _match_using_deltas}


def get(isamAppliance, id, check_mode=False, force=False):
    """
    Retrieve a URL Mapping
    """
    return isamAppliance.invoke_get('Retrieve a URL Mapping',
        '/wga/dynurl_config/{0}'.format(id))


def create_instance_of(qualified_name, **kwargs):
    """Creates an instance of the fully qualified name of a class.

  Args:
    qualified_name (str): Full name of the class to instantiate
    kwargs: Other arguments that will be forwarded

  Returns:
    obj: Instance of the asked class

  """
    parts = qualified_name.split('.')
    klass = parts[-1:][0]
    mod = __import__('.'.join(parts[:-1]), fromlist=[klass])
    return getattr(mod, klass)(**kwargs)


def get_commit(repositoryName=None, commitId=None):
    """
    Returns information about a commit, including commit message and committer information.
    See also: AWS API Documentation

    :example: response = client.get_commit(
        repositoryName='string',
        commitId='string'
    )

    :type repositoryName: string
    :param repositoryName: [REQUIRED]
            The name of the repository to which the commit was made.

    :type commitId: string
    :param commitId: [REQUIRED]
            The commit ID.

    :rtype: dict
    :return: {
        'commit': {
            'treeId': 'string',
            'parents': [
                'string',
            ],
            'message': 'string',
            'author': {
                'name': 'string',
                'email': 'string',
                'date': 'string'
            },
            'committer': {
                'name': 'string',
                'email': 'string',
                'date': 'string'
            },
            'additionalData': 'string'
        }
    }

    :returns:
    (string) --

    """
    pass


def compute_resize_scale(image_shape, min_side=1024, max_side=1333):
    """ Compute an image scale such that the image size is constrained to min_side and max_side.

    Args
        min_side: The image's min side will be equal to min_side after resizing.
        max_side: If after resizing the image's max side is above max_side, resize until the max side is equal to max_side.

    Returns
        A resizing scale.
    """
    if len(image_shape) == 3:
        rows, cols, _ = image_shape
    elif len(image_shape) == 2:
        rows, cols = image_shape
    else:
        raise ValueError('image_shape error')
    smallest_side = min(rows, cols)
    scale = min_side / smallest_side
    largest_side = max(rows, cols)
    if largest_side * scale > max_side:
        scale = max_side / largest_side
    return scale


def detail_flood_fill():
    """Flood fill the mesh with the selected detail setting

    """
    pass


def add_hover_tool(p, rend):
    """ Append hover tool to plot
    parameters
    ----------
    p : bokeh figure
        declares where to append hover tool
    rend : list
        list of renderer to append hover tool
    """
    from bokeh.models import HoverTool
    hover_tool = HoverTool(tooltips=[('Name', '$name'), ('Count',
        '@data_points'), ('Mean', '@average'), ('Deviation', '@deviation')],
        renderers=rend)
    p.tools.append(hover_tool)


def _close_widgets(item):
    """
    Close all widgets registered in the pytest item.
    """
    widgets = getattr(item, 'qt_widgets', None)
    if widgets:
        for w, before_close_func in item.qt_widgets:
            w = w()
            if w is not None:
                if before_close_func is not None:
                    before_close_func(w)
                w.close()
                w.deleteLater()
        del item.qt_widgets


def _get_required_fn(fn, root_path):
    """
    Definition of the MD5 file requires, that all paths will be absolute
    for the package directory, not for the filesystem.

    This function converts filesystem-absolute paths to package-absolute paths.

    Args:
        fn (str): Local/absolute path to the file.
        root_path (str): Local/absolute path to the package directory.

    Returns:
        str: Package-absolute path to the file.

    Raises:
        ValueError: When `fn` is absolute and `root_path` relative or                     conversely.
    """
    if not fn.startswith(root_path):
        raise ValueError('Both paths have to be absolute or local!')
    replacer = '/' if root_path.endswith('/') else ''
    return fn.replace(root_path, replacer, 1)


def map_tag_name_to_dict(instance, value):
    """Convert a tag name into a dictionary for Tag."""
    return {'name': value, '__incomplete__': True}


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

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


def reassign_representative(cur_representative_id, cur_aai,
    new_representative_id, new_aai, trusted_user_genomes):
    """Determines best representative genome.

    Genomes are preferentially assigned to representatives based on
    source repository (RefSeq => GenBank => Trusted User => User) and AAI.
    """
    source_order = {'R': 0, 'G': 1, 'U': 2}
    if not cur_representative_id:
        return new_representative_id, new_aai
    cur_source = source_order[cur_representative_id[0]]
    new_source = source_order[new_representative_id[0]]
    if new_representative_id in trusted_user_genomes:
        new_source = source_order['G']
    if new_source < cur_source:
        return new_representative_id, new_aai
    elif new_source == cur_source:
        if new_aai > cur_aai:
            return new_representative_id, new_aai
    return cur_representative_id, cur_aai


def bitwidth(num):
    """Return the number of bits required to represent num
    """
    count = 0
    while num:
        count += 1
        num = num >> 1
    return count


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 delete_project(id=None, clientRequestToken=None, deleteStack=None):
    """
    Deletes a project, including project resources. Does not delete users associated with the project, but does delete the IAM roles that allowed access to the project.
    See also: AWS API Documentation

    :example: response = client.delete_project(
        id='string',
        clientRequestToken='string',
        deleteStack=True|False
    )

    :type id: string
    :param id: [REQUIRED]
            The ID of the project to be deleted in AWS CodeStar.

    :type clientRequestToken: string
    :param clientRequestToken: A user- or system-generated token that identifies the entity that requested project deletion. This token can be used to repeat the request.

    :type deleteStack: boolean
    :param deleteStack: Whether to send a delete request for the primary stack in AWS CloudFormation originally used to generate the project and its resources. This option will delete all AWS resources for the project (except for any buckets in Amazon S3) as well as deleting the project itself. Recommended for most use cases.

    :rtype: dict
    :return: {
        'stackId': 'string',
        'projectArn': 'string'
    }

    """
    pass


def filterExperimentFilesUsingStatus(expFileList):
    """filterExperimentFilesUsingStatus returns a subset of the experiment files in expFileList with default status.

    Input:

        expFileList - a list of MadrigalExperimentFile objects to be filtered.

    Returns:

        a subset of expFileList with default status
    """
    retList = []
    for expFile in expFileList:
        if expFile.category == 1:
            retList.append(expFile)
    return retList


def __new__(mcls, name, parents, attributes):
    """Creates a new Type object (an instance of TypeMetaclass).
    Args:
        name (str): the name of the new type.
        parents (list(str)): a list of superclasses.
        attributes: (???): a map from name to value for "parameters" for defining
           the new type.
    """
    return type.__new__(mcls, name, parents, attributes)


def setRegisterNumbersForTemporaries(ast, start):
    """Assign register numbers for temporary registers, keeping track of
    aliases and handling immediate operands.
    """
    seen = 0
    signature = ''
    aliases = []
    for node in ast.postorderWalk():
        if node.astType == 'alias':
            aliases.append(node)
            node = node.value
        if node.reg.immediate:
            node.reg.n = node.value
            continue
        reg = node.reg
        if reg.n is None:
            reg.n = start + seen
            seen += 1
            signature += reg.node.typecode()
    for node in aliases:
        node.reg = node.value.reg
    return start + seen, signature


def renumber(topology, start=None, column='resSeq', retain_gap=True):
    """
    Renumber a numeric column in the TopologyDataFrame

    Select the column to renumber by column header name using the `column`
    argument. Renumber starting from a new `start` number or the first number
    in the column.
    If there is a gab in the numeric sequence the `retain_gab` argument will
    correct for this in the renumbered sequence.

    :param topology:
    :type topology:     :interact:TopologyDataFrame
    :param start:       start number
    :type:              :py:int
    :param column:      column name of numeric column to renumber
    :type column:       :py:str
    :param retain_gap:  preserve gaps in the numbering
    :type retain_gap:   :py:bool

    :return:
    """
    if column not in topology.columns:
        raise TypeError('No such column: {0}'.format(column))
    numbers = topology[column].values
    if start is None:
        start = int(numbers[0])
    renumbered = []
    current = None
    for nr in numbers:
        if current is None:
            current = nr
        if current != nr:
            if retain_gap:
                diff = nr - current
                if diff > 1:
                    start += diff
                else:
                    start += 1
            else:
                start += 1
            current = nr
        renumbered.append(start)
    if len(renumbered) != len(numbers):
        raise ArithmeticError('Renumbering failed, length mismatch')
    topology[column] = renumbered
    return topology


def stringify(syllables):
    """This function takes a syllabification returned by syllabify and
	   turns it into a string, with phonemes spearated by spaces and
	   syllables spearated by periods."""
    ret = []
    for syl in syllables:
        stress, onset, nucleus, coda = syl
        if stress != None and len(nucleus) != 0:
            nucleus[0] += str(stress)
        ret.append(' '.join(onset + nucleus + coda))
    return ' . '.join(ret)


def HasPendingNodesASAP(APCG, ScheduledDict, ComNode):
    """
	Return True if data parent operation is not scheduled yet, False otherwise.
	"""
    PendingNodes = []
    for Node in ScheduledDict:
        for SuccessorNode in APCG.successors(Node):
            if SuccessorNode is ComNode:
                continue
            elif not SuccessorNode in ScheduledDict:
                if not SuccessorNode in PendingNodes:
                    PendingNodes.append(SuccessorNode)
    return PendingNodes


def errorcode_from_error(e):
    """
    Get the error code from a particular error/exception caused by PostgreSQL.
    """
    return e.orig.pgcode


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

    """
    pass


def theta_K_Na_HMW84(T, P):
    """c-c': potassium sodium [HMW84]."""
    theta = -0.012
    valid = T == 298.15
    return theta, valid


def manage_acquiredPermissions(permissions=[]):
    """Change the permissions that acquire.
        """


def context_set_id(data_path: str='', value: str=''):
    """Set a context value to an ID data-block

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    :param value: Value, Assign value
    :type value: str
    """
    pass


@staticmethod
def _slicespec2boundsspec(slicespec, scs):
    """
        Convert an iterable slicespec (supplying r1,r2,c1,c2 of a
        Slice) into a BoundingRegion specification.

        Exact inverse of _boundsspec2slicespec().
        """
    r1, r2, c1, c2 = slicespec
    left, bottom = scs.matrix2sheet(r2, c1)
    right, top = scs.matrix2sheet(r1, c2)
    return (left, bottom), (right, top)


def M_eta_m1_m2(m1, m2):
    """
    Computes the symmetric mass-ratio (eta)
    and total mass (M) from the component masses
    input: m1, m2
    output: M, eta
    """
    M = m1 + m2
    eta = m1 * m2 / (m1 + m2) ** 2
    return M, eta


def read_wordlist(filename: str):
    """Return words from a wordlist file."""
    with open(filename, encoding='utf-8') as wordlist_file:
        for row in iter(wordlist_file):
            row = row.strip()
            if row != '':
                yield row


def get_layers(proto):
    """Returns layers in a caffe_pb2.NetParameter object
    """
    if len(proto.layer):
        return proto.layer
    elif len(proto.layers):
        return proto.layers
    else:
        raise ValueError('Invalid proto file.')


def PointerProperty(type=None, name: str='', description: str='', options:
    set={'ANIMATABLE'}, tags: set={}, poll=None, update=None):
    """Returns a new pointer property definition.

    :param type: A subclass of bpy.types.PropertyGroup or bpy.types.ID.
    :param name: Name used in the user interface.
    :type name: str
    :param description: Text used for the tooltip and api documentation.
    :type description: str
    :param options: Enumerator in [‘HIDDEN’, ‘SKIP_SAVE’, ‘ANIMATABLE’, ‘LIBRARY_EDITABLE’, ‘PROPORTIONAL’,’TEXTEDIT_UPDATE’].
    :type options: set
    :param tags: Enumerator of tags that are defined by parent class.
    :type tags: set
    :param poll: function to be called to determine whether an item is valid for this property. The function must take 2 values (self, object) and return Bool.
    :param update: Function to be called when this value is modified, This function must take 2 values (self, context) and return None. Warning there are no safety checks to avoid infinite recursion.
    """
    pass


def invisible_p(x, y):
    """Return true if the point (X, Y) is visible in the canvas."""
    if x < -499999 or y < -499999:
        return 1
    return 0


def is_channel(string):
    """
    Return True if input string is a channel
    """
    return string and string[0] in '#&+!'


def ColumnValidator(parent, filepointer, nCol=5):
    """Validate a file to check that it contains columns of numbers"""
    l = filepointer.readline()
    line = 1
    while l[0] in ['#', '(']:
        l = filepointer.readline()
        line += 1
    for i in range(10):
        S = l.split()
        if len(S) < nCol:
            parent.errors = 'line ' + str(line) + ': invalid input\n' + l
            return False
        for v in S[:nCol]:
            try:
                float(v)
            except ValueError:
                parent.errors = 'line ' + str(line
                    ) + """: string found where a number is expected
""" + l
                return False
        l = filepointer.readline()
        line += 1
    return True


def int_shape(x):
    """Returns the shape of a Keras tensor or a Keras variable as a tuple of
    integers or None entries.

    # Arguments
        x: Tensor or variable.

    # Returns
        A tuple of integers (or None entries).
    """
    if hasattr(x, '_keras_shape'):
        return x._keras_shape
    else:
        return None


def modifiedjd_to_juliandate(modifiedjd):
    """Convert a Modified Julian Date to Julian Date

    :param modifiedjf: a Modified Julian Date.
    :return: Julian Date.

    """
    return modifiedjd + 2400000.5


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

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

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


@classmethod
def count(cls):
    """
        Return total number of items in database.
        """
    return cls.query.count()


def ReadableSize(num):
    """Get a human-readable size."""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if abs(num) <= 1024.0:
            return '%3.2f%s' % (num, unit)
        num /= 1024.0
    return '%.1f TB' % (num,)


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

        :param SharedLinkChangeExpiryType val:
        :rtype: EventType
        """
    return cls('shared_link_change_expiry', val)


def retrieve(resource_id: str) ->str:
    """
        Retrieve a copy of a resource from this adapter.

        Retrieve assumes that the file can be stored to the `output_dir`.
        AdapterManager will always verify that this is the case.

        Returns the path to the resource.

        May overwrite files in the `output_dir`

        :param r_id - the resource to retrieve's UUID
        """
    pass


def image_cuda():
    """ Run grid and image with rfgpu
    TODO: update to use rfgpu
    """
    pass


def tag_fig_ordinal(tag):
    """
    Meant for finding the position of fig tags with respect to whether
    they are for a main figure or a child figure
    """
    tag_count = 0
    if 'specific-use' not in tag.attrs:
        return len(list(filter(lambda tag: 'specific-use' not in tag.attrs,
            tag.find_all_previous(tag.name)))) + 1


def airDensity_from_theta_v(data, units, notation=None, inplace_units=True,
    use_means=False, return_full_df=True):
    """
    Calculates moist air density using p = rho R_dry T_virtual

    Parameters
    ----------
    data: pandas.DataFrame
        data to use to calculate air density
    units: dict
        dictionary of units
    notation: pymicra.Notation
        notation to be used
    inplace_units: bool
        whether or not to update the units inplace. If False, units are returns too
    use_means: bool
        whether or not to use averages of pressure and virtual temperature, instead of the means plus fluctuations

    Returns
    -------

    """
    from . import algs
    from . import constants
    defs = algs.get_notation(notation)
    data = data.copy()
    if not inplace_units:
        units = units.copy()
    R_dry = constants.R_spec['dry']
    if use_means:
        data.loc[:, (defs.moist_air_mass_density)] = data[defs.pressure].mean(
            ) / (R_dry * data[defs.virtual_temp].mean())
    else:
        data.loc[:, (defs.moist_air_mass_density)] = data[defs.pressure] / (
            R_dry * data[defs.virtual_temp])
    units.update({defs.moist_air_mass_density: units[defs.pressure] / (
        constants.units['R_spec'] * units[defs.virtual_temp])})
    data = data.convert_cols({defs.moist_air_mass_density: 'kg/m**3'},
        units, inplace_units=True)
    if inplace_units:
        return data
    else:
        return data, units


@classmethod
def readScene(cls, args):
    """Classmethod to create a CziScene object from args (argparse).

        Kwargs:
          |  args (argparse.Namespace): As returned by parse_args()

        """
    ret = cls(args.czi_filename[0], scene=args.scene[0], metafile_out=args.
        metafile_out[0], tifffile_out=args.tifffile_out[0], verbose=args.
        cziscene_verbose)
    ret.read_scene_image()
    return ret


def get_prompt(zelf, *args, **kwargs):
    """ return a prompt. """
    return ''


def get_alpha(value, capital=False):
    """
    Convert an integer value to a character. a-z then double, aa-zz etc.
    @param value: int, Value to get an alphabetic character from
    @param capital: boolean: True if you want to get capital character
    @return: str, Character from an integer
    """
    base_power = base_start = base_end = 0
    while value >= base_end:
        base_power += 1
        base_start = base_end
        base_end += pow(26, base_power)
    base_index = value - base_start
    alphas = ['a'] * base_power
    for index in range(base_power - 1, -1, -1):
        alphas[index] = chr(97 + base_index % 26)
        base_index /= 26
    if capital:
        return ''.join(alphas).upper()
    return ''.join(alphas)


def process_bool_arg(arg):
    """ Determine True/False from argument """
    if isinstance(arg, bool):
        return arg
    elif isinstance(arg, str):
        if arg.lower() in ['true', '1']:
            return True
        elif arg.lower() in ['false', '0']:
            return False


def load_handlers(name):
    """Load the (URL pattern, handler) tuples for each component."""
    mod = __import__(name, fromlist=['default_handlers'])
    return mod.default_handlers


@classmethod
def PUT(cls, *n, **kw):
    """Perform a PUT request using :meth:`RESTClient.request()`."""
    return cls.IMPL.PUT(*n, **kw)


@staticmethod
def is_comment_string(data_string):
    """ Checks if supplied string after stripping corresponds to comment and shall thus be ignored in data processing

        :param data_string: a string to check if it is a pure comment string
        :type data_string: ``str``
        :return: a flag indicating if supplied string is a pure comment string
        :rtype: ``Boolean``
        """
    return data_string.strip().startswith('#')


def qart(data, a=0.0, f=0.0):
    """
    Scale Quad Artifacts.

    Replaces imaginary data with (1 + a) * data.imag + f * data.real

    Parameters
    ----------
    data : ndarray
        Array of NMR data.
    a : float
        Amplitude adjustment.
    f : float
        Phase adjustment.

    Returns
    -------
    ndata : ndarray
        Array of NMR data with quadrature artifacts scaled.

    """
    data.imag = (1 + a) * data.imag + f * data.real
    return data


def extend_parser(optparser_parse):
    """
    You can add or remove options from the parser here.
    """


@classmethod
def match_log_from_log_name(cls, log_name):
    """Parses the log from a log resource.

        Args:
          log_name (string): A fully-qualified path representing a log
            resource.

        Returns:
          A string representing the log.
        """
    return cls._LOG_PATH_TEMPLATE.match(log_name).get('log')


def isNull(val):
    """Returns boolean value for passed value indicating if it is a Null or NaN value"""
    if val == None:
        return True
    elif val != val:
        return True
    else:
        return False


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


@classmethod
def remove_access(cls, ns, entity, provider):
    """
        Removes the access for the given entity to the provider in the
        access namespace.
        :param string ns: The namespace of the access domain.
        :param Entity entity: An entity.
        :param mongoengine.Document provider: The provider of the access.
        """
    cls.objects(ns=ns, entity=entity, provider=provider).delete(safe=True)


@staticmethod
def _sentence_tokenizer_merge_matches(match):
    """ Best way we found to deal with repeating groups"""
    start, end = match.span()
    return match.string[start:end] + '<SPLIT>'


@classmethod
def create_module(cls, spec):
    """Use default semantics for module creation."""


def find_prepositions(chunked):
    """ The input is a list of [token, tag, chunk]-items.
        The output is a list of [token, tag, chunk, preposition]-items.
        PP-chunks followed by NP-chunks make up a PNP-chunk.
    """
    for ch in chunked:
        ch.append('O')
    for i, chunk in enumerate(chunked):
        if chunk[2].endswith('PP') and chunk[-1] == 'O':
            if i < len(chunked) - 1 and (chunked[i + 1][2].endswith(('NP',
                'PP')) or chunked[i + 1][1] in ('VBG', 'VBN')):
                chunk[-1] = 'B-PNP'
                pp = True
                for ch in chunked[i + 1:]:
                    if not (ch[2].endswith(('NP', 'PP')) or ch[1] in ('VBG',
                        'VBN')):
                        break
                    if ch[2].endswith('PP') and pp:
                        ch[-1] = 'I-PNP'
                    if not ch[2].endswith('PP'):
                        ch[-1] = 'I-PNP'
                        pp = False
    return chunked


@classmethod
def delete_acls_for_secret_model(cls, secret, session=None):
    """Delete acl in Secret

        :param secret: an instance of Secret model
        :param session: a session to connect with database

        Used during converting Model to OVO. It will be removed in the near
        future.
        """
    cls.db_repo.delete_acls_for_secret(secret, session)


def _linear_bf(x):
    """
    Linear base-function the mode_cost

    Can't be a lambda because of parallelization
    :param x: x
    :return: x
    """
    return x


def ABI_Downloader(bucket, year, month, day, hour, product, channel):
    """        ABI_Downloader(bucket,year,month,day,hour,product,channel): All these variables are strings.
    The first argument is the Bucket it's the reposity where has the contents from the satellite, example:

    Bucket='noaa-goes16'
    year  = can be List or a single string to Year date: example = ['2017','2018'] or "2018
    month = can be List or a single string to month date: example = ['03','04'] or "03"
    day   = can be List or a single string for day date: example = ['10','20','30'] or "20"
    hour   = can be List or a single string to hour, and need be UTC coordinate time date: example = ['06','12','18'] or "06"
    product = can be a List or a single string for ABI sensors products from GOES satellite next-generation example: ["ABI-L2-CMIPF"] or "ABI-L1b-RadF"
    channel = can be a List or a single string for the channels from ABI sensors. Example = ['01','02'] or "13"
    """
    from goespy.utils import __isAList
    from goespy.utils import ProgressPercentage
    from goespy import checkData
    from goespy import boto3
    from goespy import botocore
    julianDay = ''
    days = 0
    s3 = boto3.resource('s3', config=botocore.client.Config(
        signature_version=botocore.UNSIGNED))
    goes16 = s3.Bucket(bucket)
    year, month, day, product, hour, channel, julianDay = __isAList(year,
        month, day, product, hour, channel, julianDay=julianDay)
    for i in year:
        for mth in month:
            while days <= len(day) - 1 and days <= len(julianDay) - 1:
                for prod in product:
                    print('Downloading... the product %s ' % prod)
                    for nindex in hour:
                        print('Downloading dataset to... {0} UTC'.format(
                            nindex))
                        objs = goes16.objects.filter(Delimiter='/', Prefix=
                            '{0}/{1}/{2}/{3}/'.format(prod, i, julianDay[
                            days], nindex))
                        for object in objs:
                            filename = object.key.rsplit('/', 1)[1]
                            for ch in channel:
                                if filename.partition(ch)[1] == ch:
                                    path = checkData.createPathGoesData(bucket,
                                        i, mth, day[days], prod, nindex, ch)
                                    if checkData.checkFiles(path, filename):
                                        if checkData.checkSize(path, filename,
                                            object.size):
                                            pass
                                        else:
                                            goes16.download_file(object.key, path +
                                                filename, Callback=
                                                ProgressPercentage(filename, object
                                                .size))
                                    else:
                                        goes16.download_file(object.key, path +
                                            filename, Callback=
                                            ProgressPercentage(filename, object
                                            .size))
                days += 1
    return 0


def getMyIssues(openStates, memberId, manager):
    """Get a catalog query result set of my issues.

        So: all issues assigned to or submitted by the current user,
        with review state in openStates.

        If manager is True, you can add more states.
        """


def __call__(path, idattribute):
    """Read XML file from path and instanciate model consisting of
        IXMLNode implementations.

        @param path: path to input xml file
        @param idattribute: attribute used to catalog referencable objects.
                            this might get a list in future.
        """


@classmethod
def group_key(cls, move):
    """
        Key function for grouping and sorting of
        moves
        """
    return move.from_location, move.product


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 boolean_value(value):
    """get bolean value"""
    if value == 'true':
        ret = True
    else:
        ret = False
    return ret


def combine_modbusmap_and_channel(channel_obj, modbus_map):
    """Add the parameters from the modbus map to the channel object."""
    channel_part = modbus_map['1']['addresses']['300']
    for c in channel_part:
        if channel_part[c]['chn'] == channel_obj['name']:
            channel_obj['units'] = channel_part[c]['misc_u']
            try:
                min_max_range = channel_part[c]['r'].split('-')
                channel_obj['min'] = int(min_max_range[0])
                channel_obj['max'] = int(min_max_range[1])
            except Exception:
                channel_obj['min'] = None
                channel_obj['max'] = None
            channel_obj['change'] = float(channel_part[c]['c'])
            channel_obj['guaranteedReportPeriod'] = int(channel_part[c]['grp'])
            channel_obj['minReportTime'] = int(channel_part[c]['mrt'])
            return channel_obj
    return False


def _no_convert(_, start, end=None):
    """Dummy function for when no conversion is needed."""
    if end:
        return start, end
    else:
        return start, start


@staticmethod
def translate_to_boolean(value):
    """ Takes a boolean or string (eg. true, True, FALSE, etc.) value and returns (boolean) True or False
        :param value: True, 'true', 'false' or 'False' ...
        :return:
        """
    if isinstance(value, bool) or isinstance(value, int):
        return value
    elif isinstance(value, str):
        return value.lower() == 'true'
    else:
        raise ValueError('Invalid argument: ' + value +
            '. Needs to be of type boolean or string')


def get_text(node):
    """Get the contents of text nodes in a parent node"""
    return node.text


@property
def _bit_size_(cls):
    """Only for sized (Not BaseClass)."""
    return NotImplemented


def get_invoice(trip):
    """
    Returns the invoice of the trip
    :param trip: Object
    :return: String containing invoice
    """
    invoice = ''
    if 'invoice' in trip.keys():
        invoice = trip['invoice']
        if invoice != '':
            return invoice
    if invoice == '' and 'jobs' in trip.keys():
        try:
            invoice = trip['jobs']
        except KeyError as e:
            invoice = ''
    else:
        invoice = ''
    if invoice == '':
        if 'ShipmentId' in trip.keys():
            invoice = trip['ShipmentId']
        if invoice == '':
            if 'lr_number' in trip.keys():
                invoice = trip['lr_number']
    return invoice


def items():
    """ Return a list of [(k,v)] pairs from the dictionary """


def add_edi_arguments(parser, required=False):
    """
    Add EDI arguments parser

    :param parser: add arguments to it
    :type parser: argparse.ArgumentParser
    :param required: (Optional) mark edi arguments as required if it equals True
    :type required: bool
    :return: None
    """
    parser.add_argument('--edi', type=str, help='EDI server host', required
        =required)
    parser.add_argument('--token', type=str, help='EDI server token',
        required=required)


def fifo_replace(number_of_episodes):
    """ Return the index of the oldest element in the list """
    return 0


def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Nest Sensor.

    No longer used.
    """


def elapsed(seconds, short=True):
    """ return a string showing the elapsed days, hours, minutes, seconds. """
    txt = ''
    sub = str(seconds).split('.')[-1]
    nsec = float(seconds)
    year = 365 * 24 * 60 * 60
    week = 7 * 24 * 60 * 60
    day = 24 * 60 * 60
    hour = 60 * 60
    minute = 60
    years = int(nsec / year)
    nsec -= years * year
    weeks = int(nsec / week)
    nsec -= weeks * week
    days = int(nsec / day)
    nsec -= days * day
    hours = int(nsec / hour)
    nsec -= hours * hour
    minutes = int(nsec / minute)
    sec = nsec - minutes * minute
    if years:
        txt += '%sy' % years
    if weeks:
        days += weeks * 7
    if days:
        txt += '%sd' % days
    if years and short and txt:
        return txt
    if hours:
        txt += '%sh' % hours
    if days and short and txt:
        return txt
    if minutes:
        txt += '%sm' % minutes
    if hours and short and txt:
        return txt
    if sec == 0:
        txt += '0s'
    elif sec < 1 or not short:
        txt += '%.3fs' % sec
    else:
        txt += '%ss' % int(sec)
    txt = txt.strip()
    return txt


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


def get_files(github_object):
    """Get files from a PR or a commit.
    """
    try:
        return github_object.get_files()
    except AttributeError:
        return github_object.files


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 do_save_image(result, grabber):
    """Result handler to save a result to the system.

    Modifies the supplied result dict with:

        * ``save_dir`` = the root directory for saving images
        * ``save_path`` = the configured path for saving images
        * ``save_path_full`` = the full path, token filtered
        * ``is_saved`` = whether the image has actually been saved or not

    Args:
        result (dict): A result dict to process.
        grabber (camgrab.Grabber): A Grabber instanced, used to get setings,
            etc. from.
    """
    result['save_dir'] = grabber.save_dir
    result['save_path'] = grabber.get_save_path()
    result['save_path_full'] = grabber.format_path(result['save_path'], result)
    result['is_saved'] = False
    if not result.get('image', False):
        return result
    if grabber.should_save_image():
        grabber.make_save_path_dirs(result['save_path_full'])
        result['image'].save(result['save_path_full'])
        result['is_saved'] = True
    return result


@classmethod
def is_allowance_value_valid(cls, allowance_type, allowance_value):
    """
        Method that validates the allowance value against the allowance type
        """
    if allowance_type in cls.ADDITIONAL_TIME_GRANTED:
        if not allowance_value.isdigit():
            return False
    return True


def _gcd(a, b):
    """Calculate the greatest common divisor of a and b"""
    while b:
        a, b = b, a % b
    return a


def addTag(tag):
    """
        Добавить тэг tag к сообщению.

        @param tag: тэг
        @type tag: C{str}
        """


def fromqpixmap(im):
    """Creates an image instance from a QPixmap image"""
    from . import ImageQt
    if not ImageQt.qt_is_installed:
        raise ImportError('Qt bindings are not installed')
    return ImageQt.fromqpixmap(im)


def first(iterable):
    """ Returns the first element in the iterable or None if it doesn't exist. """
    for element in iterable:
        return element
    return None


def is_kernelspec_model(spec_dict):
    """Returns True if spec_dict is already in proper form.  This will occur when using a gateway."""
    return (isinstance(spec_dict, dict) and 'name' in spec_dict and 'spec' in
        spec_dict and 'resources' in spec_dict)


def select_nth(nth: int=2, skip: int=1, offset: int=0):
    """Deselect every Nth element starting from the active vertex, edge or face

    :param nth: Nth Selection
    :type nth: int
    :param skip: Skip
    :type skip: int
    :param offset: Offset
    :type offset: int
    """
    pass


@staticmethod
def _is_cjk_character(ch):
    """CJK类字符判断（包括中文字符也在此列）
        参考：https://en.wikipedia.org/wiki/CJK_Unified_Ideographs_(Unicode_block)
        """
    code = ord(ch)
    return (19968 <= code <= 40959 or 13312 <= code <= 19903 or 131072 <=
        code <= 173791 or 173824 <= code <= 177983 or 177984 <= code <=
        178207 or 178208 <= code <= 183983 or 63744 <= code <= 64255 or
        194560 <= code <= 195103)


def remove_namespaces(xml):
    """Remove the namespaces from an
    ``etree.Element`` object and return
    the modified object.
    """
    for elem in xml.getiterator():
        split_elem = elem.tag.split('}')
        if len(split_elem) > 1:
            elem.tag = split_elem[1]
    return xml


def check_dimension_names(dimensions):
    """
    Check whether all dimensions have names. Raises `ValueError`,
    if one or more dimensions are unnamed.

    Parameters
    ----------
    dimensions : list(Dimension)
        List of Dimension-objects.

    """
    err_dims = list(filter(lambda dim: dim.name is None, dimensions))
    if len(err_dims) > 0:
        msg = 'All dimensions must have names, but found: {}'
        msg = msg.format(err_dims)
        raise ValueError(msg)


@classmethod
def get_table_names(cls, inspector, schema):
    """Need to disregard the schema for Sqlite"""
    return sorted(inspector.get_table_names())


def _cdp_split_single_times_read_aligns(split_alignment_dict, pos):
    """
    Dict. of times a read aligns to all references
    {read: times aligned}
    """
    srna_align_counts = {}
    for aligned_sRNAs in list(split_alignment_dict.values())[pos]:
        for aligned_sRNA, count in aligned_sRNAs.items():
            if aligned_sRNA in srna_align_counts:
                srna_align_counts[aligned_sRNA][pos] += count
            else:
                srna_align_counts[aligned_sRNA][pos] = count
    return srna_align_counts


def listify(o):
    """Ensure an object is a list by wrapping if necessary"""
    if isinstance(o, list):
        return o
    return [o]


def get_thing_shadow(thingName=None):
    """
    Gets the thing shadow for the specified thing.
    For more information, see GetThingShadow in the AWS IoT Developer Guide .
    See also: AWS API Documentation

    :example: response = client.get_thing_shadow(
        thingName='string'
    )

    :type thingName: string
    :param thingName: [REQUIRED]
            The name of the thing.

    :rtype: dict
    :return: {
        'payload': StreamingBody()
    }

    """
    pass


def magnitude2cps(magnitude, magnitude_zero_point):
    """
    converts an apparent magnitude to counts per second

    The zero point of an instrument, by definition, is the magnitude of an object that produces one count
    (or data number, DN) per second. The magnitude of an arbitrary object producing DN counts in an observation of
    length EXPTIME is therefore:
    m = -2.5 x log10(DN / EXPTIME) + ZEROPOINT

    :param magnitude:
    :param magnitude_zero_point:
    :return: counts per second
    """
    delta_M = magnitude - magnitude_zero_point
    counts = 10 ** (-delta_M / 2.5)
    return counts


def add_subject(subject, parent):
    """Adds a subject to the tree of subjects.

        Subject is added under parent. If parent is None, the subject
        is added to the root.
        """


def domino_field_iter_items(resource, fields, required_field_names=None,
    skip_null_values=False):
    """
    Return an iterator that yields fields and their values from a resource.

    :param resource: Resource to iterate over.
    :param fields: Fields to use
    :param required_field_names: Fields that must be included (even if null) eg Key Fields
    :param skip_null_values: Skip values that are Null or None (as this is a special case in DynamoDB)
    :returns: an iterator that returns (field, value) tuples.

    """
    required_field_names = required_field_names or []
    for f in fields:
        value = f.value_from_object(resource)
        if (skip_null_values and f.name not in required_field_names and
            value in [None, '']):
            continue
        yield f, f.prepare_dynamo(value)


def get_suite():
    """Get unittest suite for this module"""
    import doctest
    import sys
    return doctest.DocTestSuite(sys.modules[__name__])


def file_as_bytes(path: str) ->bytes:
    """Read in a file as a byte array."""
    with open(path, 'rb') as f:
        return f.read()