@classmethod
def is_dtype(cls, dtype) ->bool:
    """
        Return a boolean if we if the passed type is an actual dtype that we
        can match (via string or type)
        """
    if isinstance(dtype, str):
        if dtype.lower().startswith('interval'):
            try:
                if cls.construct_from_string(dtype) is not None:
                    return True
                else:
                    return False
            except (ValueError, TypeError):
                return False
        else:
            return False
    return super().is_dtype(dtype)


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 nonzero_1d(input):
    """Return the nonzero index of the given 1D input.

    Parameters
    ----------
    input : Tensor
        Must be a 1D tensor.

    Returns
    -------
    Tensor
        A 1D integer tensor containing the nonzero indices.
    """
    pass


def modify_ssl():
    """Set TLS/HTTPS info"""
    raise NotImplementedError


def urls2list(urls: dict):
    """generates a list of EventNotificationReport objects from a list of urls"""
    urls_l = []
    for year, months in urls.items():
        for month, murls in months.items():
            for url in murls:
                urls_l.append(url)
    return urls_l


def _rescue(function):
    """
    Boxes function's input parameter from a regular value to a container.

    In other words, it modifies the function
    signature from: ``a -> Container[b]`` to: ``Container[a] -> Container[b]``

    Similar to :func:`returns.pointfree.bind`, but works for failed containers.

    This is how it should be used:

    .. code:: python

      >>> from returns.pointfree import rescue
      >>> from returns.result import Success, Failure, Result

      >>> def example(argument: int) -> Result[str, int]:
      ...     return Success(argument + 1)
      ...
      >>> assert rescue(example)(Success('a')) == Success('a')
      >>> assert rescue(example)(Failure(1)) == Success(2)

    Note, that this function works for all containers with ``.rescue`` method.
    See :class:`returns.primitives.interfaces.Rescueable` for more info.

    """
    return lambda container: container.rescue(function)


def _format_date(dt):
    """convert a datetime into an RFC 822 formatted date

    Input date must be in GMT.
    """
    return '%s, %02d %s %04d %02d:%02d:%02d GMT' % (['Mon', 'Tue', 'Wed',
        'Thu', 'Fri', 'Sat', 'Sun'][dt.weekday()], dt.day, ['Jan', 'Feb',
        'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
        'Dec'][dt.month - 1], dt.year, dt.hour, dt.minute, dt.second)


def check(ob, operation):
    """
        Check whether *operation* is allowed.

        The operation name is the Python special method name,
        e.g. "__getitem__".

        May raise Unauthorized or Forbidden.  Returns no value.

        If a checker implements ``__setitem__``, then ``__setitem__``
        will be called rather than ``check`` to ascertain whether an
        operation is allowed. This is a hack that allows significantly
        greater performance due to the fact that low-level operator
        access is much faster than method access.

        :raises: :class:`Unauthorized`
        :raises: :class:`Forbidden`
        :return: Nothing
        """


def zip_longest(*args, **kwargs):
    """
    https://docs.python.org/3.5/library/itertools.html#itertools.zip_longest
    """
    try:
        from itertools import zip_longest
        return zip_longest(*args, **kwargs)
    except ImportError:
        from itertools import izip_longest
        return izip_longest(*args, **kwargs)


@classmethod
def info(cls, options=None):
    """
        Gets information for GPG Key
        """
    cls.command_sub = 'info'
    return cls.execute(cls._construct_command(options), output_format='json')


@classmethod
def check_collision(cls, ball1, ball2):
    """Return true if colliding with another ball"""
    norm = (ball1.positions[-1] - ball2.positions[-1]) ** 2
    norm = norm[0] + norm[1]
    return not (ball1.static and ball2.static) and norm < (ball1.radius +
        ball2.radius) ** 2


def get_aparc_aseg(files):
    """Return the aparc+aseg.mgz file"""
    for name in files:
        if 'aparc+aseg.mgz' in name:
            return name
    raise ValueError('aparc+aseg.mgz not found')


def read_numpy(fh, byteorder, dtype, count, offsetsize):
    """Read tag data from file and return as numpy array."""
    dtype = 'b' if dtype[-1] == 's' else byteorder + dtype[-1]
    return fh.read_array(dtype, count)


def contains_zeros(tables):
    """Checks if any tables contains only zeros."""
    f_epsilon = format['epsilon']
    names = []
    for name in tables:
        vals = tables[name]
        if len(vals) > 0 and abs(vals).max() < f_epsilon:
            names.append(name)
    return names


@classmethod
def _get_origin(cls):
    """Return list of Model names for origin Reference"""
    return []


def get_typestrings(struct):
    """
    Return the valid schema types as a set.
    """
    type_strings = struct.get('type', [])
    if isinstance(type_strings, str):
        type_strings = set([type_strings])
    else:
        type_strings = set(type_strings)
    if not type_strings:
        type_strings = set(['null', 'boolean', 'object', 'array', 'number',
            'string'])
    if 'integer' in type_strings and 'number' in type_strings:
        type_strings.remove('integer')
    return type_strings


def evaluations(ty, pv):
    """
    evaluations(ty, pv) -> (ACC, MSE, SCC)

    Calculate accuracy, mean squared error and squared correlation coefficient
    using the true values (ty) and predicted values (pv).
    """
    if len(ty) != len(pv):
        raise ValueError('len(ty) must equal to len(pv)')
    total_correct = total_error = 0
    sumv = sumy = sumvv = sumyy = sumvy = 0
    for v, y in zip(pv, ty):
        if y == v:
            total_correct += 1
        total_error += (v - y) * (v - y)
        sumv += v
        sumy += y
        sumvv += v * v
        sumyy += y * y
        sumvy += v * y
    l = len(ty)
    ACC = 100.0 * total_correct / l
    MSE = total_error / l
    try:
        SCC = (l * sumvy - sumv * sumy) * (l * sumvy - sumv * sumy) / ((l *
            sumvv - sumv * sumv) * (l * sumyy - sumy * sumy))
    except:
        SCC = float('nan')
    return ACC, MSE, SCC


@classmethod
def build_format_file(cls, data_object):
    """Builds the format file for a given file with columns attribute
        :param data_object: An object that has a list attribute with the name
                            of 'columns'
        :return: String value of the format file
        :rtype: str
        """
    if data_object.qualifier:
        format_file_row_count = len(data_object.columns) + 1
    else:
        format_file_row_count = len(data_object.columns)
    format_file = f'9.0\n{format_file_row_count}\n'
    terminators = cls._get_field_terminators(data_object)
    if data_object.qualifier:
        format_file += f"""1 SQLCHAR 0 0 "{terminators[0]}" 0 ignored_line_start_qualifier SQL_Latin1_General_CP1_CI_AS
"""
        format_file_row_index = 2
        terminators = terminators[1:]
    else:
        format_file_row_index = 1
    for column_index, terminator in enumerate(terminators, 1):
        format_file += f"""{format_file_row_index} SQLCHAR 0 0 "{terminator}" {column_index} {data_object.columns[column_index - 1]} SQL_Latin1_General_CP1_CI_AS
"""
        format_file_row_index += 1
    return format_file


def extract_documents(input_dict):
    """
    Extract documents, given document indices, from Annotated Document Corpus.

    :param adc: Annotated Document Corpus
    :param index_list: list of document ids to include
    :param discard_filtered_out default-false: discard documents that are not included in index_list

    :return adc_filtered: adc with documents that fulfil the condition
    :return adc_rest: adc with documents that do not fulfil the condtion
    """
    discard_filtered_out = input_dict['discard_filtered_out'] == 'true'
    included = input_dict['index_list']
    for i in included:
        if i < 0 or i >= len(input_dict['adc'].documents) or type(i) != int:
            raise Exception('Document indices are set incorrectly.')
    discarded = [i for i in range(len(input_dict['adc'].documents)) if i not in
        input_dict['index_list']]
    adc_filtered, adc_rest = input_dict['adc'].split(included, None if
        discard_filtered_out else discarded)
    return {'adc_filtered': adc_filtered, 'adc_rest': adc_rest}


def calculate_final_drive_torques_in(final_drive_torques_out,
    final_drive_ratio_vector, final_drive_torque_losses):
    """
    Calculates final drive torque [N*m].

    :param final_drive_torques_out:
        Torque at the wheels [N*m].
    :type final_drive_torques_out: numpy.array | float

    :param final_drive_ratio_vector:
        Final drive ratio vector [-].
    :type final_drive_ratio_vector: numpy.array | float

    :param final_drive_torque_losses:
        Final drive torque losses [N*m].
    :type final_drive_torque_losses: numpy.array | float

    :return:
        Final drive torque in [N*m].
    :rtype: numpy.array | float
    """
    t = final_drive_torques_out / final_drive_ratio_vector
    return t + final_drive_torque_losses


def __deserialize_primitive(A, data, klass):
    """Deserializes string to primitive type.

        :param data: str.
        :param klass: class literal.

        :return: int, long, float, str, bool.
        """
    assert type(data) == klass
    return data


def monitor_sector8(tsv_filename):
    """Monitors a list of files and displays them as they are collected
    from the instrument. A matplotlib axes is displayed and is updated
    with each new frame that is detected. This function will block
    until all files in the file list are accounted for.

    Parameters
    ----------
    tsv_filename : string
      The name of the file that contains a tab-separated-values list
      of filenames. This file is automatically generated by the
      ``sector8_xanes_script`` function.

    """
    pass


def _timedelta_to_seconds(timedelta):
    """
    >>> _timedelta_to_seconds(datetime.timedelta(hours=3))
    10800
    >>> _timedelta_to_seconds(datetime.timedelta(hours=3, minutes=15))
    11700
    """
    return (timedelta.days * 86400 + timedelta.seconds + timedelta.
        microseconds // 1000)


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


def round_to_fraction(val, res, decimals=None):
    """ round to closest resolution """
    if val is None:
        return 0.0
    if decimals is None and '.' in str(res):
        decimals = len(str(res).split('.')[1])
    return round(round(val / res) * res, decimals)


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

        :param FileRequestsChangePolicyDetails val:
        :rtype: EventDetails
        """
    return cls('file_requests_change_policy_details', val)


def setattrrec(object, name, value):
    """Inject data into the innermost layer in an onion of wrapper objects.

    See also ``getattrrec``.
    """
    o = object
    while hasattr(o, name) and hasattr(getattr(o, name), name):
        o = getattr(o, name)
    setattr(o, name, value)


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


@staticmethod
def select_folder(title='Select Folder', start_directory=None):
    """
        Function that shows select folder DCC native dialog
        :param title: str
        :param start_directory: str
        :return: str
        """
    raise NotImplementedError('select_folder() function is not implemented')


def describe_player_sessions(GameSessionId=None, PlayerId=None,
    PlayerSessionId=None, PlayerSessionStatusFilter=None, Limit=None,
    NextToken=None):
    """
    Retrieves properties for one or more player sessions. This action can be used in several ways: (1) provide a PlayerSessionId to request properties for a specific player session; (2) provide a GameSessionId to request properties for all player sessions in the specified game session; (3) provide a PlayerId to request properties for all player sessions of a specified player.
    To get game session record(s), specify only one of the following: a player session ID, a game session ID, or a player ID. You can filter this request by player session status. Use the pagination parameters to retrieve results as a set of sequential pages. If successful, a  PlayerSession object is returned for each session matching the request.
    See also: AWS API Documentation

    :example: response = client.describe_player_sessions(
        GameSessionId='string',
        PlayerId='string',
        PlayerSessionId='string',
        PlayerSessionStatusFilter='string',
        Limit=123,
        NextToken='string'
    )

    :type GameSessionId: string
    :param GameSessionId: Unique identifier for the game session to retrieve player sessions for.

    :type PlayerId: string
    :param PlayerId: Unique identifier for a player to retrieve player sessions for.

    :type PlayerSessionId: string
    :param PlayerSessionId: Unique identifier for a player session to retrieve.

    :type PlayerSessionStatusFilter: string
    :param PlayerSessionStatusFilter: Player session status to filter results on.
            Possible player session statuses include the following:
            RESERVED   The player session request has been received, but the player has not yet connected to the server process and/or been validated.
            ACTIVE   The player has been validated by the server process and is currently connected.
            COMPLETED   The player connection has been dropped.
            TIMEDOUT   A player session request was received, but the player did not connect and/or was not validated within the time-out limit (60 seconds).

    :type Limit: integer
    :param Limit: Maximum number of results to return. Use this parameter with NextToken to get results as a set of sequential pages. If a player session ID is specified, this parameter is ignored.

    :type NextToken: string
    :param NextToken: Token that indicates the start of the next sequential page of results. Use the token that is returned with a previous call to this action. To specify the start of the result set, do not specify a value. If a player session ID is specified, this parameter is ignored.

    :rtype: dict
    :return: {
        'PlayerSessions': [
            {
                'PlayerSessionId': 'string',
                'PlayerId': 'string',
                'GameSessionId': 'string',
                'FleetId': 'string',
                'CreationTime': datetime(2015, 1, 1),
                'TerminationTime': datetime(2015, 1, 1),
                'Status': 'RESERVED'|'ACTIVE'|'COMPLETED'|'TIMEDOUT',
                'IpAddress': 'string',
                'Port': 123,
                'PlayerData': 'string'
            },
        ],
        'NextToken': 'string'
    }

    :returns:
    CreatePlayerSession
    CreatePlayerSessions
    DescribePlayerSessions

    """
    pass


def index_resource(resource, oid=None, action_mode=None):
    """Register the resource in indexes of this catalog using objectid
        ``oid``.  If ``oid`` is not supplied, the ``__oid__`` of the
        ``resource`` will be used.  ``action_mode``, if supplied, should be one
        of ``None``, :attr:`~substanced.interfaces.MODE_IMMEDIATE`,
        :attr:`~substanced.interfaces.MODE_ATCOMMIT` or
        :attr:`~substanced.interfaces.MODE_DEFERRED`."""


def mslike(pop, **kwargs):
    """
    Function to establish default parameters
    for a single-locus simulation for standard pop-gen
    modeling scenarios.

    :params pop: An instance of :class:`fwdpy11.DiploidPopulation`
    :params kwargs: Keyword arguments.
    """
    import fwdpy11
    if isinstance(pop, fwdpy11.DiploidPopulation) is False:
        raise ValueError('incorrect pop type: ' + str(type(pop)))
    defaults = {'simlen': 10 * pop.N, 'beg': 0.0, 'end': 1.0, 'theta':
        100.0, 'pneutral': 1.0, 'rho': 100.0, 'dfe': None}
    for key, value in kwargs.items():
        if key in defaults:
            defaults[key] = value
    import numpy as np
    params = {'demography': np.array([pop.N] * defaults['simlen'], dtype=np
        .uint32), 'nregions': [fwdpy11.Region(defaults['beg'], defaults[
        'end'], 1.0)], 'recregions': [fwdpy11.Region(defaults['beg'],
        defaults['end'], 1.0)], 'rates': (defaults['pneutral'] * defaults[
        'theta'] / (4.0 * pop.N), (1.0 - defaults['pneutral']) * defaults[
        'theta'] / (4.0 * pop.N), defaults['rho'] / (4.0 * float(pop.N))),
        'gvalue': fwdpy11.Multiplicative(2.0)}
    if defaults['dfe'] is None:
        params['sregions'] = []
    else:
        params['sregions'] = [defaults['dfe']]
    return params


def default(value, default_value, empty_value=None):
    """
    >>> default('1', '0')
    '1'
    >>> default(None, '0')
    '0'
    >>> default('', '0')
    ''
    >>> default('', '0', empty_value='')
    '0'
    """
    return default_value if value == empty_value else value


def serialize_milestone(milestone):
    """
    Milestone object-to-dict serialization
    """
    return {'id': milestone.id, 'name': milestone.name, 'display_name':
        milestone.display_name, 'namespace': milestone.namespace,
        'description': milestone.description}


def channels_length(sequence_shape, data_format: str='channels_last') ->int:
    """Returns sequence.shape[-1] or [0] depending on data_format."""
    if data_format is None:
        data_format = 'channels_last'
    return (sequence_shape[0],) if data_format == 'channels_last' else (
        sequence_shape[-1],)


def is_owner(obj, user):
    """ Check if user is owner of the slice """
    return obj and user in obj.owners


def k_to_R(k, t, A=1.0):
    """Returns the thermal resistance of a substance given its thickness
    and thermal conductivity.

    .. math::
        R = \\frac{t}{kA}

    Parameters
    ----------
    k : float
        Thermal conductivity of a substance [W/m/K]
    t : float
        Thickness of the substance for a given value of R, [m]
    A : float, optional
        Area; normally 1, [m^2]

    Returns
    -------
    R : float
        Thermal resistance of a substance [K/W]

    Examples
    --------
    >>> k_to_R(k=0.5, t=0.025)
    0.05

    Notes
    -----
    When solving problems of changing areas, this value may be calculated with
    an area other than 1 m^2. Values in tables reported as properties of
    materials are often divided by area already; the conversion holds if A is 1.

    References
    ----------
    .. [1] Bergman, Theodore L., Adrienne S. Lavine, Frank P. Incropera, and
       David P. DeWitt. Introduction to Heat Transfer. 6E. Hoboken, NJ:
       Wiley, 2011.
    """
    return t / (k * A)


def rand_shuffle(arr):
    """Random shuffle the data in the first dimension of the array.

    The shuffled data is stored in a new array.

    Parameters
    ----------
    arr : Tensor
        The data tensor

    Returns
    -------
    Tensor
        The result tensor
    """
    pass


def return_tuple_item(item):
    """tuple of statements, next statement"""
    return '                {0},'.format(item)


def tick(s):
    """Print `s` as a list item. This is used to update the user during a
    long-running function.
    """
    print(' -', s)


def parse_project_id(project_id):
    """Simple check for project id.

    :param project_id: a numeric project id, int or string.
    :return: a unified project id.
    :rtype: :class:`str`
    """
    try:
        int(project_id)
    except ValueError:
        raise ValueError('Project id should be convertible to integer')
    return str(project_id)


@classmethod
def children_range(cls, id_parent):
    """ all descendants except first in chain should implement this class method"""
    raise NotImplementedError


def create_serial_add_op(names, op_code, shifts, BW_in, BW_out, module_name,
    reset_name, depth):
    """
    Creates an add or subtract operation ( input c is not allowed, no shifts allowed )
    names = [ out_name, a_name, b_name, c_name ]
    op_code = 0 -> - a - b - c ( not allowed in this implementation )
    op_code = 1 -> - a - b + c ( not allowed in this implementation )
    op_code = 2 -> - a + b - c
    op_code = 3 -> - a + b + c
    op_code = 4 ->   a - b - c
    op_code = 5 ->   a - b + c
    op_code = 6 ->   a + b - c
    op_code = 7 ->   a + b + c
    shifts = [ shift_a, shift_b, shift_c ] ( not allowed in this implementation )
    BW_in -> the bitwidth of the input
    BW_out -> the bitwidth of the output
    module_name -> the name to call the adder
    reset_name -> the reset to use, will assert the reset on the cycle before use
    depth -> how deep the op is down the tree, inputs have a depth of 0 ( not used in this op )
    """
    assert names[3] == str(BW_out
        ) + "'h0", 'Three inputs not implemented in this adder'
    assert shifts[0] == 0 and shifts[1
        ] == 0, 'Shift registers not implemented in this adder'
    op_code = op_code >> 1
    if names[2] == str(BW_out) + "'h0" and op_code == 0:
        op_code = 1
    assert op_code != 0, 'Cannot be both negative inputs for serial adder for module ' + module_name
    neg_b = (op_code != 3) * 1
    if op_code == 1:
        names[1], names[2] = names[2], names[1]
    ser_add_module = ('wire [' + str(BW_in - 1) + ':0] ' + names[0] +
        """;
serial_adder #(
  .neg_b(""" + str(neg_b) + '),\n  .BW(' + str
        (BW_in) + ')\n) ' + module_name + """ (
 .clk(clock),
 .reset(""" +
        reset_name + '),\n .a(' + names[1] + '),\n .b(' + names[2] +
        '),\n .c(' + names[0] + ')\n);\n')
    return ser_add_module, BW_in


@classmethod
def from_geojson(cls, geojson):
    """
        Construct a Workflows Geometry from a GeoJSON mapping.

        Note that the GeoJSON must be relatively small (under 10MiB of serialized JSON).

        Parameters
        ----------
        geojson: Dict

        Returns
        -------
        ~descarteslabs.workflows.Geometry
        """
    try:
        return cls._from_apply(cls._constructor, type=geojson['type'],
            coordinates=geojson['coordinates'])
    except KeyError:
        raise ValueError(
            "Expected a GeoJSON mapping containing the fields 'type' and 'coordinates', but got {}"
            .format(geojson))


@classmethod
def from_json(cls, client, project_id, json_obj, download_translations=True,
    download_sources=False):
    """Deserialize the file JSON to File object.

        :param client: an object instance of TextUnitedClient
        :type client: TextUnitedClient
        :param project_id: The project id of the file
        :param json_obj: the File json object
        :param download_translations: a boolean to select to download the
        translated file content. Only if the file status is Translated.
        :param download_sources: a boolean to select to download the source
        file content.
        :type download_translations: bool
        :type download_sources: bool
        :return: a File object with the attributes of the JSON object
        :rtype: File object
        """
    obj = cls(client=client, project_id=project_id, id_=json_obj['FileId'],
        name=json_obj['Filename'], subdir=json_obj['Subdir'], size=json_obj
        ['FileSize'], words=json_obj['Words'], status=json_obj['Status'])
    if download_translations and obj.status == 'Translated':
        obj.get_translated_content()
    if download_sources:
        obj.get_source_content()
    return obj


def _qt_implementation(module):
    """Helper function to get name (PyQt4, PyQt5, PySide) and the QtCore module
    """
    global _qtcore
    name = module.name.split('.')[0]
    try:
        _qtcore = __import__(name, fromlist=['QtCore']).QtCore
    except RuntimeError:
        print(
            'WARNING: Tried to load multiple incompatible Qt wrappers. Some incorrect files may be copied.'
            )
    return name, _qtcore


def has_polyA(read, n=6):
    """
    SPECIFIC !!! For now only check if the read ends with n "A"
    Intended for stranded specific data
    """
    if read.sequence.endswith('A' * n):
        return True


def get_id_constraints(pkname, pkey):
    """Returns primary key consraints.

  :pkname: if a string, returns a dict with pkname=pkey. pkname and pkey must be enumerables of
  matching length.
  """
    if isinstance(pkname, str):
        return {pkname: pkey}
    else:
        return dict(zip(pkname, pkey))


@classmethod
def create(cls, api, upload_create):
    """Post an upload to Raster Foundry for processing

        Args:
            api (API): API to use for requests
            upload_create (dict): post parameters for /uploads. See
                upload_create_from_files

        Returns:
            Upload: created object in Raster Foundry
        """
    return api.client.Imagery.post_uploads(Upload=upload_create).result()


def ep2string(EP, area=1.0):
    """Format energy efficiency indicators as string from primary energy data

    In the context of the CTE regulations, this refers to primary energy values.
    """
    areafactor = 1.0 / area
    eparen = areafactor * EP['EPpasoA']['ren']
    epanren = areafactor * EP['EPpasoA']['nren']
    epatotal = eparen + epanren
    eparer = eparen / epatotal if epatotal else 0.0
    epren = areafactor * EP['EP']['ren']
    epnren = areafactor * EP['EP']['nren']
    eptotal = epren + epnren
    eprer = epren / eptotal if eptotal else 0.0
    txt = (
        """EP(step A)  , ren ={:>8.1f}, nren={:>8.1f}, tot ={:>8.1f}, RER ={:>8.2f}
EP(step A+B), ren ={:>8.1f}, nren={:>8.1f}, tot ={:>8.1f}, RER ={:>8.2f}
"""
        .format(eparen, epanren, epatotal, eparer, epren, epnren, eptotal,
        eprer))
    return txt


def deconv(gaus_bm, gaus_c):
    """ Deconvolves gaus_bm from gaus_c to give gaus_dc.
        Stolen shamelessly from aips DECONV.FOR.
        All PA is in degrees."""
    from math import pi, cos, sin, atan, sqrt
    rad = 180.0 / pi
    gaus_d = [0.0, 0.0, 0.0]
    phi_c = gaus_c[2] + 900.0 % 180
    phi_bm = gaus_bm[2] + 900.0 % 180
    maj2_bm = gaus_bm[0] * gaus_bm[0]
    min2_bm = gaus_bm[1] * gaus_bm[1]
    maj2_c = gaus_c[0] * gaus_c[0]
    min2_c = gaus_c[1] * gaus_c[1]
    theta = 2.0 * (phi_c - phi_bm) / rad
    cost = cos(theta)
    sint = sin(theta)
    rhoc = (maj2_c - min2_c) * cost - (maj2_bm - min2_bm)
    if rhoc == 0.0:
        sigic = 0.0
        rhoa = 0.0
    else:
        sigic = atan((maj2_c - min2_c) * sint / rhoc)
        rhoa = (maj2_bm - min2_bm - (maj2_c - min2_c) * cost) / (2.0 * cos(
            sigic))
    gaus_d[2] = sigic * rad / 2.0 + phi_bm
    dumr = (maj2_c + min2_c - (maj2_bm + min2_bm)) / 2.0
    gaus_d[0] = dumr - rhoa
    gaus_d[1] = dumr + rhoa
    error = 0
    if gaus_d[0] < 0.0:
        error += 1
    if gaus_d[1] < 0.0:
        error += 1
    gaus_d[0] = max(0.0, gaus_d[0])
    gaus_d[1] = max(0.0, gaus_d[1])
    gaus_d[0] = sqrt(abs(gaus_d[0]))
    gaus_d[1] = sqrt(abs(gaus_d[1]))
    if gaus_d[0] < gaus_d[1]:
        sint = gaus_d[0]
        gaus_d[0] = gaus_d[1]
        gaus_d[1] = sint
        gaus_d[2] = gaus_d[2] + 90.0
    gaus_d[2] = gaus_d[2] + 900.0 % 180
    if gaus_d[0] == 0.0:
        gaus_d[2] = 0.0
    elif gaus_d[1] == 0.0:
        if abs(gaus_d[2] - phi_c) > 45.0 and abs(gaus_d[2] - phi_c) < 135.0:
            gaus_d[2] = gaus_d[2] + 450.0 % 180
    return gaus_d


@classmethod
def find_tendril(cls, proto, addr):
    """
        Finds the tendril corresponding to the protocol and address
        tuple.  Returns the Tendril object, or raises KeyError if the
        tendril is not tracked.

        The address tuple is the tuple of the local address and the
        remote address for the tendril.
        """
    proto = proto.lower()
    return cls._tendrils[proto][addr]


def receive_group_specific_query(group_state: 'GroupState',
    max_response_time: int):
    """
    Received IGMP Group Specific Query packet regarding group GroupState
    """
    group_state.group_state_logger.debug(
        'Querier CheckingMembership: receive_group_specific_query')
    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


@classmethod
def get_current_id_count(cls):
    """
        Returns the current count of AMDSec objects, for id generation
        purposes.
        """
    return cls._id_generator.counter


@classmethod
def _fire_inactive(cls, obj):
    """
        Fire an AttributeError if a method is called on an inactive
        object
        """
    if not obj.is_active():
        raise AttributeError('method called on inactive rest object')


def running_average(data):
    """Iterate over data, yielding the running average.

    >>> list(running_average([40, 30, 50, 46, 39, 44]))
    [40, 35.0, 40.0, 41.5, 41.0, 41.5]

    The running average is also known as the cumulative moving average.
    Given data [a, b, c, d, ...] it yields the values:
        a, (a+b)/2, (a+b+c)/3, (a+b+c+d)/4, ...

    that is, the average of the first item, the first two items, the first
    three items, the first four items, ...
    """
    it = iter(data)
    ca = next(it)
    yield ca
    for i, x in enumerate(it, 2):
        ca = (x + (i - 1) * ca) / i
        yield ca


def add_marker(location: float=(0.0, 0.0)):
    """Place new marker at specified location

    :param location: Location, Location of marker on frame
    :type location: float
    """
    pass


def user_joined(line):
    """
        Parse information about joined user.

        Input:
        `line`      # A string describing new server connection. Example:
                    # "socket channel '0', ip 192.168.1.2:21000, user0, is complete created."

        Output:
        An object providing information about connected user if the input line
        was successfully parsed. Otherwise `None`.
        """


@classmethod
def create_model_class(cls, name, table_name, attrs, validations=None, *,
    otherattrs=None, other_bases=None):
    """Creates a new class derived from ModelBase."""
    members = dict(table_name=table_name, attrs=attrs, validations=
        validations or [])
    if otherattrs:
        members.update(otherattrs)
    return type(name, other_bases or (), members)


def freestyle_module_remove():
    """Remove the style module from the stack

    """
    pass


@classmethod
def add_hook(cls, hook_type, hook_func):
    """Add a new hook of specified type.

        :param cls: class that registers hooks
        :param hook_type: hook type, e.g., '__pre_parse_args__'
        :param hook_func: hook function
        """
    if hook_type not in cls._hooks_map:
        cls._hooks_map[hook_type] = []
    cls._hooks_map[hook_type].append(hook_func)


def _collapse_entries(entries):
    """
    Convert [['key', 'value1'], ['key', 'value2]] to [['key', ['value1', 'value2']]]
    Expect key values to be consecutive. Will maintain order as provided.
    """
    if entries is None or len(entries) < 1:
        return []
    else:
        cur_key = entries[0][0]
        cur_value = []
        new_entry = []
    for entry in entries:
        if entry[0] == cur_key:
            cur_value.append(entry[1])
        else:
            new_entry.append([cur_key, cur_value])
            cur_key = entry[0]
            cur_value = [entry[1]]
    new_entry.append([cur_key, cur_value])
    return new_entry


def check_positive(**params):
    """Check that parameters are positive as expected

    Raises
    ------
    ValueError : unacceptable choice of parameters
    """
    for p in params:
        if params[p] <= 0:
            raise ValueError('Expected {} > 0, got {}'.format(p, params[p]))


def with_siblings(graph, outputs):
    """Include all missing siblings."""
    siblings = set()
    for node in outputs:
        siblings |= graph.siblings(node)
    return siblings


def change_fleet_direction(ai_settings, aliens):
    """drops fleet and changes direction"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction *= -1


@classmethod
def tokenize_content(cls, content):
    """ Take tokenizable ChordSpec content and return the tokens """
    tokens = []
    cursor = 0
    while cursor < len(content):
        subspec = content[cursor:]
        found = False
        for token_str, token in cls._sorted_token_string_tuples():
            if subspec.startswith(token_str):
                tokens.append(token)
                cursor += len(token_str)
                found = True
                break
        if not found:
            raise ValueError('found garbage character "{}" at position {}'.
                format(subspec[0], cursor))
    if len(tokens) == 0:
        tokens.append(cls.TOKEN_MAJOR)
    return tokens


def remove_task_name(apps, schema_editor):
    """
    This doesn't need to be implemented as the task names will be deleted when the field is removed
    """
    return


def printline(line):
    """Function to simmulate appending to a plainText widget."""
    print(line, end=' ')


def select_previous():
    """Select control points preceding already selected ones along the curves

    """
    pass


def add_artifact_version(parser):
    """Add an `artifact-version` flag to _parser_."""
    parser.add_argument('--artifact-version', help=
        'Artifact version for S3 deployments')


def update_hierarchy(hierarchy, feature_type, parent_types):
    """Break input gff3 line into attributes.

    Determines feature type hierarchy using type and attributes fields.
    """
    if not parent_types:
        if feature_type not in hierarchy:
            hierarchy[feature_type] = {'children': [], 'parents': [], 'rank': 0
                }
        hierarchy[feature_type]['rank'] = 1
    else:
        if feature_type not in hierarchy:
            hierarchy[feature_type] = {'children': [], 'parents': [], 'rank': 0
                }
        hierarchy[feature_type]['parents'] = parent_types
        for p in parent_types:
            if hierarchy.get(p):
                if feature_type not in hierarchy[p]['children']:
                    hierarchy[p]['children'].append(feature_type)
            else:
                hierarchy[p] = {'children': [feature_type], 'parents': [],
                    'rank': 0}


def keyframe_insert():
    """Insert a keyframe to selected tracks at current frame

    """
    pass


def set_token(token):
    """Set the token key to access the database.

    Args:
        token (str): The token.
    """
    global _query_token
    _query_token = token


def close(x, y, rtol=1e-05, atol=1e-08):
    """Returns True if x and y are sufficiently close.

    Parameters
    ----------
    rtol : float
        The relative error tolerance.
    atol : float
        The absolute error tolerance.

    """
    return abs(x - y) <= atol + rtol * abs(y)


@classmethod
def daikin_values(cls, dimension):
    """Return sorted list of translated values."""
    return sorted(list(cls.TRANSLATIONS[dimension].values()))


def _identity(a):
    """Returns the argument."""
    return a


def pad_data(pcm_frames, channels, bits_per_sample):
    """returns True if the given stream combination
    requires an extra padding byte at the end of the 'data' chunk"""
    return pcm_frames * channels * (bits_per_sample // 8) % 2


@staticmethod
def print_console_help():
    """
        Print the console help in the console
        @return:
        """
    print('GridCal internal commands.\n')
    print(
        'If a command is unavailable is because the study has not been executed yet.'
        )
    print('\n\nclc():\tclear the console.')
    print('\n\nApp functions:')
    print('\tapp.new_project(): Clear all.')
    print('\tapp.open_file(): Prompt to load GridCal compatible file')
    print('\tapp.save_file(): Prompt to save GridCal file')
    print('\tapp.export_diagram(): Prompt to export the diagram in png.')
    print(
        '\tapp.create_schematic_from_api(): Create the schematic from the circuit information.'
        )
    print(
        '\tapp.adjust_all_node_width(): Adjust the width of all the nodes according to their name.'
        )
    print('\n\nCircuit functions:')
    print('\tapp.circuit.compile_snapshot(): Compile the grid(s) snapshot mode'
        )
    print(
        '\tapp.circuit.compile_time_series(): Compile the grid(s) time series mode'
        )
    print(
        '\tapp.circuit.plot_graph(): Plot a graph in a Matplotlib window. Call plt.show() after.'
        )
    print(
        '\tapp.circuit.load_file("file_name.xlsx/.m/.raw/.dgs"): Load GridCal compatible file'
        )
    print('\tapp.circuit.save_file("file_name.xlsx"): Save GridCal file')
    print(
        '\tapp.circuit.export_pf("file_name.xlsx"): Export power flow results to Excel'
        )
    print('\n\nPower flow results:')
    print('\tapp.power_flow.voltage:\t the nodal voltages in per unit')
    print('\tapp.power_flow.current:\t the branch currents in per unit')
    print('\tapp.power_flow.loading:\t the branch loading in %')
    print('\tapp.power_flow.losses:\t the branch losses in per unit')
    print('\tapp.power_flow.power:\t the nodal power injections in per unit')
    print(
        '\tapp.power_flow.power_from:\t the branch power injections in per unit at the "from" side'
        )
    print(
        '\tapp.power_flow.power_to:\t the branch power injections in per unit at the "to" side'
        )
    print('\n\nShort circuit results:')
    print('\tapp.short_circuit.voltage:\t the nodal voltages in per unit')
    print('\tapp.short_circuit.current:\t the branch currents in per unit')
    print('\tapp.short_circuit.loading:\t the branch loading in %')
    print('\tapp.short_circuit.losses:\t the branch losses in per unit')
    print('\tapp.short_circuit.power:\t the nodal power injections in per unit'
        )
    print(
        '\tapp.short_circuit.power_from:\t the branch power injections in per unit at the "from" side'
        )
    print(
        '\tapp.short_circuit.power_to:\t the branch power injections in per unit at the "to" side'
        )
    print(
        '\tapp.short_circuit.short_circuit_power:\t Short circuit power in MVA of the grid nodes'
        )
    print('\n\nOptimal power flow results:')
    print(
        '\tapp.optimal_power_flow.voltage:\t the nodal voltages angles in rad')
    print('\tapp.optimal_power_flow.load_shedding:\t the branch loading in %')
    print('\tapp.optimal_power_flow.losses:\t the branch losses in per unit')
    print('\tapp.optimal_power_flow.Sbus:\t the nodal power injections in MW')
    print('\tapp.optimal_power_flow.Sbranch:\t the branch power flows')
    print('\tapp.optimal_power_flow.losses:\t the branch losses in MVA')
    print(
        '\tapp.optimal_power_flow.short_circuit_power:\t Short circuit power in MVA of the grid nodes'
        )
    print('\n\nTime series power flow results:')
    print(
        '\tapp.time_series.time:\t Profiles time index (pandas DateTimeIndex object)'
        )
    print(
        '\tapp.time_series.load_profiles:\t Load profiles matrix (row: time, col: node)'
        )
    print(
        '\tapp.time_series.gen_profiles:\t Generation profiles matrix (row: time, col: node)'
        )
    print(
        '\tapp.time_series.voltages:\t nodal voltages results matrix (row: time, col: node)'
        )
    print(
        '\tapp.time_series.currents:\t branches currents results matrix (row: time, col: branch)'
        )
    print(
        '\tapp.time_series.loadings:\t branches loadings results matrix (row: time, col: branch)'
        )
    print(
        '\tapp.time_series.losses:\t branches losses results matrix (row: time, col: branch)'
        )
    print('\n\nVoltage stability power flow results:')
    print(
        '\tapp.voltage_stability.continuation_voltage:\t Voltage values for every power multiplication factor.'
        )
    print(
        '\tapp.voltage_stability.continuation_lambda:\t Value of power multiplication factor applied'
        )
    print(
        '\tapp.voltage_stability.continuation_power:\t Power values for every power multiplication factor.'
        )
    print('\n\nMonte Carlo power flow results:')
    print('\tapp.monte_carlo.V_avg:\t nodal voltage average result.')
    print('\tapp.monte_carlo.I_avg:\t branch current average result.')
    print('\tapp.monte_carlo.Loading_avg:\t branch loading average result.')
    print('\tapp.monte_carlo.Losses_avg:\t branch losses average result.')
    print('\tapp.monte_carlo.V_std:\t nodal voltage standard deviation result.'
        )
    print(
        '\tapp.monte_carlo.I_std:\t branch current standard deviation result.')
    print(
        '\tapp.monte_carlo.Loading_std:\t branch loading standard deviation result.'
        )
    print(
        '\tapp.monte_carlo.Losses_std:\t branch losses standard deviation result.'
        )
    print('\tapp.monte_carlo.V_avg_series:\t nodal voltage average series.')
    print(
        '\tapp.monte_carlo.V_std_series:\t branch current standard deviation series.'
        )
    print(
        '\tapp.monte_carlo.error_series:\t Monte Carlo error series (the convergence value).'
        )
    print('The same for app.latin_hypercube_sampling')


def __new__(cls, *args, **kwargs):
    """ Create a new instance
        """
    if '_inst' not in vars(cls):
        cls._inst = object.__new__(cls)
    return cls._inst


def plugin_settings(settings):
    """
    Injects local settings into django settings
    """
    env_tokens = getattr(settings, 'ENV_TOKENS', {})
    auth_tokens = getattr(settings, 'AUTH_TOKENS', {})
    if env_tokens.get('ANALYTICS_API_URL'):
        settings.ANALYTICS_API_CLIENT['url'] = env_tokens['ANALYTICS_API_URL']
    if auth_tokens.get('ANALYTICS_API_KEY'):
        settings.ANALYTICS_API_CLIENT['token'] = auth_tokens[
            'ANALYTICS_API_KEY']


def methods_of(obj):
    """Get all callable methods of an object that don't start with underscore

    returns a list of tuples of the form (method_name, method)
    """
    result = []
    for fn in dir(obj):
        if callable(getattr(obj, fn)) and not fn.startswith('_'):
            result.append((fn, getattr(obj, fn), getattr(obj, fn +
                '_description', None)))
    return result


@staticmethod
def generate_address_header(addr, local_seg_id, wants_ack):
    """Generate a PCK command address header.

        :param    addr:   The module's/group's address
        :type     addr:   :class:`~LcnAddrMod` or :class:`~LcnAddrGrp`
        :param    int     local_seg_id:    The local segment id
        :param    bool    wants_ack:      Is an acknowledge requested.

        :return:    The PCK address header string.
        :rtype:     str
        """
    return '>{:s}{:03d}{:03d}{:s}'.format('G' if addr.is_group() else 'M',
        addr.get_physical_seg_id(local_seg_id), addr.get_id(), '!' if
        wants_ack else '.')


def dorequest(request, body=None, chunk=None, trailers=None):
    """This method is called after a new request is resolved to an
        application, typically by :class:`pluggdapps.web.IHTTPConnection`
        plugin. This callback will be issued when,

        * A new request without body is received, where the request data is
          available in ``request``.

        * A new request with a body is received, in which case kwarg ``body``
          gives the request body as byte-string.

        It is responsibility of this method to initialize ``request`` plugin.
        Callback :meth:`pluggdapps.web.interfaces.IHTTPRequest.handle` method.
        And finally use the :meth:`pluggdapps.web.interfaces.IHTTPRouter.route`
        method to handle request.

        ``body``,
            byte string request body.

        ``chunk``,
            tuple of (chunk-size, chunk-ext, chunk-data), where chunk-size is
            integer size of chunk-data, chunk-ext is byte string and
            chunk-data is request-chunk in byte string.

        ``trailers``,
            Dictionary of HTTP headers. instance of :class:`HTTPHeaders`
            class.
        """


def merge(x, y):
    """Given two dicts, merge them into a new dict as a shallow copy."""
    z = x.copy()
    z.update(y)
    return z


def glPushName(name: int):
    """Push the name stack

    :param name: Specifies a name that will be pushed onto the name stack.
    :type name: int
    """
    pass


def mirror_distance_image(focal_point, distance_object):
    """Usage: Find distance of image with focal point and distance of object"""
    numerator = focal_point * distance_object
    denominator = distance_object - focal_point
    return numerator / denominator


def infer_dtype(data):
    """ Infer the type of data provided

    Args
    -----
    data (iterable):

    Returns
    --------
    type

    """
    types = list(set(map(type, data)).difference({type(None)}))
    if len(types) == 0:
        dtype = type(None)
    elif len(types) == 1:
        dtype = types[0]
    else:
        msg = 'Multiple types detected in input: {}'
        raise ValueError(msg.format(map(lambda x: x.__name__, types)))
    return dtype


def wei_to_ether(wei):
    """
    Convert wei to ether
    """
    return 1.0 * wei / 10 ** 18


def hsv2rgb(h, s, v):
    """Convert color in HSV (Hue, Saturation, Value) space to RGB.  Return (R,
    G, B) as a list.  Transformation algorithm is taken from
    http://psychology.wikia.com/wiki/HSV_color_space."""
    hi = int(h / 60) % 6
    f = h / 60 - hi
    p = v * (1 - s)
    q = v * (1 - f * s)
    t = v * (1 - (1 - f) * s)
    if hi == 0:
        return v, t, p
    elif hi == 1:
        return q, v, p
    elif hi == 2:
        return p, v, t
    elif hi == 3:
        return p, q, v
    elif hi == 4:
        return t, p, v
    elif hi == 5:
        return v, p, q


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 ireq_satisfied_by_existing_pin(ireq, existing_pin):
    """
    Return True if the given InstallationRequirement is satisfied by the
    previously encountered version pin.
    """
    version = next(iter(existing_pin.req.specifier)).version
    return ireq.req.specifier.contains(version, prereleases=existing_pin.
        req.specifier.prereleases)


@staticmethod
def escape(pattern):
    """Escape chars to use as regex search pattern."""
    return pattern.replace('*', '\\*').replace('-', '\\-')


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

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


def set_python_main(option, opt_str, value, parser):
    """
	Set the main Python code; after contexts are initialized, main is ran.
	"""
    main = value, option.python_loader
    setattr(parser.values, option.dest, main)
    if not parser.allow_interspersed_args:
        parser.rargs.insert(0, '--')


def format_description(string):
    """
    Adds the header and a final new line to the issue description string.
    """
    return str('**Descrição:**\n---\n\n' + string + '\n' * 2)


def getDataShape(indices):
    """
  Create new data shape based on the selected index array (from idx)

  Parameters
  ----------
  indices:  ndarray

  Returns
  -------
  out : ndarray
  """
    dataShape = []
    for i in range(len(indices)):
        dataShape.append(len(indices[i]))
    dataShape = tuple(dataShape)
    return dataShape


def clean_node_tree(node_tree):
    """Clear all nodes in a shader node tree except the output.

    Returns the output node
    """
    nodes = node_tree.nodes
    for node in list(nodes):
        if not node.type == 'OUTPUT_MATERIAL':
            nodes.remove(node)
    return node_tree.nodes[0]


@staticmethod
def _message_soap(liste_contenus):
    """
        | Méthode privée statique construisant le squelette du message SOAP.
        | Cette méthode est appelée par get_message_soap.

        Entrée:

        liste_contenus
            La liste des contenus à intégrer au message XOP/MTOM. Les valeurs
            possibles sont "fichierDemande", "certificat", "numUnique",
            "dateNouveauDaloDepuisLe" et "dateRadiationDepuisLe".

        Sortie:
            Chaine de caractères représentant le squelette du message SOAP.
        """
    if not isinstance(liste_contenus, type([])):
        raise TypeError('La liste de contenus doit être un tableau.')
    parametres = ''
    for contenu in liste_contenus:
        if contenu == 'fichierDemande':
            parametres += """      <nomFichierDemande>DEMG1226-{{ date_maintenant }}-000000.xml</nomFichierDemande>
      <fichierDemande><xop:Include href="cid:{{ xml_id }}" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></fichierDemande>
"""
        elif contenu == 'certificat':
            parametres += """      <nomCertificat>CERG1226-{{ date_maintenant }}.pem</nomCertificat>
      <certificat ws:contentType="application/x-x509-ca-cert"><xop:Include href="cid:{{ certificate }}" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></certificat>
"""
        elif contenu == 'numUnique':
            parametres += '      <numUnique>{{ num_unique }}</numUnique>\n'
        elif contenu == 'dateNouveauDaloDepuisLe':
            parametres += (
                '      <dateNouveauDaloDepuisLe>{{ date }}</dateNouveauDaloDepuisLe>\n'
                )
        elif contenu == 'dateRadiationDepuisLe':
            parametres += (
                '      <dateRadiationDepuisLe>{{ date }}</dateRadiationDepuisLe>\n'
                )
        else:
            raise Exception('Les paramètres SOAP fournis sont incorrects.')
    return parametres


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


def create_player_session(GameSessionId=None, PlayerId=None, PlayerData=None):
    """
    Adds a player to a game session and creates a player session record. Before a player can be added, a game session must have an ACTIVE status, have a creation policy of ALLOW_ALL , and have an open player slot. To add a group of players to a game session, use  CreatePlayerSessions .
    To create a player session, specify a game session ID, player ID, and optionally a string of player data. If successful, the player is added to the game session and a new  PlayerSession object is returned. Player sessions cannot be updated.
    See also: AWS API Documentation

    :example: response = client.create_player_session(
        GameSessionId='string',
        PlayerId='string',
        PlayerData='string'
    )

    :type GameSessionId: string
    :param GameSessionId: [REQUIRED]
            Unique identifier for the game session to add a player to.

    :type PlayerId: string
    :param PlayerId: [REQUIRED]
            Unique identifier for a player. Player IDs are developer-defined.

    :type PlayerData: string
    :param PlayerData: Developer-defined information related to a player. Amazon GameLift does not use this data, so it can be formatted as needed for use in the game.

    :rtype: dict
    :return: {
        'PlayerSession': {
            'PlayerSessionId': 'string',
            'PlayerId': 'string',
            'GameSessionId': 'string',
            'FleetId': 'string',
            'CreationTime': datetime(2015, 1, 1),
            'TerminationTime': datetime(2015, 1, 1),
            'Status': 'RESERVED'|'ACTIVE'|'COMPLETED'|'TIMEDOUT',
            'IpAddress': 'string',
            'Port': 123,
            'PlayerData': 'string'
        }
    }

    :returns:
    RESERVED  The player session request has been received, but the player has not yet connected to the server process and/or been validated.
    ACTIVE  The player has been validated by the server process and is currently connected.
    COMPLETED  The player connection has been dropped.
    TIMEDOUT  A player session request was received, but the player did not connect and/or was not validated within the time-out limit (60 seconds).

    """
    pass


def parse_block(lines, header=False):
    """Parse and return a single block, popping off the start of `lines`.

    If parsing a header block, we stop after we reach a line that is not a
    comment. Otherwise, we stop after reaching an empty line.

    :param lines: list of lines
    :param header: whether we are parsing a header block
    :return: list of lines that form the single block
    """
    block_lines = []
    while lines and lines[0] and (not header or lines[0].startswith('#')):
        block_lines.append(lines.pop(0))
    return block_lines


def is_int(val):
    """check when device_id numeric represented value is int"""
    try:
        int(val)
        return True
    except ValueError:
        return False


def fmtfloat(n, decimals=3, total=None):
    """Work around borken python float formatting"""
    s = '%0.*f' % (decimals, n)
    if total:
        s = (' ' * total + s)[-total:]
    return s


def isfuture(obj):
    """Check for a Future.

    This returns True when obj is a Future instance or is advertising
    itself as duck-type compatible by setting _asyncio_future_blocking.
    See comment in Future for more details.
    """
    return hasattr(obj.__class__, '_asyncio_future_blocking'
        ) and obj._asyncio_future_blocking is not None


def rint(value):
    """
    >>> rint(0.5) == 0
    True
    >>> rint(0.501) == 1
    True
    >>> rint(1.5) == 2
    True
    """
    ret = round(value)
    return 2.0 * round(value / 2.0) if abs(ret - value) == 0.5 else ret


@classmethod
def get(cls, format):
    """
        Gets an emitter, returns the class and a content-type.
        """
    if format in cls.EMITTERS:
        return cls.EMITTERS.get(format)
    raise ValueError('No emitters found for type %s' % format)


def get_theta_params(pkey, kind='dpm'):
    """ set and return loc, scale of parameter pkey
    ::Arguments::
        pkey (str): parameter name to get loc and scale for sampling
    ::Returns::
        theta[pkey] (tuple): (loc, scale)
    """
    theta = {'a': (0.35, 0.15), 'si': (0.001, 0.1), 'sso': (0.05, 0.035),
        'ssv': (-0.5, 0.3), 'tr': (0.25, 0.075), 'v': (0.8, 0.3), 'xb': (
        1.0, 0.35), 'z': (0.3, 0.2)}
    thetaRL = {'AX': (0.0005, 0.3), 'BX': (0.001, 0.2), 'PX': (0.0001,
        0.005), 'vd': (0.5, 0.5), 'vi': (0.3, 0.4)}
    if 'irace' in kind:
        mu, sigma = theta['ssv']
        theta['ssv'] = abs(mu), sigma
    theta.update(thetaRL)
    return theta[pkey]


def build_redirect_url(request, default_url):
    """
    Retrieve redirect url from session.

    Use default if retrieved one is broken or not safe.
    """
    url = request.session.get('login_redirect_url')
    if not url or '//' in url or ' ' in url:
        url = default_url
    try:
        del request.session['login_redirect_url']
    except KeyError:
        pass
    return url


def getId():
    """Return the id of the object as a string.

        This method should be used in preference to accessing an id
        attribute of an object directly. The getId method is public.
        """


def set_to_interval_set(s):
    """ Convert python set to interval set

    >>> set_to_interval_set(set())
    []
    >>> set_to_interval_set({1, 2, 5, 7, 9, 10, 11})
    [(1, 2), (5, 5), (7, 7), (9, 11)]
    """
    intervals = []
    l = list(s)
    l.sort()
    if len(l) > 0:
        i = 0
        current_interval = [l[i], l[i]]
        i += 1
        while i < len(l):
            if l[i] == current_interval[1] + 1:
                current_interval[1] = l[i]
            else:
                intervals.append(tuple(current_interval))
                current_interval = [l[i], l[i]]
            i += 1
        if current_interval not in intervals:
            intervals.append(tuple(current_interval))
    return intervals


def lookup_ssh_host_config(hostname, config):
    """
    Provided only as a backward-compatible wrapper around `.SSHConfig`.
    """
    return config.lookup(hostname)


def prepend_point_to_extension(extension):
    """ Prepends a point to the extension of it doesn't already start with it
    """
    if extension.startswith('.'):
        return extension
    else:
        return '.' + extension


def from_twos_complement(val):
    """
    >>> bin(from_twos_complement(7))
    '0b111'
    >>> from_twos_complement(-7)
    249
    >>> bin(from_twos_complement(-7))
    '0b11111001'
    >>> bin(from_twos_complement(-128))
    '0b10000000'
    """
    if val & 128:
        val = -((val ^ 255) + 1)
    return val


@classmethod
def _get_atr(cls, df, window=None):
    """ Average True Range

        The average true range is an N-day smoothed moving average (SMMA) of
        the true range values.  Default to 14 days.
        https://en.wikipedia.org/wiki/Average_true_range

        :param df: data
        :return: None
        """
    if window is None:
        window = cls.ATR_SMMA
        column_name = 'atr'
    else:
        window = int(window)
        column_name = 'atr_{}'.format(window)
    tr_smma_column = 'tr_{}_smma'.format(window)
    df[column_name] = df[tr_smma_column]
    cls._drop_columns(df, [tr_smma_column])


def skip_to_nonblankline(enumstream, strip=True):
    """skip to non-blank line and returns it,

    enumstream yields (lineno, line)
    strip chooses wheter returned line is stripped (strip==True) or not

    (lineno, line) is retuned
    """
    while True:
        lineno, line = next(enumstream)
        strippedline = line.strip()
        if strippedline:
            if strip:
                return lineno, strippedline
            else:
                return lineno, line


def ip_bin_to_str(ip_num):
    """
    转换ip格式，从bin转为str
    :param ip_num:
    :return:
    """
    import socket
    return socket.inet_ntoa(ip_num)


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

        :param DisabledDomainInvitesDetails val:
        :rtype: EventDetails
        """
    return cls('disabled_domain_invites_details', val)


def render_resources(namespace):
    """ render resources for the namespace
        """


def set_run_validators(run):
    """
    Set whether or not validators are run.  By default, they are run.
    """
    if not isinstance(run, bool):
        raise TypeError("'run' must be bool.")
    global _run_validators
    _run_validators = run


def list_tags_for_resource(ResourceName=None, Filters=None):
    """
    Lists all tags on an Amazon RDS resource.
    For an overview on tagging an Amazon RDS resource, see Tagging Amazon RDS Resources .
    See also: AWS API Documentation

    Examples
    This example lists information about all tags associated with the specified DB option group.
    Expected Output:

    :example: response = client.list_tags_for_resource(
        ResourceName='string',
        Filters=[
            {
                'Name': 'string',
                'Values': [
                    'string',
                ]
            },
        ]
    )

    :type ResourceName: string
    :param ResourceName: [REQUIRED]
            The Amazon RDS resource with tags to be listed. This value is an Amazon Resource Name (ARN). For information about creating an ARN, see Constructing an RDS Amazon Resource Name (ARN) .

    :type Filters: list
    :param Filters: This parameter is not currently supported.
            (dict) --This type is not currently supported.
            Name (string) -- [REQUIRED]This parameter is not currently supported.
            Values (list) -- [REQUIRED]This parameter is not currently supported.
            (string) --

    :rtype: dict
    :return: {
        'TagList': [
            {
                'Key': 'string',
                'Value': 'string'
            },
        ]
    }

    """
    pass


def place2f(x):
    """Converts a basilar membrane place (mm) to a frequency (Hz)

        Takes a basilar membrane place (mm), and computes a frequency (Hz),
        using the Greenwood equation, and constants suitable for human ears.

        Parameters
        ----------
        x : scalar
            A basilar membrane place, in mm.

        Returns
        -------
        f : scalar
            A frequency, in Hz.
    """
    return 165.4 * (10 ** (0.06 * x) - 0.88)


def encoding_dtype(xarr):
    """Get dtype encoding info

    Parameters
    ----------
    xarr : xarray.DataArray or np.ndarray
        DataArray to consider

    Returns
    -------
    dict[str, np.dtype]
        Datatype information for encoding (e.g., ``{'dtype': np.float32}``)

    """
    return {'dtype': xarr.dtype}


def listElem(item):
    """
    Convert to a list element
    """
    return [item]


def render_template(template_name, *vargs, **kwargs):
    """ Render a simple template in your application """
    pass


def equal(x, y):
    """Compares whether the elements are equal.

    Parameters
    ----------
    x, y : Tensor
        The two tensors

    Returns
    -------
    Boolean tensor
        The result, with the same shape as input.
    """
    pass


def stable_hash(x):
    """A hash of `x` that is stable across program runs.

  Background:
  As of Python 3, `hash()` is given a fresh seed every time the interpret
  starts; hash codes are not stable without setting the env var
  `PYTHONHASHSEED`.

  Can we just simply adjust for the seed programmatically?
  Note that while it is possible to get the hash seed at runtime:
   * https://stackoverflow.com/questions/41088635/extract-hash-seed-in-unit-testing
  Python doesn't use the seed in an easily-inverted way:
   * https://github.com/python/cpython/blob/630c8df5cf126594f8c1c4579c1888ca80a29d59/Python/pyhash.c#L237

  Thus for stability (and even light portability), we leverage Python
  serialization to provide a key for `x`.
  """
    try:
        import cloudpickle as pkl
    except ImportError:
        import pickle as pkl
    key = pkl.dumps(x)
    import hashlib
    return int(hashlib.md5(key).hexdigest(), 16)


def default_font():
    """
    Content of Font tab.

    Arguments:
    None

    Return:
    Content items as list
    """
    items = [['Font', '5', float, '', 'PLAIN', '', ''], ['Width adjustment',
        '1', float, '', 'PLAIN', '', ''], ['Height adjustment', '1', float,
        '', 'PLAIN', '', ''], ['Start button', '25', float, '', 'PLAIN', '',
        ''], ['Notification edit', '40', float, '', 'PLAIN', '', ''], [
        'Notification check', '25', float, '', 'PLAIN', '', ''], [
        'Notification button', '30', float, '', 'PLAIN', '', ''], [
        'Mount button', '80', float, '', 'PLAIN', '', ''], ['Frame entry',
        '5', float, '', 'PLAIN', '', ''], ['Frame button', '8', float, '',
        'PLAIN', '', ''], ['Frame label', '8', float, '', 'PLAIN', '', ''],
        ['Setting widget', '50', float, '', 'PLAIN', '', ''], [
        'Setting widget large', '50', float, '', 'PLAIN', '', ''], [
        'Status name', '12', float, '', 'PLAIN', '', ''], ['Status info',
        '12', float, '', 'PLAIN', '', ''], ['Status quota', '12', float, '',
        'PLAIN', '', ''], ['Tab width', '50', float, '', 'PLAIN', '', ''],
        ['Widget height', '3', float, '', 'PLAIN', '', ''], ['Tab height',
        '5', float, '', 'PLAIN', '', '']]
    return items


def compare_version(version1, version2):
    """
    Compare version strings.
    Return 1 if version1 is after version2;
          -1 if version1 is before version2;
           0 if two versions are the same.
    """
    v1_arr = version1.split('.')
    v2_arr = version2.split('.')
    len1 = len(v1_arr)
    len2 = len(v2_arr)
    len_max = max(len1, len2)
    for x in range(len_max):
        v1_token = 0
        if x < len1:
            v1_token = int(v1_arr[x])
        v2_token = 0
        if x < len2:
            v2_token = int(v2_arr[x])
        if v1_token < v2_token:
            return -1
        if v1_token > v2_token:
            return 1
    return 0


def seq_norm_bbox_values(bboxes, height, width):
    """Sequence and normalize bounding box values.

    Args:
        bboxes (:obj:`list` of :obj:`carpedm.data.util.BBox`):
            Bounding boxes to process.
        width (int): Width (in pixels) of image bboxes are in.
        height (int): Height (in pixels) of image bboxes are in.

    Returns:
        tuple: :obj:`tuple` containing:

            :obj:`list` of :obj:`float`: Normalized minimum x-values

            :obj:`list` of :obj:`float`: Normalized minimum y-values

            :obj:`list` of :obj:`float`: Normalized maximum x-values

            :obj:`list` of :obj:`float`: Normalized maximum y-values
    """
    xmin, ymin, xmax, ymax = [], [], [], []
    for b in bboxes:
        xmin.append(b.xmin / width)
        ymin.append(b.ymin / height)
        xmax.append(b.xmax / width)
        ymax.append(b.ymax / height)
    return xmin, ymin, xmax, ymax


def intersect(i1, i2):
    """ Does the interval intersect with i2?
        """
    return (i1.inf <= i2.sup and i2.inf <= i1.sup or i2.inf <= i1.sup and
        i1.inf <= i2.sup)


def sort_closeness(replicas, location):
    """
    Return a list of replicas sorted by AGIS closeness.
    :param replicas : A dict with RSEs as values and replicas as keys (URIs).
    :param location: Location dictionary containing {'ip', 'fqdn', 'site'}
    """
    return replicas


@classmethod
def sort(cls, items, metric, verbose=False, **kwargs):
    """
        Sort `items` with respect to `metric` such that the result has minimal loss according to
        `Solver.loss`.

        Parameters
        ----------
        items : sequence of 2-sequences
            The sequence to be sorted. Each item must be represented by two values
            (``item[0], item[1]``) which in turn must be compatible with the given metric.
            E.g.: ``[(0.1, 0.3), (0.2, 0.6), (0.4, 0.5), ...]``.
        metric : dominosort.metrics.Metric
            The metric to be used for computing differences between items' heads and tails.
            ``difference = metric(x[1], y[0])`` for two items `x`, `y`.
        verbose : bool, default=True
        **kwargs
            Additional arguments for the `scipy.optimize.linprog` solver. Those arguments are
            passed as the ``options`` keyword argument.

        Returns
        -------
        sorted : list
            The sorted items.

        Raises
        ------
        UserWarning
            Issues a warning via `warnings.warn` if no optimal sort order could be determined.
            This can be the case if for example the number of iterations for the underlying
            solver is too small. The warning contains as a message the most recent message
            from the solver. In this case the given `items` are returned.
        """
    raise NotImplementedError


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 dumpj(game):
    """Dump a game to json"""
    return game.to_json()


def parse_region_string(s):
    """parse a genomic region string.

    Returns tuple of contig, start, end. Missing values are None.
    """
    if not s:
        return None, None, None
    if ':' in s:
        contig, coords = s.split(':')
        if '-' in coords:
            start, end = list(map(int, coords.split('-')))
        else:
            start = int(start)
            end = None
        return contig, start, end
    else:
        return s, None, None


@classmethod
def coerce_boolean(cls, value):
    """ Coerce a Python value to a Cypher Boolean.

        :rtype: :py:class:`bool`
        """
    return bool(value)


def get_tool_template():
    """ Internal project data

    a dict with the following keys is returned:
    source_paths - a list of source paths derived from s
    include_paths - a list of include paths derived from sources
    include_files - a dict of include files used in the copy function mapping
                    groups to the files with each group (a list)
    source_files_c - a dict of c source files mapping groups to a list of files
                     within the group
    source_files_cpp - a dict of c++ source files mapping groups to a list of
                       files within the group
    source_files_s - a dict of groups to lists of assembly source files within
                     each group
    source_files_obj - dict of groups to lists of object files within each group
    source_files_lib - a dict of libraries mapping a group to a list of
                       libraries
    singular - a Boolean value indicating whether this is a singular project or
               part of a workspace
    output_dir - a dict containing:
      path - directory that output files are generated into by the exported
             project, relative to the current directory
      rel_path - the relative path to the root
      rel_count - the number of steps to the root
    macros - a list of c pre-processor macros
    template - a filename of an external template file
    misc - a dict of miscellaneous tool options

    """
    internal_template = {'source_paths': [], 'include_paths': [],
        'include_files': {}, 'source_files_c': {}, 'source_files_cpp': {},
        'source_files_s': {}, 'source_files_obj': {}, 'source_files_lib': {
        }, 'singular': True, 'output_dir': {'path': '', 'rel_path': '',
        'rel_count': ''}, 'macros': [], 'template': None, 'misc': {}}
    return internal_template


def parse_stats(stats):
    """
    Convert stats from a mixed string or dictionary representation
    to only dictionaries.
    """
    is_one = False
    if not isinstance(stats, list):
        is_one = True
        stats = [stats]
    else:
        stats = stats.copy()
    for i in range(len(stats)):
        if isinstance(stats[i], str):
            stats[i] = {'tag': stats[i], 'settings': {}}
    return stats[0] if is_one else stats


@staticmethod
def _convolve_image(image, kernel, fast=True):
    """Convolve the image with the provided kernel."""
    if fast:
        from astropy.convolution import convolve_fft
        return convolve_fft(image, kernel)
    from astropy.convolution import convolve
    return convolve(image, kernel)


def readEpochLines(filename, header, epoch_start, epoch_end):
    """
    Read lines from collectd CSV file and return
    a list containing the lines that match the given time interval
    Arguments:
        filename: The path and name to the data file to be read
        header: Boolean describing if header should be included in the result
        epoch_start: The start epoch (timestamp) of the wanted timeframe
        epoch_end: The end epoch (timestamp) of the wanted timeframe
    Returns:
        a list containing the lines between the start and end epoch.
    """
    line = ''
    output = list()
    with open(filename, 'r') as infile:
        if header:
            output.append(infile.readline()[:-1])
        else:
            infile.readline()
        """
        line1 = infile.readline()
        line2 = infile.readline()
        epoch1 = float(line1.split(",", 1)[0])
        epoch2 = float(line2.split(",", 1)[0])
        step = (epoch2 - epoch1)
        epochdiff = epoch_start - epoch1
        if epochdiff > 0:
            infile.readlines(int(len(line1)*(epochdiff/(step + 1))))
        """
        while True:
            line = infile.readline()
            if len(line) == 0:
                break
            line = line[:-1]
            current_epoch = float(line.split(',', 1)[0])
            if current_epoch > epoch_end:
                break
            elif current_epoch >= epoch_start:
                output.append(line)
    return output


def split_dict(dic, *keys):
    """Return two copies of the dict.  The first will contain only the
    specified items.  The second will contain all the *other* items from the
    original dict.

    Example::

        >>> split_dict({"From": "F", "To": "T", "Received", R"}, "To", "From")
        ({"From": "F", "To": "T"}, {"Received": "R"})
    """
    for k in keys:
        if k not in dic:
            raise KeyError('key {0!r} is not in original mapping'.format(k))
    r1 = {}
    r2 = {}
    for k, v in dic.items():
        if k in keys:
            r1[k] = v
        else:
            r2[k] = v
    return r1, r2


def evaluate_group(flags):
    """evaluate group will take a list of flags (eg:

        [True, and, False, or, True]

       And read through the logic to determine if the image result
       is to be flagged. This is how we combine a set of criteria in
       a group to come to a final decision.
    """
    flagged = False
    first_entry = True
    while len(flags) > 0:
        flag = flags.pop(0)
        if flag == 'and':
            flag = flags.pop(0)
            flagged = flag and flagged
        elif flag == 'or':
            flag = flags.pop(0)
            flagged = flag or flagged
        elif first_entry is True:
            flagged = flag
        else:
            flagged = flagged and flag
        first_entry = False
    return flagged


def update(*args, **kwds):
    """od.update(E, **F) -> None.  Update od from dict/iterable E and F.

        If E is a dict instance, does:           for k in E: od[k] = E[k]
        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
        In either case, this is followed by:     for k, v in F.items(): od[k] = v

        """
    if len(args) > 2:
        raise TypeError(
            'update() takes at most 2 positional arguments (%d given)' % (
            len(args),))
    elif not args:
        raise TypeError('update() takes at least 1 argument (0 given)')
    self = args[0]
    other = ()
    if len(args) == 2:
        other = args[1]
    if isinstance(other, dict):
        for key in other:
            self[key] = other[key]
    elif hasattr(other, 'keys'):
        for key in other.keys():
            self[key] = other[key]
    else:
        for key, value in other:
            self[key] = value
    for key, value in kwds.items():
        self[key] = value


def method_overridden(method_name, klass, instance):
    """
    Determine if a method has been overridden.
    """
    method = getattr(klass, method_name)
    default_method = getattr(method, '__func__', method)
    return default_method is not getattr(instance, method_name).__func__


@classmethod
def is_multi_config_generator(cls, generator: str) ->bool:
    """Whether or not string ``generator`` is a multi-config generator."""
    return generator in cls.visual_studio_generators | cls.other_generators


def single_gen(msg):
    """Turn a single message into a plan

    If ``lambda x: yield x`` were valid Python, this would be equivalent.
    In Python 3.6 or 3.7 we might get lambda generators.

    Parameters
    ----------
    msg : Msg
        a single message

    Yields
    ------
    msg : Msg
        the input message
    """
    return (yield msg)


def sliding_intervals_gen(coordgen, interval_size=1000):
    """
    Generate sliding window coordinate intervals over the entire reference genome provided
    """
    for chr_name, chr_len in coordgen.chr_name_len.items():
        for start in range(0, chr_len, interval_size):
            end = (start + interval_size if start + interval_size <=
                chr_len else chr_len)
            yield coordgen(chr_name, start, end)


def filter_packages(lines):
    """Get rid of comments. Return the packages list.

    warning: it removes everything after a '#'. Do some requirement
    files use it to specify the package version ?

    """
    packages = []
    for line in lines:
        if not line.startswith('#') and line.strip():
            if '#' in line:
                line = line.split('#')[0]
            packages.append(line.strip())
    return packages


def migrate(engine):
    """Return the number of rows migrated."""
    return 0


def quaternion_multiply(r, q):
    """Multiplies two quaternions.

    Parameters
    ----------
    r : list
        Quaternion as a list of four real values ``[rw, rx, ry, rz]``.
    q : list
        Quaternion as a list of four real values ``[qw, qx, qy, qz]``.

    Returns
    -------
    list
        Quaternion :math:`p = rq` as a list of four real values ``[pw, px, py, pz]``.

    Notes
    -----
    Multiplication of two quaternions :math:`p = rq` can be interpreted as applying rotation :math:`r` to an orientation :math:`q`,
    provided that both :math:`r` and :math:`q` are unit-length.
    The result is also unit-length.
    Multiplication of quaternions is not commutative!

    References
    ----------
    .. _mathworld quaternion: http://mathworld.wolfram.com/Quaternion.html

    """
    rw, rx, ry, rz = r
    qw, qx, qy, qz = q
    pw = rw * qw - rx * qx - ry * qy - rz * qz
    px = rw * qx + rx * qw + ry * qz - rz * qy
    py = rw * qy - rx * qz + ry * qw + rz * qx
    pz = rw * qz + rx * qy - ry * qx + rz * qw
    return [pw, px, py, pz]