def pin2name(id: int) ->str:
    """Convert pin number to name"""
    if not isinstance(id, int):
        raise TypeError('id must be a non-negative integer')
    if id < 0:
        raise ValueError('id must be a non-negative integer')
    ports = 'ABCDEFGHIJKL'
    port_num = id // 32
    pin_num = id - port_num * 32
    if pin_num >= 32:
        raise ValueError('id out of range')
    try:
        return 'P{}{}'.format(ports[port_num], pin_num)
    except IndexError:
        raise ValueError('id out of range')


def print_dup(original, duplicate, m):
    """A callback that just prints the duplicate pair."""
    print('\n- ORIG:  {}\n  DUPL:  {}'.format(str(original), str(duplicate)))


@classmethod
def GetAnalyzerInstances(cls, analyzer_names):
    """Retrieves instances for all the specified analyzers.

    Args:
      analyzer_names (list[str]): names of the analyzers to retrieve.

    Returns:
      list[BaseAnalyzer]: analyzer instances.
    """
    analyzer_instances = []
    for analyzer_name, analyzer_class in iter(cls.GetAnalyzers()):
        if analyzer_name in analyzer_names:
            analyzer_instances.append(analyzer_class())
    return analyzer_instances


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

        :param FileTransfersTransferDownloadType val:
        :rtype: EventType
        """
    return cls('file_transfers_transfer_download', val)


def context_cycle_array(data_path: str='', reverse: bool=False):
    """Set a context array value (useful for cycling the active mesh edit mode)

    :param data_path: Context Attributes, RNA context string
    :type data_path: str
    :param reverse: Reverse, Cycle backwards
    :type reverse: bool
    """
    pass


@classmethod
def get_session_class(cls, interface_type, resource_class):
    """Return the session class for a given interface type and resource class.

        :type interface_type: constants.InterfaceType
        :type resource_class: str
        :return: Session
        """
    try:
        return cls._session_classes[interface_type, resource_class]
    except KeyError:
        raise ValueError('No class registered for %s, %s' % (interface_type,
            resource_class))


def _get_obj_location(ds, srcfile, hash_str):
    """Determine the location of a metadata object in a dataset's object store

    Parameters
    ----------
    ds : Dataset
      The reference dataset whose store shall be used.
    srcfile : Path
      The path of the object's sourcefile (to determine the correct
      file extension.
    hash_str : str
      The hash the object should be stored under.

    Returns
    -------
    Path
      pathlib Path instance to the absolute location for the metadata object
    """
    objpath = ds.pathobj / '.datalad' / 'metadata' / 'objects' / hash_str[:2
        ] / (hash_str[2:] + srcfile.suffix)
    return objpath


def IPtoString(ip_number):
    """
    Converts an IP address from an integer to dotted decimal notation.
    Args:
        ip_number: an unsigned 32-bit integer representing an IP address

    Returns: The IP address as a dotted-decimal string.

    """
    return '{0}.{1}.{2}.{3}'.format((ip_number & 4278190080) >> 24, (
        ip_number & 16711680) >> 16, (ip_number & 65280) >> 8, ip_number & 255)


def str_reduce(msg, maxwidth):
    """ Reduce a string with dots (...) if its length is greater than maxwidth """
    if len(msg) >= maxwidth:
        return msg[:maxwidth - 3] + '...'
    else:
        return msg


def filter_center_line(center_line):
    """Filter center line marks by the number of points they contain to find road
    marks that form the center line.

    Args:
        center_line (list): list of center line marks.

    Returns:
        A list of filtered center line marks.
    """
    filtered_center_line = []
    for road_mark in center_line:
        if road_mark.size > 70 or road_mark.size < 30:
            continue
        filtered_center_line.append(road_mark)
    return filtered_center_line


@staticmethod
def read(reader, _index):
    """
        Reads Zserio varuint32 type from the bit stream.

        :param reader: Bit stream from which to read.
        :param _index: Not used.
        """
    return reader.readVarUInt32()


@classmethod
def mongo_config_for_collection(cls, collection_name: str=None):
    """
        Return a configuration object of MongoDBManager for given collection_name
        If collection_name in any configuration file then use the configured collection_name
        Else use the given collection_name instead
        """
    if collection_name is None:
        collection_name = cls.COLLECTION_NAME
    if not getattr(cls, collection_name, False):
        collection_name = collection_name
    else:
        collection_name = getattr(cls, collection_name)
    return {'MONGODB_URI': cls.MONGODB_URI, 'DB_NAME': cls.DB_NAME,
        'COLLECTION_NAME': collection_name}


def deserialize_date(string):
    """Deserializes string to date.

    :param string: str.
    :type string: str
    :return: date.
    :rtype: date
    """
    try:
        from dateutil.parser import parse
        return parse(string).date()
    except ImportError:
        return string


@classmethod
def parseKwargs(cls, config_model, logger=None):
    """Parse the model field of a configuration dict and return the kwargs to use for
        initializing an instance of the class.

        The base class implementation just returns the kwargs as they are, but derived classes
        might want to override this if they need to do something more sophisticated with them.

        :param config_model:    The model field of the configuration dict, config['model']
        :param logger:          A logger object for logging debug info. [default: None]

        :returns: a kwargs dict to pass to the initializer
        """
    kwargs = {}
    kwargs.update(config_model)
    kwargs.pop('type', None)
    return kwargs


def enable_ph(module, array):
    """Enable Remote Assist"""
    changed = False
    if array.get_phonehome()['phonehome'] != 'enabled':
        try:
            if not module.check_mode:
                array.enable_phonehome()
            changed = True
        except Exception:
            module.fail_json(msg='Enabling Phonehome failed')
    module.exit_json(changed=changed)


def dispatch_hook(key, hooks, hook_data, **kwargs):
    """Dispatches a hook dictionary on a given piece of data."""
    hooks = hooks or {}
    hooks = hooks.get(key)
    if hooks:
        if hasattr(hooks, '__call__'):
            hooks = [hooks]
        for hook in hooks:
            _hook_data = hook(hook_data, **kwargs)
            if _hook_data is not None:
                hook_data = _hook_data
    return hook_data


def deserialize_datetime(string):
    """Deserializes string to datetime.

    The string should be in iso8601 datetime format.

    :param string: str.
    :type string: str
    :return: datetime.
    :rtype: datetime
    """
    try:
        from dateutil.parser import parse
        return parse(string)
    except ImportError:
        return string


@classmethod
def is_imported(cls, importer):
    """Check whether the import was triggered.

        This inspection is a save and doesn't trigger the import.

        Parameters
        ----------
        importer : LazyImport
            The object to check.

        Returns
        -------
        flag : bool
            True if the import was triggered, else false.

        Examples
        --------
        >>> from ptvpy._cli_utils import LazyImport
        >>> math = LazyImport("math")
        >>> LazyImport.is_imported(math)
        False
        >>> math.__name__
        'math'
        >>> LazyImport.is_imported(math)
        True
        """
    if not isinstance(importer, cls):
        raise TypeError(f'must be of type {cls}, was {type(importer)}')
    return 'module' in object.__getattribute__(importer, '__dict__')


def get_example_usage(services, host, port):
    """ Gets example usage of given services.
    """
    example_usages = {}
    for service in services:
        if service.lower() == 'ping':
            example_usages[service] = "21 buy '{}:{}/ping/?uri=21.co'".format(
                host, port)
    return example_usages


def create_task_info(task):
    """Create task_info field."""
    task_info = None
    if task.get('info'):
        task_info = task['info']
    else:
        task_info = task
    return task_info


def get_root(region_parent_zip, region_id):
    """
    Return the penultimate `parent_id` for any `region_id`.

    The penultimate parent is one layer below the root (0).
    The set of penultimate parents are the distinct regions contained in the segmentation.
    They correspond to putative functional regions.

    :param tuple region_parent_zip: a list of 2-tuples of `region_ids` and `parent_ids`
    :param int region_id: the `region_id` whose root parent_id is sought
    :return int parent_id: the corresponding penultimate `parent_id` (one step below the root - value of `0`)
    """
    if region_id == 0:
        return 0
    region_parent_dict = dict(region_parent_zip)
    while region_parent_dict[region_id] != 0:
        region_id = region_parent_dict[region_id]
    parent_id = region_id
    return parent_id


def get_class(cls, name=None):
    """Obtain the class for some (named) service

            In a shortened example::

                class Foo(Base):
                    _name = 'foo'

                assert Base.get_class('foo') == Foo
        """
    if name is None:
        name = '*'
    svc_classes = getattr(cls, '__service_classes', None)
    if svc_classes is None:
        for b in cls.__mro__:
            svc_classes = getattr(b, '__service_classes', None)
            if svc_classes is not None:
                break
    if svc_classes is None:
        raise RuntimeError('No base service class for %s' % cls.__name__)
    if isinstance(name, (list, tuple)):
        for n in name:
            base_class = svc_classes.get(n, None)
            if base_class is not None:
                break
    else:
        base_class = svc_classes.get(name, None)
    if base_class is None:
        raise TypeError('No %s class with name: %s' % (cls.__name__, name))
    return base_class


def ampersand_parse(sas_input_lines, DF):
    """
    A function to parse the data if they are of the form @START VARNAME.

    Parameters
    ----------
    sas_input_lines :   list of strings; the cleanedsas variable file
    DF              :   DataFrame; the dataframe to fill

    """
    i = j = 0
    while i < len(sas_input_lines):
        start_point = int(sas_input_lines[i].replace('@', ''))
        if i > 0:
            if DF['start'][j - 1] + DF['width'][j - 1] < start_point:
                DF['width'][j] = DF['start'][j - 1] + DF['width'][j - 1
                    ] - start_point
                j += 1
        DF['start'][j] = start_point
        DF['varname'][j] = sas_input_lines[i + 1]
        if sas_input_lines[i + 2] == '$':
            DF['char']['j'] = True
            i += 1
        else:
            DF['char'][j] = False
        for k in ['F', 'CHAR']:
            sas_input_lines[i + 2] = sas_input_lines[i + 2].replace(k, '')
        try:
            if sas_input_lines[i + 2].find('.') >= 0:
                period = sas_input_lines[i + 2].find('.')
                DF['width'][j] = int(sas_input_lines[i + 2][0:period])
                DF['divisor'][j] = 1 / 10 ** int(sas_input_lines[period + 1:])
        except IndexError:
            pass
        else:
            DF['width'][j] = int(sas_input_lines[i + 2])
            DF['divisor'][j] = 1
        i += 3
        j += 1
    return DF


@classmethod
def from_str(cls, strvalue):
    """Parses a string value (`strvalue`) to ``Level``."""
    strvalue = strvalue.lower()
    if strvalue == 'toy':
        return cls.TOY
    elif strvalue == 'medium':
        return cls.MEDIUM
    elif strvalue == 'realworld':
        return cls.REALWORLD
    else:
        raise ValueError("Unrecognized level value '{}' provided.".format(
            strvalue))


def required(label, field, data, **kwargs):
    """Validates presence value.
    - when bool, return True
    - when None, return False,
    - when inexistent key, return False
    """
    if not field in data:
        return False
    value = data[field]
    if value == None:
        return False
    elif type(value) is bool:
        return True
    elif not value:
        return False
    return True


@classmethod
def attempt_convert_uuid_hex_to_bytes(cls, value):
    """Attempt to convert value to bytes or return value.

        :param value: value to attempt to convert to bytes
        :returns: tuple containing boolean indicating whether user_id was
                  stored as bytes and uuid value as bytes or the original value

        """
    try:
        return True, cls.convert_uuid_hex_to_bytes(value)
    except ValueError:
        return False, value


def load(path):
    """
    from baiji.pod.util import json
    foo = json.load('foo.json')
    """
    import simplejson as json
    with open(path, 'r') as f:
        return json.load(f)


def index_to_temporalID(index, snapnum, index_mult_factor):
    """
    Takes snapshot-local halo index and converts into temporally unique ID.

    Note: IDs start counting at 1.  So the index 0 gets mapped to an ID of 1.

    Parameters
    ----------

    index: array-like of integers, or integer.
        Array or single value that describes the snapshot-local haloID.

    snapnum: Integer.
        Snapshot that the halo/s are/is located at.

    index_mult_factor: Integer.
        Factor to convert a the snapshot-unique halo index to a temporally
        unique halo ID.

    Returns
    ----------

    index: array-like of integers, or integer.
        Array or single value that contains the temporally unique haloID.

    Examples
    ----------

    >>> index_to_temporalID(23, 18, 1e12)
    18000000000024
    """
    temporalID = snapnum * int(index_mult_factor) + index + 1
    return temporalID


def _issubclass(cls, classinfo):
    """
    issubclass() variant that doesn't raise an exception if cls isn't a
    class.
    """
    try:
        return issubclass(cls, classinfo)
    except TypeError:
        return False


def create_operation(cls, a, b):
    """Create operation between a and b, merging if a or b is already an operation of same class
    """
    operands = []
    operands.extend(a.operands if isinstance(a, cls) else [a])
    operands.extend(b.operands if isinstance(b, cls) else [b])
    return cls(*operands)


@classmethod
def create(cls, data):
    """
        Create a new collection.

        :param data: The source dictionary
        :type  data: dict
        :rtype: namedtuple
        """
    return cls(data).get()


@classmethod
def _get_minimum_frames(cls):
    """Get minimum frames."""
    return 10


def Letter():
    """Return the position (starting with "A") within the iteration
        """


def init_pattern(elements):
    """init_pattern(list) -> string

    Creates pattern from list sorted by length in descending order.

    """
    items = sorted(elements, key=lambda a: len(a), reverse=True)
    pattern = '|'.join(items)
    return pattern


def __timeout_handler(signum, frame):
    """Helper function for the timeout() function."""
    raise TimeoutError()


@staticmethod
def _get_name():
    """
        Get the name of the extractor.
        :return: the name of the extractor
        """
    return 'Toulligqc extractors'


def read_version(fn):
    """Extract mirGFF3 version"""
    with open(fn) as inh:
        for line in inh:
            if line.find('VERSION') > -1:
                return line.split('VERSION')[1].strip()
            if not line.startswith('#'):
                ValueError(
                    'Version not found in the header.A valid file should have a line like this:## mirGFF3. VERSION X.X'
                    )


def create_bot_version(name=None, checksum=None):
    """
    Creates a new version of the bot based on the $LATEST version. If the $LATEST version of this resource hasn't changed since you created the last version, Amazon Lex doesn't create a new version. It returns the last created version.
    When you create the first version of a bot, Amazon Lex sets the version to 1. Subsequent versions increment by 1. For more information, see  versioning-intro .
    This operation requires permission for the lex:CreateBotVersion action.
    See also: AWS API Documentation

    :example: response = client.create_bot_version(
        name='string',
        checksum='string'
    )

    :type name: string
    :param name: [REQUIRED]
            The name of the bot that you want to create a new version of. The name is case sensitive.

    :type checksum: string
    :param checksum: Identifies a specific revision of the $LATEST version of the bot. If you specify a checksum and the $LATEST version of the bot has a different checksum, a PreconditionFailedException exception is returned and Amazon Lex doesn't publish a new version. If you don't specify a checksum, Amazon Lex publishes the $LATEST version.

    :rtype: dict
    :return: {
        'name': 'string',
        'description': 'string',
        'intents': [
            {
                'intentName': 'string',
                'intentVersion': 'string'
            },
        ],
        'clarificationPrompt': {
            'messages': [
                {
                    'contentType': 'PlainText'|'SSML',
                    'content': 'string'
                },
            ],
            'maxAttempts': 123,
            'responseCard': 'string'
        },
        'abortStatement': {
            'messages': [
                {
                    'contentType': 'PlainText'|'SSML',
                    'content': 'string'
                },
            ],
            'responseCard': 'string'
        },
        'status': 'BUILDING'|'READY'|'FAILED'|'NOT_BUILT',
        'failureReason': 'string',
        'lastUpdatedDate': datetime(2015, 1, 1),
        'createdDate': datetime(2015, 1, 1),
        'idleSessionTTLInSeconds': 123,
        'voiceId': 'string',
        'checksum': 'string',
        'version': 'string',
        'locale': 'en-US',
        'childDirected': True|False
    }

    """
    pass


@classmethod
def load(cls, context, compiled_net, batch_index):
    """Add runtime information to instruction nodes.

        Parameters
        ----------
        context : ComputationContext
        compiled_net : nx.DiGraph
        batch_index : int

        Returns
        -------
        net : nx.DiGraph
            Loaded net, which is the `compiled_net` that has been loaded with data that
            can depend on the batch_index.

        """
    meta_dict = {'batch_index': batch_index, 'submission_index': context.
        num_submissions, 'master_seed': context.seed, 'model_name':
        compiled_net.graph['name']}
    details = dict(_batch_size=context.batch_size, _meta=meta_dict)
    for node, v in details.items():
        if compiled_net.has_node(node):
            compiled_net.node[node]['output'] = v
    return compiled_net


def checkDictArray(d, a):
    """Make sure that every key in a d is in a"""
    for k in d.keys():
        if not k in a:
            raise Exception(k + ' is not present in ' + str(a))


def Gmat2A(G):
    """Extract A from reciprocal metric tensor (G)

    :param G: reciprocal maetric tensor (3x3 numpy array
    :return: A = [G11,G22,G33,2*G12,2*G13,2*G23]

    """
    return [G[0][0], G[1][1], G[2][2], 2.0 * G[0][1], 2.0 * G[0][2], 2.0 *
        G[1][2]]


@classmethod
def delete_entry(cls, db, dow, time, zone):
    """ Remove entries for all zones at a specified day/time.

        dow is the day of week, counting from 0 being Monday. """
    cursor = db.cursor()
    cursor.execute(
        'delete from schedule where day=%s and starttime=%s and zone=%s', (
        dow, time, zone))


def get_c_init(r, name, sub):
    """
    Wrapper around c_init that initializes py_name to Py_None.

    """
    pre = (
        """
    py_%(name)s = Py_None;
    {Py_XINCREF(py_%(name)s);}
    """ %
        locals())
    return pre + r.type.c_init(name, sub)


def escape_backslash(s: str) ->str:
    """Replaces any \\ character with \\\\"""
    return s.replace('\\', '\\\\')


def write_profile_exp(name, b1_ppm, mag_exp, mag_err, file_):
    """Write the experimental CEST profile."""
    file_.write('[{}]\n'.format(name.upper()))
    file_.write('# {:>17s}   {:>17s} {:>17s}\n'.format('OFFSET',
        'INTENSITY', 'UNCERTAINTY'))
    for b1_ppm_, mag_exp_, mag_err_ in zip(b1_ppm, mag_exp, mag_err):
        file_.write('  {0:17.8e} = {1:17.8e} {2:17.8e}\n'.format(b1_ppm_,
            mag_exp_, mag_err_))
    file_.write('\n')


def _format_field_name(attr):
    """Format an object attribute in a human-friendly way."""
    parts = attr.rsplit(':', 1)
    name = parts[-1].replace('_', ' ')
    if name.isupper() or name.islower():
        name = name.title()
    parts[-1] = name
    return ': '.join(parts)


def info_experiment(api, list_id=False, site=None, **selections):
    """ Print testbed information for user experiment submission:
    * nodes description
    * nodes description in short mode

    :param api: API Rest api object
    :param list_id: By default, return full nodes list, if list_id
        return output in exp_list format '3-12+42'
    :param site: Restrict informations collection on site
    :param **selections: other selections than site
    """
    return api.get_nodes(list_id, site, **selections)


def _get_next(request):
    """
    The part that's the least straightforward about views in this module is
    how they determine their redirects after they have finished computation.

    In short, they will try and determine the next place to go in the
    following order:

    1. If there is a variable named ``next`` in the *POST* parameters, the
       view will redirect to that variable's value.
    2. If there is a variable named ``next`` in the *GET* parameters,
       the view will redirect to that variable's value.
    3. If Django can determine the previous page from the HTTP headers,
       the view will redirect to that previous page.
    """
    next = request.POST.get('next', request.GET.get('next', request.META.
        get('HTTP_REFERER', None)))
    if not next:
        next = request.path
    return next


def delete_queue(env, queue_name):
    """
    Delete the queue
    """
    env.sqs_resource.get_queue_by_name(QueueName=env.get_sqs_queue_name(
        queue_name)).delete()


@classmethod
def get(cls, debug, raw):
    """
        @type  debug: L{Debug}
        @param debug: Debug object that received the event.

        @type  raw: L{DEBUG_EVENT}
        @param raw: Raw DEBUG_EVENT structure as used by the Win32 API.

        @rtype: L{Event}
        @returns: An Event object or one of it's subclasses,
            depending on the event type.
        """
    eventClass = cls.eventClasses.get(raw.dwDebugEventCode, cls.baseEvent)
    return eventClass(debug, raw)


@classmethod
def update(cls, ob, plus_ob):
    """
        Update single object
        :param ob: Object or list of objects containing `objectId` attribute
        :param plus_ob: -d json.dumps(plus_ob)
                        -d '{"score":73453}'                         -d '{"opponents":{"__op":"Delete"}}'                         -d '{"score":{"__op":"Increment","amount":1}}'                         -d '{"skills":{"__op":"AddUnique/ Add/ Remove","objects":["flying","kungfu"]}}'                         -d '{"opponents":{
                                "__op":"AddRelation/ RemoveRelation",
                                "objects":[{"__type":"Pointer","className":"Player","objectId":"51b0f0e851c16221"}]}
                            }'         :return: {"updatedAt":"...","objectId":"..."}
        """
    return cls._update_avos(cls.__name__, ob, plus_ob)


def _mesh_shape_iterator(num_machines, max_mesh_shape_dimensions=None):
    """Iterable of mesh shapes that use a certain number of machines.

  Args:
    num_machines: integer, a power of two, the number of machines available.
    max_mesh_shape_dimensions: optional integer, the maximum number of
        dimensions to consider in any layout.

  Yields:
    [int], the dimension sizes of a mesh shape.
  """
    if num_machines == 1:
        yield [1]
        return
    current_product = num_machines
    mesh_shape = [num_machines]
    while True:
        if max_mesh_shape_dimensions is None or len(mesh_shape
            ) <= max_mesh_shape_dimensions:
            yield list(mesh_shape)
        while mesh_shape[-1] == 2:
            current_product //= mesh_shape.pop()
            if not mesh_shape:
                return
        mesh_shape[-1] //= 2
        current_product //= 2
        while current_product < num_machines:
            mesh_shape.append(min(mesh_shape[-1], num_machines //
                current_product))
            current_product *= mesh_shape[-1]


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

        :param TeamProfileAddLogoDetails val:
        :rtype: EventDetails
        """
    return cls('team_profile_add_logo_details', val)


def hcp_diamond_coord_test(x, y, z):
    """Test for coordinate in HCP diamond grid"""
    for pt in [[0, 0, 0], [3, 3, 3], [6, 0, 6], [9, 3, 9]]:
        tx = x - pt[0]
        ty = y - pt[1]
        tz = z - pt[2]
        s = tx + ty + tz
        if s % 24 == 0:
            n8 = s // 3
            if (tx - n8) % 6 == 0 and (ty - n8) % 6 == 0 and (tz - n8
                ) % 6 == 0:
                return True
    return False


def SetDefaultSASDModel():
    """Fills in default items for the SASD Models dictionary"""
    return {'Back': [0.0, False], 'Size': {'MinDiam': 50, 'MaxDiam': 10000,
        'Nbins': 100, 'logBins': True, 'Method': 'MaxEnt', 'Distribution':
        [], 'Shape': ['Spheroid', 1.0], 'MaxEnt': {'Niter': 100,
        'Precision': 0.01, 'Sky': -3}, 'IPG': {'Niter': 100, 'Approach':
        0.8, 'Power': -1}, 'Reg': {}}, 'Pair': {'Method': 'Moore',
        'MaxRadius': 100.0, 'NBins': 100, 'Errors': 'User', 'Percent error':
        2.5, 'Background': [0, False], 'Distribution': [], 'Moore': 10,
        'Dist G': 100.0, 'Result': []}, 'Particle': {'Matrix': {'Name':
        'vacuum', 'VolFrac': [0.0, False]}, 'Levels': []}, 'Shapes': {
        'outName': 'run', 'NumAA': 100, 'Niter': 1, 'AAscale': 1.0, 'Symm':
        1, 'bias-z': 0.0, 'inflateV': 1.0, 'AAglue': 0.0, 'pdbOut': False,
        'boxStep': 4.0}, 'Current': 'Size dist.', 'BackFile': ''}


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

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


def version_tuple(version):
    """ Returns a tuple from version string """
    return tuple(version.split('.'))


def parse_screenshot_src(img):
    """
    The screenshot img element's src isn't always present, and sometimes is set
    to a base64 encoded empty image because they're normally hidden in the
    scrollable carousel, for purposes of saving bandwidth and faster loading.

    Instead, it seems like we can grab the src url from data-src in those cases.

    :param img: the img bs4 element
    :return: the src url string
    """
    src = img.attrs.get('src')
    if src is None or not src.startswith('https://'):
        src = img.attrs.get('data-src')
    return src


def trim_members_all(tap_stream_id):
    """
    E.g. returns groups for groups_all
    """
    return tap_stream_id.split('_')[0]


def snake(s):
    """
    Converts an input string in PascalCase to snake_case.
    """
    snek = []
    prev_up = False
    prev_alnum = False
    for idx, c in enumerate(s):
        alnum = c.isalnum()
        up = c.isupper()
        next_up = s[idx + 1].isupper() if idx + 1 < len(s) else False
        if (up and not prev_up and prev_alnum and idx != 0 or up and
            prev_up and not next_up and idx != len(s)):
            snek.append('_')
        snek.append(c.lower())
        prev_alnum = alnum
        prev_up = up
    return ''.join(snek)


def shell_escape(command):
    """
    Escape special characters from a command so that it can be passed
    as a double quoted (" ") string in a (ba)sh command.

    :param command: the command string to escape.

    :return: The escaped command string. The required englobing double
            quotes are NOT added and so should be added at some point by
            the caller.

    See also: http://www.tldp.org/LDP/abs/html/escapingsection.html
    """
    command = command.replace('\\', '\\\\')
    command = command.replace('$', '\\$')
    command = command.replace('"', '\\"')
    command = command.replace('`', '\\`')
    return command


def get_suitable_int_type(upper: int, lower: int=0) ->str:
    """Returns the suitable integer type with the least bits.

  Returns the integer type that can hold all values between max_val and min_val
  (inclusive) and has the least bits.

  Args:
    max_val: Maximum value that needs to be valid.
    min_val: Minimum value that needs to be valid.

  Returns:
    The suitable type.
  """
    assert upper >= lower
    upper = max(upper, 0)
    lower = min(lower, 0)
    if lower == 0:
        return 'uint%d' % upper.bit_length()
    return 'int%d' % (max(upper.bit_length(), (lower + 1).bit_length()) + 1)


def get_layer_input_shape_shape5(layer):
    """Convert a keras shape to an fdeep shape"""
    shape = layer.input_shape[1:]
    depth = len(shape)
    if depth == 1:
        return 1, 1, 1, 1, shape[0]
    if depth == 2:
        return 1, 1, 1, shape[0], shape[1]
    if depth == 3:
        return 1, 1, shape[0], shape[1], shape[2]
    if depth == 4:
        return 1, shape[0], shape[1], shape[2], shape[3]
    if depth == 5:
        return shape
    raise ValueError('invalid number of dimensions')


def is_hybi00(headers):
    """
    Determine whether a given set of headers is HyBi-00-compliant.

    Hixie-76 and HyBi-00 use a pair of keys in the headers to handshake with
    servers.
    """
    return 'Sec-WebSocket-Key1' in headers and 'Sec-WebSocket-Key2' in headers


def print_plugin(plugin, namefield='longName'):
    """Print the plugin longName and version."""
    print('%s:%s' % (plugin[namefield], plugin['version']))


def to_pyrocko_trace(trace):
    """
    Convert ObsPy trace object to Pyrocko trace object.

    :param trace:
        :py:class:`obspy.Trace <obspy.core.trace.Trace>` object
    :returns:
        :py:class:`pyrocko.trace.Trace` object
    """
    obspy_trace = trace
    from pyrocko import trace
    return trace.Trace(str(obspy_trace.stats.network), str(obspy_trace.
        stats.station), str(obspy_trace.stats.location), str(obspy_trace.
        stats.channel), tmin=obspy_trace.stats.starttime.timestamp, tmax=
        obspy_trace.stats.endtime.timestamp, ydata=obspy_trace.data, deltat
        =obspy_trace.stats.delta)


def psi_K_HCO3_HSO4_HMW84(T, P):
    """c-a-a': potassium bicarbonate bisulfate [HMW84]."""
    psi = 0.0
    valid = T == 298.15
    return psi, valid


def linear(x, weights):
    """A linear interaction.

    :param x:
        shape ``(batch_size, in_features)``
    :param weights:
        shape ``(n_factors, in_features, out_features)``
    """
    return x @ weights


def drop_edge_punct(word: str) ->str:
    """
    Remove edge punctuation.
    :param word: a single string
    >>> drop_edge_punct("'fieri")
    'fieri'
    >>> drop_edge_punct('sedes.')
    'sedes'
    """
    if not word:
        return word
    try:
        if not word[0].isalpha():
            word = word[1:]
        if not word[-1].isalpha():
            word = word[:-1]
    except:
        pass
    return word


@staticmethod
def valid_fields():
    """Valid fields to sort a table of cards by"""
    return ['name', 'list', 'tags', 'desc', 'due', 'activity', 'id', 'url']


def parse_config_basic(config):
    """Parse basic options from the configuration file."""
    options = {}
    if config.has_option('cutsky', 'npix'):
        options['npix'] = config.getint('cutsky', 'npix')
    if config.has_option('cutsky', 'pixsize'):
        options['pixsize'] = config.getfloat('cutsky', 'pixsize')
    for key in ['coordframe', 'ctype', 'outdir']:
        if config.has_option('cutsky', key):
            options[key] = config.get('cutsky', key)
    return options


@staticmethod
def standard_scale(data2d, axis=1):
    """Divide the data by the difference between the max and min

        Parameters
        ----------
        data2d : pandas.DataFrame
            Data to normalize
        axis : int
            Which axis to normalize across. If 0, normalize across rows, if 1,
            normalize across columns.
        vmin : int
            If 0, then subtract the minimum of the data before dividing by
            the range.

        Returns
        -------
        standardized : pandas.DataFrame
            Noramlized data with a mean of 0 and variance of 1 across the
            specified axis.

        """
    if axis == 1:
        standardized = data2d
    else:
        standardized = data2d.T
    subtract = standardized.min()
    standardized = (standardized - subtract) / (standardized.max() -
        standardized.min())
    if axis == 1:
        return standardized
    else:
        return standardized.T


def splitCouchServiceURL(serviceURL):
    """
    split service URL to couchURL and couchdb name
    serviceURL should be couchURL/dbname format.
    """
    splitedURL = serviceURL.rstrip('/').rsplit('/', 1)
    return splitedURL[0], splitedURL[1]


def enforce_at_least(version):
    """Assert that the current Python version is equal or higher than *version*."""
    assert version.at_least(), 'Requires at least Python ' + str(version)


def demeshgrid(arr):
    """Turns an ndarray created by a meshgrid back into a 1D array

    Parameters
    ----------
    arr : array of dimension > 1
        This array should have been created by a meshgrid.
    """
    dim = len(arr.shape)
    for i in range(dim):
        Slice1 = [0] * dim
        Slice2 = [1] * dim
        Slice1[i] = slice(None)
        Slice2[i] = slice(None)
        if (arr[tuple(Slice1)] == arr[tuple(Slice2)]).all():
            return arr[tuple(Slice1)]


def _get_association_nodes(digraph, sub, predicate, obj):
    """
    Given a subject, predicate, object, retrieve the OBAN association
    node from the evidence graph
    """
    subject_assocs = set()
    object_assocs = set()
    predicate_assocs = set()
    union_assoc = set()
    if predicate['pred'] in digraph.node:
        for neighbor, edges in digraph.pred[sub].items():
            for edge in edges.values():
                if edge['pred'] == 'OBAN:association_has_subject':
                    subject_assocs.add(neighbor)
        for neighbor, edges in digraph.pred[obj].items():
            for edge in edges.values():
                if edge['pred'] == 'OBAN:association_has_object':
                    object_assocs.add(neighbor)
        for neighbor, edges in digraph.pred[predicate['pred']].items():
            for edge in edges.values():
                if edge['pred'] == 'OBAN:association_has_predicate':
                    predicate_assocs.add(neighbor)
        union_assoc = subject_assocs & object_assocs & predicate_assocs
    return union_assoc


def get_regex_pattern(urlpattern):
    """
    Get the raw regex out of the urlpattern's RegexPattern or RoutePattern. This is always a regular expression,
    unlike get_original_route above.
    """
    if hasattr(urlpattern, 'pattern'):
        return urlpattern.pattern.regex.pattern
    else:
        return urlpattern.regex.pattern


def add(item, score):
    """Record that item 'item' has score 'score'.  No return value.

        The N best-scoring items are remembered, where N was passed to
        the constructor.  'item' can by anything.  'score' should be
        a number, and larger numbers are considered better.
        """


def values_exist(expected: set, actual: set) ->bool:
    """
    Check the expected worksheets exist.
    :return:
    """
    return expected <= actual


@staticmethod
def p_ref_measurement_optional_list_optional(p):
    """ref_measurement_optional_list_optional : empty
                                                  | ref_measurement_optional_list"""
    p[0] = tuple() if p[1] is None else p[1]


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

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


def reverse_complement(seq):
    """Creates reverse complement of a DNA string."""
    seq = seq.upper()
    return seq.translate(str.maketrans('ATGCN', 'TACGN'))[::-1]


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

        :param SharingUserError val:
        :rtype: UnshareFileError
        """
    return cls('user_error', val)


def is_continuous(field_name):
    """ Given an apache log_parser field name,
        return TRUE if that field is continuous
    """
    return field_name == 'time_received'


def S_IFMT(mode):
    """Return the portion of the file's mode that describes the
    file type.
    """
    return mode & 61440


def sighandler(signum, frame):
    """
    Signal handler for exiting app.
    """
    global running
    print('Received signal {}, stopping application...'.format(signum))
    running = False


@classmethod
def __class_init__(cls, namespace):
    """
        Called when the class is created

        :param cls:       class
        :param namespace: namespace for newly created
        :type  namespace: dict
        """


def _stacktrace_end(stacktrace, size):
    """ Gets the last `size` bytes of the stacktrace """
    stacktrace_length = len(stacktrace)
    if stacktrace_length <= size:
        return stacktrace
    return stacktrace[:-(stacktrace_length - size)]


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


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

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

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


def _collapse_arches(options, pkgs):
    """Collapse arches into a single set."""
    keywords = set()
    stable_keywords = set()
    unstable_keywords = set()
    for pkg in pkgs:
        for x in pkg.keywords:
            if x[0] == '~':
                unstable_keywords.add(x[1:])
            elif x in options.arches:
                stable_keywords.add(x)
    if options.unstable:
        keywords.update(unstable_keywords)
    if options.only_unstable:
        keywords.update(unstable_keywords.difference(stable_keywords))
    if not keywords or options.stable:
        keywords.update(stable_keywords)
    return sorted(keywords.intersection(options.native_arches)) + sorted(
        keywords.intersection(options.prefix_arches))


def _plot_raw_time(value, params):
    """Deal with changed time value."""
    info = params['info']
    max_times = params['n_times'] / float(info['sfreq']) + params['first_time'
        ] - params['duration']
    if value > max_times:
        value = params['n_times'] / float(info['sfreq']) + params['first_time'
            ] - params['duration']
    if value < params['first_time']:
        value = params['first_time']
    if params['t_start'] != value:
        params['t_start'] = value
        params['hsel_patch'].set_x(value)


def source_mass(mass, redshift):
    """
    Calculate source mass parameter for mass m as:
    m_source = m / (1.0 + z)
    For a parameter m.
    """
    return mass / (1.0 + redshift)


@staticmethod
def positional_to_model(value):
    """Converts a positional argument to a model value"""
    return value


def get_mod(modulePath):
    """Import a module."""
    return __import__(modulePath, globals(), locals(), [''])


@staticmethod
def _args_to_str(args, kwargs):
    """Format arguments in appropriate way."""
    args_str = []
    kwargs_str = {}
    for arg in args:
        if isinstance(arg, int):
            args_str.append(arg)
        else:
            args_str.append(str(arg))
    for key in kwargs.keys():
        if isinstance(kwargs[key], int):
            kwargs_str[key] = kwargs[key]
        else:
            kwargs_str[key] = str(kwargs[key])
    return '(%s, %s)' % (args_str, kwargs_str)


def groupid():
    """Return group unique identifier.
        """


def theta_Ba_Na_PK74(T, P):
    """c-c': barium sodium [PK74]."""
    theta = -0.003
    valid = T == 298.15
    return theta, valid


def _create_entity_dofs(fiat_cell, num_dofs):
    """This function is ripped from FIAT/discontinuous_lagrange.py"""
    entity_dofs = {}
    top = fiat_cell.get_topology()
    for dim in sorted(top):
        entity_dofs[dim] = {}
        for entity in sorted(top[dim]):
            entity_dofs[dim][entity] = []
    entity_dofs[dim][0] = list(range(num_dofs))
    return entity_dofs


def add_pool_size(parser):
    """ Add --pool_size option to parser """
    parser.add_argument('--pool_size', help=
        'Number of simultaneous SSH connections to use when updating virtualenvs, removing logs, or tailing logs.'
        , default=10, type=int)


def override_options(options, arguments):
    """Update `options` dict with settings from `arguments`
    with the same key.
    """
    for key in options.keys():
        if getattr(arguments, key, None) is not None:
            options[key] = getattr(arguments, key)


def log(message, log_level=0, current_log_level=None):
    """
    Auxiliary function to use as log level

    :param current_log_level: Log level selected at the moment of running the program
    :type current_log_level: int

    :param message: Message to display
    :type message: basestring

    :param log_level: log level: 0-4
    :type log_level: int
    """
    from sys import stdout
    from os import environ
    if current_log_level is None:
        try:
            _current_log_level = int(environ['PLECOST_LOG_LEVEL'])
        except KeyError:
            _current_log_level = 0
    else:
        _current_log_level = current_log_level
    if log_level <= _current_log_level:
        print(message, end='')
        stdout.flush()


@classmethod
def set_render(cls, render):
    """ Define default render function

        :param render: render name (txt or tex)
        """
    cls.RENDER = render


def _to_bytes_or_false(val):
    """An internal graph to convert the input to a bytes or to False.

    The criteria for conversion is as follows and should be python 2 and 3
    compatible:
    - If val is py2 str or py3 bytes: return bytes
    - If val is py2 unicode or py3 str: return val.decode('utf-8')
    - Otherwise, return False
    """
    if isinstance(val, bytes):
        return val
    else:
        try:
            return val.encode('utf-8')
        except AttributeError:
            return False


def py_str(x):
    """convert c string back to python string"""
    return x.decode('utf-8')


def set_to(image_np, value):
    """Sets the image pixels to the given value."""
    if image_np is None or value is None:
        return None
    if isinstance(value, tuple):
        channels = 1 if image_np.ndim < 3 else image_np.shape[2]
        if len(value) < channels:
            raise ValueError(
                'Input value has less entries than image channels.')
        if channels == 1:
            image_np[:] = value[0]
        else:
            for ch in range(channels):
                image_np[:, :, (ch)] = value[ch]
    else:
        image_np[:] = value
    return image_np


@classmethod
def make_public(cls, curve_id, public_value, application):
    """Construct a U2F ECDSA public key"""
    return cls(curve_id, public_value, application)


def get_allowed_types() ->list:
    """
        get all allowed types
        """


@staticmethod
def json_converter(obj):
    """
        Returns the representation string (repr()) for objects that can't be
        converted to JSON
        """
    return str(obj)


def freestyle_lineset_remove():
    """Remove the active line set from the list of line sets

    """
    pass


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

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

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


def bdecode(block):
    """
    Decode a block descriptor to get its left and right sides and level.

    A block string consisting of (0, 1), with optionally one colon. The
    number of digits after the colon is the refinemenet level. The combined
    digits denote the binary representation of the left edge.
    """
    if ':' in block:
        level = len(block) - block.find(':') - 1
    else:
        level = 0
    bst = block.replace(':', '')
    d = float(2 ** len(bst))
    left = int(bst, 2)
    right = left + 1
    left /= d
    right /= d
    return level, left, right


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

    Always returns the same number of entries as provided, and always returns
    unique values. Case sensitive comparison by default.

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


def AR_6(dul):
    """Association release AR-6.

    On receiving P-DATA-TF during attempted association release request
    send P-DATA indication

    State-event triggers: Sta7 + Evt10

    References
    ----------
    1. DICOM Standard 2015b, PS3.8, Table 9-7, "Associate Establishment
       Related Actions"

    Parameters
    ----------
    dul : pynetdicom.dul.DULServiceProvider
        The DICOM Upper Layer Service instance for the local AE

    Returns
    -------
    str
        Sta7, the next state of the state machine
    """
    dul.to_user_queue.put(dul.primitive)
    return 'Sta7'


def mdot(matrix, benchmark_information):
    """
    Calculates a product between a matrix / matrices with shape (n1) or (a, n1) and a weight list with shape (b, n2)
    or (n2,), where n1 and n2 do not have to be the same
    """
    n1 = matrix.shape[-1]
    weights_t = benchmark_information.T
    n2 = weights_t.shape[0]
    n_smaller = min(n1, n2)
    if n1 > n2:
        matrix = matrix.T
        matrix = matrix[:n_smaller]
        matrix = matrix.T
    elif n2 > n1:
        weights_t = weights_t[:n_smaller]
    return matrix.dot(weights_t)


def __getitem__(cls, name):
    """ Access some class, through the name

            ONLY works for classes, not class objects.
            An alias for get_class()
        """
    return cls.get_class(name)


def in_file_string_replace(filename, old_string, new_string):
    """ String replacement within a text file. It is used to fix typos in
    downloaded csv file.
    The code was modified from "https://stackoverflow.com/questions/4128144/    replace-string-within-file-contents"

    Parameters
    ----------
    filename : string
        Path to the file where strings should be replaced
    old_string : str
        The string to be replaced in the file.
    new_string : str
        The new string that will replace old_string

    """
    with open(filename) as f:
        s = f.read()
    with open(filename, 'w') as f:
        s = s.replace(old_string, new_string)
        f.write(s)


@staticmethod
def read(sile, *args, **kwargs):
    """ Reads density matrix from `Sile` using `read_energy_density_matrix`.

        Parameters
        ----------
        sile : Sile, str or pathlib.Path
            a `Sile` object which will be used to read the density matrix
            and the overlap matrix (if any)
            if it is a string it will create a new sile using `get_sile`.
        * : args passed directly to ``read_energy_density_matrix(,**)``
        """
    from sisl.io import get_sile, BaseSile
    if isinstance(sile, BaseSile):
        return sile.read_energy_density_matrix(*args, **kwargs)
    else:
        with get_sile(sile) as fh:
            return fh.read_energy_density_matrix(*args, **kwargs)


@classmethod
def from_dir(cls, project_home):
    """Construct a ProjectMetadata that reads from the specified directory."""
    return cls(project_home)


def _deserialize_object(value):
    """Return a original value.

    :return: object.
    """
    return value


def validate_cert_settings(namespace):
    """Custom parsing for certificate commands - adds default thumbprint
    algorithm.
    """
    namespace.thumbprint_algorithm = 'sha1'


@staticmethod
def _key(service=None, env=None):
    """Compute a key with the same format used by the Datadog agent API."""
    service = service or ''
    env = env or ''
    return 'service:' + service + ',env:' + env


def datetime_to_clocktime(index):
    """
    Convert DataFrame index from datetime to clocktime (seconds past midnight)

    Parameters
    --------------
    index : pandas Index
        DataFrame index in datetime

    Returns
    ----------
    pandas Index
        DataFrame index in clocktime
    """
    clocktime = (index.hour * 3600 + index.minute * 60 + index.second +
        index.microsecond / 1000000.0)
    return clocktime


def machine_accuracy():
    """This function computes the accuracy of the computer being used.

    This function returns a tuple containing the number of significant bits in
    the mantissa of a floating number, and the number of significant digits in
    a decimal number.

    :returns: Number of significant bits, and of significant digits
    :rtype: tuple
    """
    j = 0.0
    x = 2.0
    while x + 1.0 != x:
        j += 1.0
        x *= 2.0
    return j, int(j * 0.30103)


@staticmethod
def format_peak_constraints(peak, attr):
    """Returns a string representing the peak's attribute's constraints.
        """
    constraints = peak.get_constraints(attr)
    if constraints['value'] is None:
        return ''
    cstring = ''
    if constraints['expr']:
        cstring += str(constraints['expr'])
    elif not constraints['vary']:
        cstring += '{}'.format(constraints['value'])
    else:
        if constraints['min'] not in (float('-inf'), 0):
            cstring += '> {} '.format(constraints['min'])
        if constraints['max'] != float('inf'):
            cstring += '< {}'.format(constraints['max'])
    return cstring


def create(cls, name: str, **schema):
    """Create a new schema type.

Parameters
----------
name: str
    The title of the new type/schema
**schema: dict
    Extra features to add include in the schema.

Returns
-------
type

        """
    return type(name, (cls,), {}, **schema)


def _parse_text(value):
    """Default coercion function which assumes text is UTF-8 encoded"""
    return value.decode('utf-8')


def plot_spectrum_datasets_off_regions(datasets, ax=None):
    """Plot spectrum datasets of regions.

    Parameters
    ----------
    datasets : list of `SpectrumDatasetOnOff`
        List of spectrum on-off datasets
    """
    import matplotlib.pyplot as plt
    import matplotlib.patches as mpatches
    ax = plt.gca() or ax
    color_cycle = plt.rcParams['axes.prop_cycle']
    colors = color_cycle.by_key()['color']
    handles = []
    for color, dataset in zip(colors, datasets):
        kwargs = {'edgecolor': color, 'facecolor': 'none'}
        dataset.counts_off.plot_region(ax=ax, **kwargs)
        handle = mpatches.Patch(label=dataset.name, **kwargs)
        handles.append(handle)
    plt.legend(handles=handles)


def convert_empty_value_to_none(event, key_name):
    """ Changes an empty string of "" or " ", and empty list of [] or an empty dictionary of {} to None so it will be NULL in the database

    :param event: A dictionary
    :param key_name: The key for which to check for empty strings
    :return: An altered dictionary

    Examples:

    .. code-block:: python

        # Example #1
        event = {'a_field': ' '}
        event = convert_empty_value_to_none(event, key_name='a_field')
        event = {'a_field': None}

        # Example #2
        event = {'a_field': '{}'}
        event = convert_empty_value_to_none(event, key_name='a_field')
        event = {'a_field': None}

        # Example #3
        event = {'a_field': {}}
        event = convert_empty_value_to_none(event, key_name='a_field')
        event = {'a_field': None}

    """
    if key_name in event:
        if type(event[key_name]) == str and (event[key_name] == '' or event
            [key_name].strip() == '' or event[key_name] == '{}' or event[
            key_name] == '[]'):
            event[key_name] = None
        if not event[key_name]:
            event[key_name] = None
    return event


@staticmethod
def enable_transfer_acceleration(bucket):
    """
        Enable transfer acceleration for an S3 bucket

        :param bucket: Name of the bucket to enable transfer acceleration
        """
    return (
        'aws s3api put-bucket-accelerate-configuration --bucket {bucket} --accelerate-configuration Status=Enabled'
        .format(bucket=bucket))


def extract_version_from_wheel_name(name: str) ->str:
    """
    Get the version part out of the wheel file name.
    """
    parted: list = name.split('-')
    return '' if len(parted) < 2 else parted[1]


@classmethod
def missing_dependencies(cls, lst):
    """
        Checks if the given list contains all dependencies.

        :param lst: A list of all already resolved bear classes (not
                    instances).
        :return:    A set of missing dependencies.
        """
    return set(cls.BEAR_DEPS) - set(lst)


def minify_html(html):
    """Perform a template-specific, rudimentary HTML minification for displaCy.
    Disclaimer: NOT a general-purpose solution, only removes indentation and
    newlines.

    html (unicode): Markup to minify.
    RETURNS (unicode): "Minified" HTML.
    """
    return html.strip().replace('    ', '').replace('\n', '')


def get_override_code():
    """
    Attempts to procure the override code for
    localhost spawns.
    """
    try:
        with open('/etc/vmmanagement.override_code') as fp:
            override_code = fp.read().strip('\n')
    except Exception:
        override_code = None
    return override_code


@classmethod
def from_dict(cls, data):
    """
		Takes the dictionary--data--and
		returns a PawpyData instance.
		"""
    if 'metadata' in data:
        metadata = data['metadata']
    else:
        metadata = None
    return cls(data['structure'], data['data'], energy_levels=data[
        'energy_levels'], dos=[data['energies'], data['densities'], data[
        'efermi']], vbm=data['vbm'], cbm=data['cbm'], metadata=metadata)


@classmethod
def name_from_metaio(cls, metaio_type_name):
    """Get a DataType string from a MetaIO data type string"""
    for name, data_type in cls.types.items():
        if data_type.metaio_type == metaio_type_name:
            return name
    raise ValueError('Unknown type: ' + metaio_type_name)


@classmethod
def _emit_ok(cls):
    """Print OK for success."""
    cls._emit_message('OK\n')


def process(proc_data):
    """
    Final processing to conform to the schema.

    Parameters:

        proc_data:   (dictionary) raw structured data to process

    Returns:

        Dictionary. Structured data with the following schema:

        {
          "agrctlrssi":        integer,
          "agrextrssi":        integer,
          "agrctlnoise":       integer,
          "agrextnoise":       integer,
          "state":             string,
          "op_mode":           string,
          "lasttxrate":        integer,
          "maxrate":           integer,
          "lastassocstatus":   integer,
          "802_11_auth":       string,
          "link_auth":         string,
          "bssid":             string,
          "ssid":              string,
          "mcs":               integer,
          "channel":           string
        }
    """
    int_list = ['agrctlrssi', 'agrextrssi', 'agrctlnoise', 'agrextnoise',
        'lasttxrate', 'maxrate', 'lastassocstatus', 'mcs']
    for key in proc_data:
        if key in int_list:
            try:
                proc_data[key] = int(proc_data[key])
            except ValueError:
                proc_data[key] = None
    return proc_data


def uuid_to_url(baseurl, uuid):
    """
    Return an url constructed from the MISP baseurl and the uuid of the event, to go to this event on this MISP
    :param baseurl: the baseurl of the MISP instnce e.g. http://localhost:8080 or http://localhost:8080/
    :param uuid: the uuid of the event that we want to have a link to
    :return: the complete URL to go to this event on this MISP instance
    """
    if baseurl[len(baseurl) - 1] != '/':
        baseurl += '/'
    return f'{baseurl}events/view/{uuid}'


def keypress(key, modifiers=None):
    """Fire a key-pressed event."""
    pass


@staticmethod
def ee_checksum(value):
    """Takes a string of digits as input, returns check digit."""
    for i in (1, 3):
        check = 0
        for c in value:
            check += i * int(c)
            i = i % 9 + 1
        check %= 11
        if check < 10:
            return check
    return check % 10


@staticmethod
def _endsWithSegmentNumber(name):
    """
        Check if the last component in the name is a segment number.

        :param Name name: The name to check.
        :return: True if the name ends with a segment number, otherwise False.
        :rtype: bool
        """
    return name.size() >= 1 and name.get(-1).isSegment()


def calculate_chunk_size(num_tasks, num_parallel_processes,
    update_timeline_num=8):
    """
    calculate the size of the number of tasks to pass in each 'chunk' to each parallele process
    """
    num_chunks, extra = divmod(num_tasks, num_parallel_processes *
        update_timeline_num)
    if extra:
        num_chunks += 1
    return int(num_chunks)


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

        :param FileLogInfo val:
        :rtype: AssetLogInfo
        """
    return cls('file', val)


def _range_rule(lbound, ubound) ->float:
    """
    Uses a modified version (dividing by 10 instead of 4) of
    the range rule heuristic to provide a very rough estimate
    of what a good standard deviation could be for a normal
    distribution to sample genetic mutations from for a
    hyperparameter having the range (lbound, ubound).
    """
    return (ubound - lbound) / 10


def create_triangulation(cls, edge_labels, vertex_labels=None,
    vertex_states=None):
    """ A helper function for pickling. """
    return cls.from_tuple(edge_labels, vertex_labels, vertex_states)


def to_text(path):
    """Read text from given file.

    Parameters
    ----------
    path : str
        path of electronic invoice in JPG or PNG format

    Returns
    -------
    extracted_str : str
        returns extracted text any out file

    """
    file = open(path, 'r')
    return file.read()


@staticmethod
def get_set_params(instance, conf):
    """
        Extract Params from metadata, and set them in the instance.
        """
    for paramName in conf['paramMap']:
        param = instance.getParam(paramName)
        paramValue = conf['paramMap'][paramName]
        instance.set(param, paramValue)


def duplicate():
    """Duplicate the selected Grease Pencil strokes

    """
    pass


def _get_orbit_number_from_message_data(msg_data):
    """Get orbit number from message data"""
    if 'orbit_number' in msg_data:
        return msg_data['orbit_number']
    else:
        return None


def escape(string):
    """Escape strings to be SQL safe"""
    if '"' in string:
        raise Exception(
            "Can't escape identifier {} because it contains a backtick".
            format(string))
    return '"{}"'.format(string)


def prettifyNode(elem):
    """
    Return a pretty-printed XML string for the Element. Useful for debugging
    or better understanding of xml trees.
    """
    from xml.etree import ElementTree
    from xml.dom import minidom
    rough_string = ElementTree.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent='  ')


def delta_velocity_avt(acceleration, time):
    """Usage: delta_velocity_avt(acceleration of object, time taken)"""
    return acceleration * time


def IsCollection(vVar):
    """Does not include strings as a collection"""
    try:
        iter(vVar)
    except TypeError:
        bCanIter = False
    else:
        bCanIter = True
    return bCanIter and not isinstance(vVar, str)


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

        :param str val:
        :rtype: AddMemberSelectorError
        """
    return cls('invalid_dropbox_id', val)


@classmethod
def load_pkcs1_openssl_der(cls, keyfile):
    """Loads a PKCS#1 DER-encoded public key file from OpenSSL.

        :param keyfile: contents of a DER-encoded file that contains the public
            key, from OpenSSL.
        :return: a PublicKey object
        :rtype: bytes

        """
    from rsa.asn1 import OpenSSLPubKey
    from pyasn1.codec.der import decoder
    from pyasn1.type import univ
    keyinfo, _ = decoder.decode(keyfile, asn1Spec=OpenSSLPubKey())
    if keyinfo['header']['oid'] != univ.ObjectIdentifier('1.2.840.113549.1.1.1'
        ):
        raise TypeError(
            'This is not a DER-encoded OpenSSL-compatible public key')
    return cls._load_pkcs1_der(keyinfo['key'][1:])


def less_than(stack):
    """
    Take the stack, pop off four items, if the first conditional is larger than
    the second conditional append the first item to the stack, otherwise,
    append the second.
    """
    item_1 = stack.pop()
    item_2 = stack.pop()
    conditional_1 = stack.pop()
    conditional_2 = stack.pop()
    if conditional_1 < conditional_2:
        stack.append(item_1)
    else:
        stack.append(item_2)


def collect_filtered(function, iterable, filtered):
    """
    Similar to :func:`filter` but collects filtered elements in ``filtered``.

    Args:
        function (callable): function that returns ``False`` for elements that
            should be filtered
        iterable (iterable): iterable to filter
        filtered (list): list to store filtered elements
    """
    for el in iterable:
        if function(el):
            yield el
        else:
            filtered.append(el)


def Statistics(*args, **kwargs):
    """
  Computes and plots the CDPP statistics comparison between `model` and `compare_to`
  for all long cadence light curves in a given campaign

  """
    raise NotImplementedError('This mission is not yet supported.')


def RCI_calc(mutual_information, reference_entropy):
    """
    Calculate RCI (Relative classifier information).

    :param mutual_information: mutual information
    :type mutual_information : float
    :param reference_entropy: reference entropy
    :type reference_entropy : float
    :return:  RCI as float
    """
    try:
        return mutual_information / reference_entropy
    except Exception:
        return 'None'


def filter_to_true_or_false(value: str) ->str:
    """
    Jinja filter that takes in a value, casts it to a bool and
    emits ``true`` or ``false``.

    The following example assumes ``deprecated`` as an integer ``1``.

    Example::

        "deprecated": {{ T.deprecated | js.to_true_or_false }},

    Results Example::

        "deprecated": false,

    :param str value: The template value to evaluate.
    :returns: ``true`` or ``false``
    """
    return 'true' if bool(value) else 'false'


@staticmethod
def is_seq(o):
    """Check if the object is a sequence

        Parameters
        ----------
        o : any object
           The object to check

        Returns
        -------
        is_seq : bool, scalar
           True if *o* is a sequence, False otherwise
        """
    return hasattr(o, '__len__')


def dict_sum(items):
    """Construct a dict, in between dict(items) and sum(items), by accumulating items for each key."""
    d = {}
    for k, v in items:
        if k not in d:
            d[k] = v
        else:
            d[k] += v
    return d


def atomBareSymbol(smbl):
    """Remove atom type string stripped of isotope and ion charge symbols.
    This removes blank and leading [0-9-] or trailing [1-9][+-] characters.

    smbl -- atom type string such as "Cl-", "Ca2+" or "12-C".

    Return bare element symbol.
    """
    rv = smbl.strip().lstrip('0123456789-').rstrip('123456789+-')
    return rv


@staticmethod
def _compute_request_cpus(bundle):
    """
        Compute the CPU limit used for scheduling the run.
        The default of 1 is for backwards compatibilty for
        runs from before when we added client-side defaults
        """
    if not bundle.metadata.request_cpus:
        return 1
    return bundle.metadata.request_cpus


def isupper(text):
    """
    Checks if all cased characters in ``text`` are uppercase and there is at least one cased character.

    Cased characters are defined by the Unicode standard.  All alphabetic characters in the
    ASCII character set are cased.

    :param text: The string to check
    :type text:  ``str``

    :return: True if all cased characters in ``text`` are uppercase and there is at least one cased character, False otherwise.
    :rtype:  ``bool``
    """
    assert isinstance(text, str), '%s is not a string' % text
    return text.isupper()


def run_command_from_args(args):
    """Run a subcommand with previously parsed arguments in an argparse namespace.

    This function is intended to be used for unit testing.

    Parameters
    ----------
    args : Namespace
        Command line arguments are stored as attributes of a Namespace.
        The args are obtained by calling parse_argument_list().

    Returns
    -------
    Returns 0 on success if it completes with no exceptions.
    """
    return args.func(args)


def _a_decode_int(stream, offset, count, _):
    """
    'a2i42',3,2 --> 5,42
    """
    return offset + count, int(stream[offset:offset + count])


def make_paths_absolute():
    """Make all paths to external files absolute

    """
    pass


def _fetch_file_metadata(client, path):
    """Return metadata for a single file."""
    for dataset in client.datasets.values():
        for file_ in dataset.files:
            if file_.path == path:
                return file_


def getIndexAccessor(instance):
    """Return the index accessor, i.e. the getter for an indexable value.
        """


def attendees():
    """ Returns the list of attendees' email addresses.
        """


def is_hsa_ndarray(obj):
    """Check if an object is a HSA ndarray"""
    return getattr(obj, '__hsa_ndarray__', False)


def extract_cert_secret(key, device):
    """
    Check if device is marked as secret.

    :param key: Device entry.
    :type key: dict

    :param device: HWID, FCCID or name of device.
    :param device: str
    """
    not_secret = device in key['name'] and 'secret' not in key
    return not_secret


def get_host_configs(host):
    """
    Retrieve all jobs and their configurations from a host.

    Arguments:
    host - The Host to operate on.

    Returns:
    A dictionary of job configurations.  Each key will be a job name and the
    value will be the job's configuration as an XML string.
    """
    job_configs = {}
    for name, job in host.list_jobs():
        job_configs[name] = job.get_config()
    return job_configs


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

        :param str val:
        :rtype: MemberAddResult
        """
    return cls('user_already_on_team', val)


def is_owner(username, activity):
    """ Returns true if the given username is the owner of the given
    activity.

    """
    if not username:
        return False
    return username == activity.username


def bcf_images(obj_bcf):
    """ return hyperspy required list of dict with sem
    images and metadata.
    """
    images_list = []
    for img in obj_bcf.header.image.images:
        obj_bcf.add_filename_to_general(img)
        images_list.append(img)
    if hasattr(obj_bcf.header, 'overview'):
        for img2 in obj_bcf.header.overview.images:
            obj_bcf.add_filename_to_general(img2)
            images_list.append(img2)
    return images_list


def consistency_guarantees(X, y, model_generator, method_name):
    """ Consistency Guarantees
    transform = "identity"
    sort_order = 1
    """
    guarantees = {'linear_shap_corr': 1.0, 'linear_shap_ind': 1.0, 'coef':
        0.0, 'kernel_shap_1000_meanref': 0.8, 'sampling_shap_1000': 0.8,
        'random': 0.0, 'saabas': 0.0, 'tree_gain': 0.0,
        'tree_shap_tree_path_dependent': 1.0, 'tree_shap_independent_200':
        1.0, 'mean_abs_tree_shap': 1.0, 'lime_tabular_regression_1000': 0.8,
        'lime_tabular_classification_1000': 0.8, 'maple': 0.8, 'tree_maple':
        0.8, 'deep_shap': 0.6, 'expected_gradients': 0.6}
    return None, guarantees[method_name]


def timedelta_to_seconds(td):
    """
    Converts a timedelta instance to seconds.
    """
    return td.seconds + td.days * 24 * 60 * 60


@staticmethod
def encode(value):
    """
        Overload this if you need to modify the value before storing
        e.g. Pickle
        """
    return value


def _important():
    """Returns a query item matching messages that are important."""
    return f'is:important'


def backimage_fit():
    """Fit the background image to the view

    """
    pass


def line_last_return_subject(line):
    """get the last 'return <object>' statement """
    lista = list(reversed(line.split()))
    if len(lista) > 1:
        for el in lista:
            if 'return' in el:
                s = lista[lista.index('return') - 1]
                return s.split('[')[0]


@staticmethod
def get_full_name(user):
    """Get the user's full_name on the User class during serialization."""
    return user.get_full_name()


def adjust_annotations_font_sizes(fig, factor=1.0):
    """ Adjust annotation font sizes.

    Arguments:
        fig (plotly.graph_objs._figure.Figure): Plotly figure.
        factor (float): The font sizes are multiplied with this factor.
    """
    annotations = getattr(fig.layout, 'annotations', [])
    for annotation in annotations:
        font = getattr(annotation, 'font', None)
        if font is not None:
            size = getattr(font, 'size', None)
            if size is not None:
                font['size'] *= factor


@staticmethod
def seconds_toperiods(total_seconds):
    """
        Ontleedt een getal in seconden naar lijst met vaste periodes: days, hours, minutes, seconds
        waarbij day    =          24 * 60 * 60 =     86,400 seconden
                hour   =               60 * 60 =      3,600 seconden
                minute =                    60 =         60 seconden

        Parameters
        --------------
        total_seconds : float or int
            bijvoorbeeld Timedelta.total_seconds() van Pandas dataframe bv index[1]-index[0]

        Returns
        -------------
        list : list of integer values [days, hours, minutes, seconds]
        """
    days, remainder = divmod(total_seconds, 24 * 3600)
    hours, remainder = divmod(remainder, 3600)
    minutes, seconds = divmod(remainder, 60)
    return [int(days), int(hours), int(minutes), int(seconds)]


def _is_full_circle_deg(thetamin, thetamax):
    """
    Determine if a wedge (in degrees) spans the full circle.

    The condition is derived from :class:`~matplotlib.patches.Wedge`.
    """
    return abs(abs(thetamax - thetamin) - 360.0) < 1e-12


def get_y_accel(data, arg, single_row=False, multiple_row=False,
    row_section=False):
    """
    Takes in a file and row arguement(s) along with a boolean that specifies the amount of rows to read the y acceleration for.

    Parameter:

        data: file
            The csv file that is passed in to read.
        arg: int
            The row(s) that are to be read.
        single_row: boolean
            If chosen the y acceleration for a single row specified by arg will be output.
        multiple_row: boolean
            If chosen the y acceleration for multiple rows specified by arg will be output.
        row_section: boolean
            If chosen the y acceleration for a row section by arg will be output.

    Return:

        An array of y acceleration.
    """
    y_accel = []
    if single_row is True:
        y_accel_segment = list(data.values[(arg), 29:33])
        y_accel_segment.reverse()
        y = int(''.join(map(str, y_accel_segment)))
        y_accel.append(y)
    elif multiple_row is True:
        for index, elem in enumerate(arg):
            y_accel.append('new row')
            y_accel_segment = list(data.values[(elem), 29:33])
            y_accel_segment.reverse()
            y = int(''.join(map(str, y_accel_segment)))
            y_accel.append(y)
    elif row_section is True:
        for row in range(arg[0], arg[1] + 1):
            y_accel.append('new row')
            y_accel_segment = list(data.values[(row), 29:33])
            y_accel_segment.reverse()
            y = int(''.join(map(str, y_accel_segment)))
            y_accel.append(y)
    return y_accel


def disrupt_network(G, property, thresh, fail_value):
    """
    #### Function for disrupting a graph given a threshold value against a node's value ####
    Any edges which bind to broken nodes have their 'time' property set to fail_value
     REQUIRED: G - a graph containing one or more nodes and one or more edges
               property - the element in the data dictionary for the edges to test
               thresh - values of data[property] above this value are disrupted
               fail_value - the data['time'] property is set to this value to
               simulate the removal of the edge
     RETURNS:  a modified graph with the edited 'time' attribute
    #--------------------------------------------------------------------------#
    """
    G_copy = G.copy()
    broken_nodes = []
    for u, data in G_copy.nodes(data=True):
        if data[property] > thresh:
            broken_nodes.append(u)
    print('nodes disrupted: %s' % len(broken_nodes))
    i = 0
    for u, v, data in G_copy.edges(data=True):
        if u in broken_nodes or v in broken_nodes:
            data['time'] = fail_value
            i += 1
    print('edges disrupted: %s' % i)
    return G_copy


def _remove_temp_files(dirname):
    """
    Remove the created mat files in the user's temp folder
    """
    import os
    import glob
    for fname in glob.glob(os.path.join(dirname, 'tmp*.mat')):
        try:
            os.remove(fname)
        except OSError:
            pass


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


@classmethod
def get_internal_user(user):
    """
        Create a User object for internal usage.

        This user will have unlimited privileges.
        """
    return user('__paradrop__', 'localhost', role='owner')


def color(text, color, BOLD=False):
    """ANSI Sequence wrapper for text, colorizes output"""
    ANSI_PREFIX = '\x1b['
    ANSI_ENDS = '\x1b[0m'
    ANSI_COLORS_FOREGROUND = {'black': ANSI_PREFIX + '90m', 'red':
        ANSI_PREFIX + '91m', 'green': ANSI_PREFIX + '92m', 'yellow':
        ANSI_PREFIX + '93m', 'blue': ANSI_PREFIX + '94m', 'magenta':
        ANSI_PREFIX + '95m', 'cyan': ANSI_PREFIX + '96m', 'white':
        ANSI_PREFIX + '97m'}
    if color.lower() in ANSI_COLORS_FOREGROUND.keys():
        colored = ANSI_COLORS_FOREGROUND[color] + text + ANSI_ENDS
        if BOLD:
            colored = '\x1b[1m' + colored
        return colored
    else:
        return text


def has_dtypes(df, items):
    """Asserts that `df` has ``dtypes``

    Args:
        df (pd.DataFrame): Any pd.DataFrame.
        items (dict): Mapping of columns to dtype.

    Returns:
        Original `df`.

    """
    dtypes = df.dtypes
    for col, dtype in items.items():
        if not dtypes[col] == dtype:
            raise AssertionError(
                '{} has the wrong dtype. Should be ({}), is ({})'.format(
                col, dtype, dtypes[col]))
    return df


def buoyant_force(dens_gcm3, vol, sw_dens=1.028):
    """Cacluate the buoyant force of an object in seawater

    Args
    ----
    dens_gcm3: float
        Density of the animal (g/cm^3)
    vol:
        Volume of the animal (cm^3)
    sw_dens: float
        Density of seawater (Default 1.028 g/cm^3)

    Returns
    -------
    Fb: float
        Buoyant force of animal
    """
    g = 9.80665
    return 1000 * (sw_dens - dens_gcm3) * (1e-06 * vol) * g


def nosmooth(mzs, intensities):
    """
    does nothing, just returns input. is a dummy for programmatic case where a function must be supplied
    :param counts:  numpy array
    :return: mzs: numpy array
    :return: counts: numpy array
    """
    return mzs, intensities


def gradient(scalar, coord_sys):
    """
    Returns the vector gradient of a scalar field computed wrt the
    base scalars of the given coordinate system.

    Parameters
    ==========

    scalar : Diofant Expr
        The scalar field to compute the gradient of

    coord_sys : CoordSysCartesian
        The coordinate system to calculate the gradient in

    Examples
    ========

    >>> R = CoordSysCartesian('R')
    >>> s1 = R.x*R.y*R.z
    >>> gradient(s1, R)
    R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k
    >>> s2 = 5*R.x**2*R.z
    >>> gradient(s2, R)
    10*R.x*R.z*R.i + 5*R.x**2*R.k

    """
    return coord_sys.delop(scalar).doit()


def islist(val):
    """
    check if the entry is a list or is a string of list

    Parameters
    ----------
    val
        an entry of any type

    Returns
    -------
    bool
        True if the input is either a list or a string of list, False otherwise

    """
    text = str(val)
    if text[0] == '[' and text[len(text) - 1] == ']':
        return True
    else:
        return False


@staticmethod
def _size_to_dict(size):
    """
        (width, height) --> {'width': width, 'height': height}
        """
    return {'width': size[0], 'height': size[1]}


def restore(cursor, batcher, oid, tid, data):
    """Store an object directly, without conflict detection.

        Used for copying transactions into this database.

        batcher is an object returned by self.make_batcher().
        """


def scaling_transform(w1, h1, w2, h2):
    """Rescale rectangle (w1, h1) to fit in rectangle (w2, h2) without changing the ratio."""
    r1 = w1 / h1
    r2 = w2 / h2
    if r1 <= r2:
        h = h2
        w = r1 * h2
    else:
        w = w2
        h = w2 / r1
    return w, h


def get_usage(usagePlanId=None, keyId=None, startDate=None, endDate=None,
    position=None, limit=None):
    """
    Gets the usage data of a usage plan in a specified time interval.
    See also: AWS API Documentation

    :example: response = client.get_usage(
        usagePlanId='string',
        keyId='string',
        startDate='string',
        endDate='string',
        position='string',
        limit=123
    )

    :type usagePlanId: string
    :param usagePlanId: [REQUIRED]
            The Id of the usage plan associated with the usage data.

    :type keyId: string
    :param keyId: The Id of the API key associated with the resultant usage data.

    :type startDate: string
    :param startDate: [REQUIRED]
            The starting date (e.g., 2016-01-01) of the usage data.

    :type endDate: string
    :param endDate: [REQUIRED]
            The ending date (e.g., 2016-12-31) of the usage data.

    :type position: string
    :param position: The current pagination position in the paged result set.

    :type limit: integer
    :param limit: The maximum number of returned results per page.

    :rtype: dict
    :return: {
        'usagePlanId': 'string',
        'startDate': 'string',
        'endDate': 'string',
        'position': 'string',
        'items': {
            'string': [
                [
                    123,
                ],
            ]
        }
    }

    :returns:
    (string) --
    (list) --
    (list) --
    (integer) --

    """
    pass


def get_proxy(args):
    """
    Return a proxy dictionary
    """
    if args is None or args['--proxy'] is None:
        return {'http': '', 'https': ''}
    else:
        return {'http': args['--proxy'], 'https': args['--proxy']}


@staticmethod
def _parseScores(record):
    """
        Parse alignment scores

        Arguments:
          record : dictionary containing a single row from the iHMMune-Align ouptut.

        Returns:
          dict : database entries for alignment scores.
        """
    result = {}
    try:
        result['vdj_score'] = float(record['HMM_SCORE'])
    except (TypeError, ValueError):
        result['vdj_score'] = None
    return result


def reverse(s):
    """
    Return reverse of 's'.
    """
    r = ''.join(reversed(s))
    return r


def prevBatch():
    """Return the previous batch. If there is no previous batch, return
        None."""


@classmethod
def from_index(cls, index):
    """Return the Enum value at a given index."""
    return cls.ALL[index]


def cMultiplyScalar():
    """
    cMultiplyScalar subroutine.
    """
    R = """
    KERNEL void cMultiplyScalar(
                 const float2 CA,
            GLOBAL_MEM float2 *CX)
    {
    // Scale CX by CA: CX=CA*CX
    //  CA: scaling factor(float2)
    //*CX: input, output array(float2)
    int gid = get_global_id(0);
    CX[gid].x=CA.x*CX[gid].x-CA.y*CX[gid].y;
    CX[gid].y=CA.x*CX[gid].y+CA.y*CX[gid].x;
    };
    """
    return R


def get_loc_keywords(loc):
    """
    Return the location keywords based on input loc.

    :param loc: (str) - location of the text
    :return loc_keywords: (list) - list of the location keywords
    """
    loc = loc.lower()
    loc_keywords = []
    if 'top' in loc or 'upper' in loc or 'north' in loc:
        loc_keywords.append('upper')
    elif 'bottom' in loc or 'lower' in loc or 'south' in loc:
        loc_keywords.append('lower')
    if 'right' in loc or 'east' in loc or 'east' in loc:
        loc_keywords.append('right')
    elif 'left' in loc or 'west' in loc:
        loc_keywords.append('left')
    if 'center' in loc or 'middle' in loc:
        loc_keywords.append('center')
    if 'corner' in loc:
        loc_keywords.append('corner')
    return loc_keywords


def my_import(name):
    """Function converts a string based import into a module object, used for
    dynamically importing modules from config.

    Parameters
    ----------
    :str: `str`
        A string name of the module to import

    Returns
    -------
    :obj: `module`
        A module object converted from the string.

    """
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod


def getDimensions(unique_name=None):
    """Returns a list of IDimension in the catalog optionally
        matching the given name."""


def calc_thermostat_temp(high_byte, low_byte):
    """Calculate the temperature."""
    return (low_byte | high_byte << 8) * 0.1


@staticmethod
def multi_frequency_shift(timeseries_list, freqs_list):
    """ Calculate shifted frequency results of all time series
            in list by using the frequency with the same index in the frequency list.
        :param timeseries_list: timeseries list retrieved from dpsim results
        :param freq: frequency by which the timeseries should be shifted
        :return: dict of shifted time series
        """
    result_list = {}
    for ts, freq in zip(timeseries_list, freqs_list):
        ts_shift = ts.frequency_shift(freq)
        result_list[ts.name] = ts_shift
    return result_list


def get_marker_obj(plugin, context, resource, limit, marker):
    """Retrieve a resource marker object.

    This function is used to invoke
    plugin._get_<resource>(context, marker) and is used for pagination.

    :param plugin: The plugin processing the request.
    :param context: The request context.
    :param resource: The resource name.
    :param limit: Indicates if pagination is in effect.
    :param marker: The id of the marker object.
    :returns: The marker object associated with the plugin if limit and marker
        are given.
    """
    if limit and marker:
        return getattr(plugin, '_get_%s' % resource)(context, marker)


@staticmethod
def _read_pid_from_pidfile(pidfile_path):
    """
        Read the PID recorded in the named PID file.

        Read and return the numeric PID recorded as text in the named PID file. If the PID file cannot be read, or if
        the content is not a valid PID, return ``None``.

        """
    pid = None
    try:
        pidfile = open(pidfile_path, 'r')
    except IOError:
        pass
    else:
        line = pidfile.readline().strip()
        try:
            pid = int(line)
        except ValueError:
            pass
        pidfile.close()
    return pid


def set_union(x, y):
    """
	Returns array that represents the sorted union
	of two input arrays
	"""
    temp = x
    for i in y:
        try:
            val = temp.index(i)
        except:
            temp.append(i)
    temp.sort()
    return temp


def _num_det_vars(det_string, seasons=0):
    """Gives the number of deterministic variables specified by det_string and
    seasons.

    Parameters
    ----------
    det_string : str {"nc", "co", "ci", "lo", "li"}
        * "nc" - no deterministic terms
        * "co" - constant outside the cointegration relation
        * "ci" - constant within the cointegration relation
        * "lo" - linear trend outside the cointegration relation
        * "li" - linear trend within the cointegration relation

        Combinations of these are possible (e.g. "cili" or "colo" for linear
        trend with intercept). See the docstring of the :class:`VECM`-class for
        more information.
    seasons : int
        Number of periods in a seasonal cycle.

    Returns
    -------
    num : int
        Number of deterministic terms and number dummy variables for seasonal
        terms.
    """
    num = 0
    if 'ci' in det_string or 'co' in det_string:
        num += 1
    if 'li' in det_string or 'lo' in det_string:
        num += 1
    if seasons > 0:
        num += seasons - 1
    return num


def ip_to_long(ip):
    """
    Convert ip address to a network byte order 32-bit integer.
   """
    quad = ip.split('.')
    if len(quad) == 1:
        quad = quad + [0, 0, 0]
    elif len(quad) < 4:
        host = quad[-1:]
        quad = quad[:-1] + [0] * (4 - len(quad)) + host
    lip = 0
    for q in quad:
        lip = lip << 8 | int(q)
    return lip


def downgrade():
    """Downgrade database."""


def sigmoid(data=None, name=None, attr=None, out=None, **kwargs):
    """Computes sigmoid of x element-wise.

    .. math::
       y = 1 / (1 + exp(-x))

    The storage type of ``sigmoid`` output is always dense

    Defined in src/operator/tensor/elemwise_unary_op_basic.cc:L119

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

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

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


def perm_num_cycles(p, n=None):
    """
    Return the number of cycles of the permutation ``p``.

    EXAMPLES::

        sage: from surface_dynamics.misc.permutation import perm_num_cycles
        sage: perm_num_cycles([1,2,3,0])
        1
        sage: perm_num_cycles([0,2,3,1])
        2
        sage: perm_num_cycles([3,2,1,0])
        2
        sage: perm_num_cycles([3,1,2,0])
        3
        sage: perm_num_cycles([0,1,2,3])
        4
    """
    if n is None:
        n = len(p)
    seen = [False] * n
    ans = 0
    for i in range(n):
        if seen[i] or p[i] == -1:
            continue
        ans += 1
        j = i
        while not seen[j]:
            seen[j] = True
            j = p[j]
    return ans


def selectGenes(df, selection):
    """
    Remove all rows (gene_ids) from a data frame which can not be found in
    selection.

    Parameters
    ---------
    df : DataFrame
        The data frame to work with.
    selection : set
        All ids to keep.

    Return
    ------
    df : DataFrame
        The cleand data frame.
    """
    selection = set(selection)
    for id in df.index:
        if id not in selection:
            df = df.drop(id)
    return df


def NormalizeSeps(source, format, standard=' '):
    """ Normalize various separators matching format to standard value. """
    from pijnu.generator.pijnuParser import format as formatPattern
    formatNode = formatPattern.parse(format)
    pattern = eval(formatNode.value)
    result = pattern.replace(source, standard)
    return result


def is_coordsys(obj):
    """ Test if `obj` has the CoordinateSystem API

    Parameters
    ----------
    obj : object
        Object to test

    Returns
    -------
    tf : bool
        True if `obj` has the coordinate system API

    Examples
    --------
    >>> is_coordsys(CoordinateSystem('xyz'))
    True
    >>> is_coordsys(CoordSysMaker('ikj'))
    False
    """
    if not hasattr(obj, 'coord_names'):
        return False
    if not hasattr(obj, 'name'):
        return False
    if not hasattr(obj, 'coord_dtype'):
        return False
    return not callable(obj)


def overlap(set1, set2):
    """Computes the overlap between two sets.

    Args:
        set1,set2 (set or list): Input sets (or lists). Input lists are
            converted to sets.

    Returns:
        overlap (int)
    """
    if not isinstance(set1, set):
        set1 = set(set1)
    if not isinstance(set2, set):
        set2 = set(set2)
    return len(set1.intersection(set2))


def _sequential_for(sequence, produce, retire):
    """Simple single-threaded for loop"""
    for idx, var in enumerate(sequence):
        deferred = produce(var)
        deferred.compute()
        retire(deferred, idx)


def p_possible_comma(p):
    """possible_comma : empty
                      | COMMA"""
    pass


def get_default_params(dim: int) ->dict:
    """
    Returns the default parameters of the Self-adaptive Differential Evolution Algorithm (SaDE).
    :param dim: Size of the problem (or individual).
    :type dim: int
    :return: Dict with the default parameters of SaDe
    :rtype dict
    """
    return {'max_evals': 10000 * dim, 'population_size': 60, 'callback':
        None, 'individual_size': dim, 'seed': None, 'opts': None}


def _show_mpl_pos(exec_name, trajectory_list, **kwargs):
    """
    Produces a matplotlib plot of the trajectory
    """
    for traj in trajectory_list:
        traj.show_mpl_pos(**kwargs)


@classmethod
def explicit(cls, args=None, kwargs=None):
    """ Creates a ``param`` by explicitly specifying ``args`` and
            ``kwargs``::

                >>> param.explicit([1,2,3])
                param(*(1, 2, 3))
                >>> param.explicit(kwargs={"foo": 42})
                param(*(), **{"foo": "42"})
            """
    args = args or ()
    kwargs = kwargs or {}
    return cls(*args, **kwargs)


def assets(liabilities, equity):
    """
    Computes total assets.

    @params
    -------
    liabilities: total liabilities
    equity: shareholders' equity

    returns
    -------
    Returns total assets, int or float
    """
    return liabilities + equity


def to_json(t):
    """
    converts a tree to JSON-export data,
    using the specified encoding for
    non-unicode strings
    """
    terms = []
    for n in t.terminals:
        if n.parent:
            parent_id = n.parent.id
        else:
            parent_id = '0'
        extras = []
        if hasattr(n, 'secedge') and n.secedge is not None:
            extra = []
            for secedge in n.secedge:
                tgt = secedge[1]
                if tgt.isTerminal():
                    tgt_id = tgt.start
                else:
                    tgt_id = tgt.id
                extra.append([secedge[0], tgt_id])
            if extra:
                extras = [extra]
        terms.append([n.word, n.cat, n.morph, n.edge_label, parent_id,
            getattr(n, 'lemma', None)] + extras)
    nonterms = []
    all_nodes = sorted(t.node_table.values(), key=lambda n: n.id)
    for n in all_nodes:
        if n.parent:
            parent_id = n.parent.id
        else:
            parent_id = '0'
        extras = []
        if hasattr(n, 'secedge') and n.secedge is not None:
            extra = []
            for secedge in n.secedge:
                tgt = secedge[1]
                if tgt.isTerminal():
                    tgt_id = tgt.start
                else:
                    tgt_id = tgt.id
                extra.append([secedge[0], tgt_id])
            if extra:
                extras = [extra]
        nonterms.append([n.id, n.cat, n.attr, n.edge_label, parent_id] + extras
            )
    result = {'terminals': terms, 'nonterminals': nonterms}
    if hasattr(t, 'sent_no'):
        result['_id'] = str(t.sent_no)
    return result


def parse_kipoi_colname(colname):
    """Parse kipoi column name into:
    (model, version, type)
    input: "KV:dir:examples/rbp:DIFF"
    output: ("dir", "examples/rbp", "DIFF")
    """
    _, source_type, model, diff_type = colname.split(':', 3)
    return source_type, model, diff_type


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 p_expression_plus(p):
    """expression : expression PLUS expression"""
    p[0] = p[1] + p[3]


def space_newline_fix(text):
    """Replace "space-newline" with "newline".

    Args:
        text (str): The string to work with

    Returns:
        The text with the appropriate fix.
    """
    space_newline = ' \n'
    fix = '\n'
    while space_newline in text:
        text = text.replace(space_newline, fix)
    return text


@classmethod
def _rebuild(cls, entry_name, ptx, linking, max_registers):
    """
        Rebuild an instance.
        """
    return cls(entry_name, ptx, linking, max_registers)


def resource_listdir(resource_name):
    """List of resource names in the directory (like ``os.listdir()``)"""


def add_session_msg(request, message, level):
    """
    Adds a message to our session var which will get shown on
    the next page view.  Only 'success' and 'fail' are valid
    for ``level``, but values other than that will be silently
    ignored.
    """
    if level != 'success' and level != 'fail':
        return
    varname = 'exordium_msg_%s' % level
    if varname not in request.session:
        request.session[varname] = []
    request.session[varname].append(message)
    request.session.modified = True


@classmethod
def textSearch(cls, text, limit, skip, query=None, sort=None, db=None, **kwargs
    ):
    """Find by text search and return all matched instances.

        args:
            search text(str):
            limit(int):
            skip (int):
            query(dict):
            sort (int): condition other than text search
        """
    __db = db if db else cls.__db
    if not query:
        query = {}
    if cls.__search_text_index_unit__ == 'bigram':
        query['$text'] = {'$search': cls.generateSearchBiGramStr(text)}
    else:
        raise Exception('index unit must be either bigram or morpheme')
    if not sort:
        sort = [('score', {'$meta': 'textScore'})]
    cursor = __db[cls.__collection__].find(query, {'score': {'$meta':
        'textScore'}}, **kwargs).skip(skip).limit(limit)
    print(f'B : {cursor}')
    cursorResults = cursor.sort(sort)
    return list(cls.generateInstances(cursorResults))


@staticmethod
def in_out_back(progress):
    """.. image:: images/anim_in_out_back.png
        """
    p = progress * 2.0
    s = 1.70158 * 1.525
    if p < 1:
        return 0.5 * (p * p * ((s + 1.0) * p - s))
    p -= 2.0
    return 0.5 * (p * p * ((s + 1.0) * p + s) + 2.0)


@staticmethod
def _get_index_keys(formatted_columns):
    """Get columns that are index key"""
    index_keys = list()
    for column in formatted_columns:
        column_name = column[0]
        column_is_primary_key = column[3]
        if not column_is_primary_key and column_name.lower().find('id', 0, 2
            ) != -1:
            index_keys.append(column_name)
    return index_keys