<commit_before>#!/havocbot

from havocbot.plugin import HavocBotPlugin
import logging

logger = logging.getLogger(__name__)

class HelpPlugin(HavocBotPlugin):

    @property
    def plugin_description(self):
        return "basics of the bot"

    @property
    def plugin_short_name(self):
        return "help"

    @property
    def plugin_usages(self):
        return [
            ("!help", None, "display basic help information"),
            ("!help plugins", None, "list the enabled plugins"),
            ("!help plugin <plugin>", None, "display detailed information about a specific plugin"),
        ]

    @property
    def plugin_triggers(self):
        return [
            ("!help", self.start),
            ("!help plugins", self.help_plugins),
            ("!help plugin", self.help_plugin),
        ]

    def init(self, havocbot):
        self.havocbot = havocbot

        # This will register the above triggers with havocbot
        self.havocbot.register_triggers(self.plugin_triggers)

    def shutdown(self):
        logger.debug("shutdown() - about to unregister_triggers")
        self.havocbot.unregister_triggers(self.plugin_triggers)
        logger.debug("shutdown() - about to set self.havocbot to None")
        self.havocbot = None
        logger.debug("shutdown() finished")

    def start(self, callback, message, **kwargs):
        callback_message_list = ["HavocBot can help you with the following."]
        for usage_message in self.get_usage_lines_from_plugin_as_list(self.plugin_usages):
            callback_message_list.append(usage_message)

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def help_plugins(self, callback, message, **kwargs):
        callback_message_list = []

        tuples_list = self.get_help_list_sorted()

        callback_message_list.append("Loaded Plugins - " + ", ".join([("%s (%s)" % (i[1], i[0])) for i in tuples_list]))
        callback_message_list.append("Details about a specific plugin are available with '!help plugin <plugin>'")

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def help_plugin(self, callback, message, **kwargs):
        callback_message_list = []

        tuples_list = self.get_help_list_sorted()
        words = message.text.split()

        if len(words) >= 3:
            temp_list = []
            for word in words[2:]:
                temp_list += [item for item in tuples_list if word in [item[0], item[1]]]
            if temp_list is not None and len(temp_list) > 0:
                callback_message_list = self.get_plugin_help_matching_list(temp_list)
            else:
                callback_message_list.append("No matching plugins were found. Plugin names are listed at !help plugins")
        else:
            # Print the plugin short name with the regular name in parenthesis as a joined string
            callback_message_list.append("Loaded Plugins - " + ", ".join([("%s (%s)" % (i[1], i[0])) for i in tuples_list]))
            callback_message_list.append("Details about a specific plugin are available with '!help plugin <plugin>'")

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def get_plugin_help_matching_list(self, tuples_list):
        new_list = []

        for (plugin_name, plugin_short_name, dictionary) in tuples_list:
            if dictionary is not None:
                if 'description' in dictionary:
                    new_list.append("%s (%s) - %s" % (plugin_short_name, plugin_name, dictionary['description']))
                if 'usage' in dictionary:
                    for item in self.get_usage_lines_from_plugin_as_list(dictionary['usage']):
                        new_list.append(item)
            else:
                new_list.append("%s" % (plugin_short_name, plugin_name))

        return new_list

    def get_usage_lines_from_plugin_as_list(self, usages_tuples):
        usage_list = []

        for (usage, example, description) in usages_tuples:
            if usage is not None:
                if description is not None:
                    if example is not None:
                        message = "    Usage: %s - %s - (example '%s')" % (usage, description, example)
                        usage_list.append(message)
                    else:
                        message = "    Usage: %s - %s" % (usage, description)
                        usage_list.append(message)
                else:
                    message = "    Usage: %s" % (usage)
                    usage_list.append(message)

        return usage_list

    def get_help_list_sorted(self):
        tuples_list = []

        for statefulplugin in self.havocbot.plugins_core:
            help_tuple_item = self.get_help_item_tuple(statefulplugin.handler)
            tuples_list.append(help_tuple_item)

        for statefulplugin in self.havocbot.plugins_custom:
            help_tuple_item = self.get_help_item_tuple(statefulplugin.handler)
            tuples_list.append(help_tuple_item)

        # Sort in place with the first item in the tuple being the key
        tuples_list.sort(key=lambda help_item: help_item[1])

        return tuples_list

    # Returns a tuple that contains two items. First item is the name of the plugin as a string. Second item is a dictionary containing usage tuples, description, example, and the short name
    def get_help_item_tuple(self, plugin):
        help_tuple_item = ()

        if plugin is not None:
            # Capture the name of the plugin
            plugin_name = type(plugin).__name__
            plugin_short_name = plugin.plugin_short_name

            plugin_item_dictionary = {}

            if plugin.plugin_description is not None:
                plugin_item_dictionary['description'] = plugin.plugin_description

            # if plugin.plugin_short_name is not None:
            #     plugin_item_dictionary['short_name'] = plugin.plugin_short_name

            if plugin.plugin_usages is not None:
                plugin_item_dictionary['usage'] = plugin.plugin_usages

            help_tuple_item = (plugin_name, plugin_short_name, plugin_item_dictionary)

        return help_tuple_item

# Make this plugin available to HavocBot
havocbot_handler = HelpPlugin()
<commit_msg>fix for help plugin showing duplicate messages<commit_after>#!/havocbot

from havocbot.plugin import HavocBotPlugin
import logging

logger = logging.getLogger(__name__)

class HelpPlugin(HavocBotPlugin):

    @property
    def plugin_description(self):
        return "basics of the bot"

    @property
    def plugin_short_name(self):
        return "help"

    @property
    def plugin_usages(self):
        return [
            ("!help", None, "display basic help information"),
            ("!help plugins", None, "list the enabled plugins"),
            ("!help plugin <plugin>", None, "display detailed information about a specific plugin"),
        ]

    @property
    def plugin_triggers(self):
        return [
            ("!help", self.start),
            ("!help plugins", self.help_plugins),
            ("!help plugin\s", self.help_plugin),
        ]

    def init(self, havocbot):
        self.havocbot = havocbot

        # This will register the above triggers with havocbot
        self.havocbot.register_triggers(self.plugin_triggers)

    def shutdown(self):
        logger.debug("shutdown() - about to unregister_triggers")
        self.havocbot.unregister_triggers(self.plugin_triggers)
        logger.debug("shutdown() - about to set self.havocbot to None")
        self.havocbot = None
        logger.debug("shutdown() finished")

    def start(self, callback, message, **kwargs):
        callback_message_list = ["HavocBot can help you with the following."]
        for usage_message in self.get_usage_lines_from_plugin_as_list(self.plugin_usages):
            callback_message_list.append(usage_message)

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def help_plugins(self, callback, message, **kwargs):
        callback_message_list = []

        tuples_list = self.get_help_list_sorted()

        callback_message_list.append("Loaded Plugins - " + ", ".join([("%s (%s)" % (i[1], i[0])) for i in tuples_list]))
        callback_message_list.append("Details about a specific plugin are available with '!help plugin <plugin>'")

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def help_plugin(self, callback, message, **kwargs):
        callback_message_list = []

        tuples_list = self.get_help_list_sorted()
        words = message.text.split()

        if len(words) >= 3:
            temp_list = []
            for word in words[2:]:
                temp_list += [item for item in tuples_list if word in [item[0], item[1]]]
            if temp_list is not None and len(temp_list) > 0:
                callback_message_list = self.get_plugin_help_matching_list(temp_list)
            else:
                callback_message_list.append("No matching plugins were found. Plugin names are listed at !help plugins")
        else:
            # Print the plugin short name with the regular name in parenthesis as a joined string
            callback_message_list.append("Loaded Plugins - " + ", ".join([("%s (%s)" % (i[1], i[0])) for i in tuples_list]))
            callback_message_list.append("Details about a specific plugin are available with '!help plugin <plugin>'")

        if message.channel:
            callback.send_messages_from_list(channel=message.channel, message=callback_message_list, type_=message.type_)

    def get_plugin_help_matching_list(self, tuples_list):
        new_list = []

        for (plugin_name, plugin_short_name, dictionary) in tuples_list:
            if dictionary is not None:
                if 'description' in dictionary:
                    new_list.append("%s (%s) - %s" % (plugin_short_name, plugin_name, dictionary['description']))
                if 'usage' in dictionary:
                    for item in self.get_usage_lines_from_plugin_as_list(dictionary['usage']):
                        new_list.append(item)
            else:
                new_list.append("%s" % (plugin_short_name, plugin_name))

        return new_list

    def get_usage_lines_from_plugin_as_list(self, usages_tuples):
        usage_list = []

        for (usage, example, description) in usages_tuples:
            if usage is not None:
                if description is not None:
                    if example is not None:
                        message = "    Usage: %s - %s - (example '%s')" % (usage, description, example)
                        usage_list.append(message)
                    else:
                        message = "    Usage: %s - %s" % (usage, description)
                        usage_list.append(message)
                else:
                    message = "    Usage: %s" % (usage)
                    usage_list.append(message)

        return usage_list

    def get_help_list_sorted(self):
        tuples_list = []

        for statefulplugin in self.havocbot.plugins_core:
            help_tuple_item = self.get_help_item_tuple(statefulplugin.handler)
            tuples_list.append(help_tuple_item)

        for statefulplugin in self.havocbot.plugins_custom:
            help_tuple_item = self.get_help_item_tuple(statefulplugin.handler)
            tuples_list.append(help_tuple_item)

        # Sort in place with the first item in the tuple being the key
        tuples_list.sort(key=lambda help_item: help_item[1])

        return tuples_list

    # Returns a tuple that contains two items. First item is the name of the plugin as a string. Second item is a dictionary containing usage tuples, description, example, and the short name
    def get_help_item_tuple(self, plugin):
        help_tuple_item = ()

        if plugin is not None:
            # Capture the name of the plugin
            plugin_name = type(plugin).__name__
            plugin_short_name = plugin.plugin_short_name

            plugin_item_dictionary = {}

            if plugin.plugin_description is not None:
                plugin_item_dictionary['description'] = plugin.plugin_description

            # if plugin.plugin_short_name is not None:
            #     plugin_item_dictionary['short_name'] = plugin.plugin_short_name

            if plugin.plugin_usages is not None:
                plugin_item_dictionary['usage'] = plugin.plugin_usages

            help_tuple_item = (plugin_name, plugin_short_name, plugin_item_dictionary)

        return help_tuple_item

# Make this plugin available to HavocBot
havocbot_handler = HelpPlugin()
<|endoftext|>


<commit_before># -*- mode: python; indent-tabs-mode: nil -*-

import math
import numpy
import pykalman.unscented
import functools
import logging

import mlat.geodesy
import mlat.constants

glogger = logging.getLogger("kalman")
_kalman_filter = pykalman.unscented.AdditiveUnscentedKalmanFilter()   # our shared filter

def _kalman_observation(state, *, positions):
    """Kalman filter observation function.

    Given state (position,velocity) and a list of N receiver positions,
    return N-1 pseudorange observations (each relative to the first receiver's
    pseudorange) and an altitude."""

    x, y, z, vx, vy, vz = state

    n = len(positions)
    obs = numpy.zeros(n)

    _, _, alt = mlat.geodesy.ecef2llh((x, y, z))
    obs[0] = alt

    zx, zy, zz = positions[0]
    zero_range = ((zx - x)**2 + (zy - y)**2 + (zz - z)**2)**0.5

    for i in range(1, n):
        rx, ry, rz = positions[i]
        obs[i] = ((rx - x)**2 + (ry - y)**2 + (rz - z)**2)**0.5 - zero_range

    return obs

def _kalman_transition(state, *, dt):
    """Kalman filter transition function.

    Given state (position,velocity) and a time delta dt,
    return the updated state after dt.

    This is a constant-velocity model."""

    x, y, z, vx, vy, vz = state
    return numpy.array([x + vx*dt, y + vy*dt, z + vz*dt, vx, vy, vz])

class KalmanState(object):
    """Kalman filter state for a single aircraft"""

    def __init__(self, ac):
        self.ac = ac
        self._reset()

    def _reset(self):
        # the filter itself:
        self._mean = None
        self._cov = None
        self._new = True
        self._outliers = 0
        self.last_update = None

        # does the filter have useful derived data?
        self.valid = False

        # most recent values derived from filter state
        self.position = None        # ECEF
        self.velocity = None        # ECEF
        self.position_error = None  # meters
        self.velocity_error = None  # m/s

        # .. some derived values in more useful reference frames
        self.position_llh = None    # LLH
        self.velocity_enu = None    # ENU
        self.heading = None         # degrees
        self.ground_speed = None    # m/s
        self.vertical_speed = None  # m/s

    def _update_derived(self):
        """Update derived values from self._mean and self._cov"""

        if self._mean is None or self._new:
            self.valid = False
            return

        self.position = self._mean[0:3]
        self.velocity = self._mean[3:6]

        pe = numpy.trace(self._cov[0:3, 0:3])
        self.position_error = 0 if pe < 0 else math.sqrt(pe)
        ve = numpy.trace(self._cov[3:6, 3:6])
        self.velocity_error = 0 if ve < 0 else math.sqrt(ve)

        lat, lon, alt = self.position_llh = mlat.geodesy.ecef2llh(self.position)

        # rotate velocity into the local tangent plane
        lat_r = lat * mlat.constants.DTOR
        lon_r = lon * mlat.constants.DTOR
        C = numpy.array([[-math.sin(lon_r), math.cos(lon_r), 0],
                         [math.sin(-lat_r) * math.cos(lon_r), math.sin(-lat_r) * math.sin(lon_r), math.cos(-lat_r)],
                         [math.cos(-lat_r) * math.cos(lon_r), math.cos(-lat_r) * math.sin(lon_r), -math.sin(-lat_r)]])
        east, north, up = numpy.dot(C, self.velocity.T).T

        # extract speeds, headings
        self.heading = math.atan2(east, north) * 180.0 / math.pi
        if self.heading < 0:
            self.heading += 360
        self.ground_speed = math.sqrt(north**2 + east**2)
        self.vertical_speed = up

        self.valid = True

    def update(self, position_time, measurements, altitude, leastsquares_position, leastsquares_cov, distinct):
        """Update the filter given a new set of observations.

        position_time:         the time of these measurements, UTC seconds
        measurements:          a list of (receiver, timestamp, variance) tuples
        altitude:              reported altitude in meters
        leastsquares_position: the ECEF position computed by the least-squares solver
        distinct:              the number of distinct receivers (<= len(measurements))
        """

        if self._mean is None or (position_time - self.last_update > 120.0):
            # reinitialize
            self._reset()
            if distinct >= 4:
                # accept this
                self.last_update = position_time
                self._mean = numpy.array(list(leastsquares_position) + [0, 0, 0])
                self._cov = numpy.zeros((6, 6))
                self._cov[0:3, 0:3] = leastsquares_cov
                self._cov[3, 3] = self._cov[4, 4] = self._cov[5, 5] = 200**2
                return
            else:
                # nope.
                return

        if self._new and distinct < 4:
            # don't trust 3 station results until we have converged
            return

        # update filter
        zero_pr = measurements[0][1] * mlat.constants.Cair
        positions = [measurements[0][0].position]

        n = len(measurements)
        obs = numpy.zeros(n)
        obs_var = numpy.zeros(n)

        obs[0] = altitude
        obs_var[0] = 50**2

        for i in range(1, n):
            receiver, timestamp, variance = measurements[i]
            positions.append(receiver.position)
            obs[i] = timestamp * mlat.constants.Cair - zero_pr
            obs_var[i] = (variance + measurements[0][2]) * mlat.constants.Cair**2

        obs_covar = numpy.diag(obs_var)

        dt = position_time - self.last_update
        accel = 0.5   # m/s^2

        trans_covar = numpy.zeros((6, 6))
        trans_covar[0, 0] = trans_covar[1, 1] = trans_covar[2, 2] = accel**2 * 0.25*dt**4
        trans_covar[0, 3] = trans_covar[3, 0] = accel**2 * 0.5*dt**3
        trans_covar[1, 4] = trans_covar[4, 1] = accel**2 * 0.5*dt**3
        trans_covar[2, 5] = trans_covar[5, 2] = accel**2 * 0.5*dt**3
        trans_covar[3, 3] = trans_covar[4, 4] = trans_covar[5, 5] = accel**2 * dt**2

        trans_covar = trans_covar * accel**2

        try:
            transition_function = functools.partial(_kalman_transition, dt=dt)
            observation_function = functools.partial(_kalman_observation, positions=positions)

            #
            # This is extracted from pykalman's AdditiveUnscentedFilter.filter_update()
            # because we want to access the intermediate (prediction) result to decide
            # whether to accept this observation or not.
            #

            # make sigma points
            moments_state = pykalman.unscented.Moments(self._mean, self._cov)
            points_state = pykalman.unscented.moments2points(moments_state)

            # Predict.
            (_, moments_pred) = (
                pykalman.unscented.unscented_filter_predict(
                    transition_function=transition_function,
                    points_state=points_state,
                    sigma_transition=trans_covar
                )
            )
            points_pred = pykalman.unscented.moments2points(moments_pred)

            # Decide whether this is an outlier:
            # Get the current filter state mean and covariance
            # as an observation:
            (obs_points_pred, obs_moments_pred) = (
                pykalman.unscented.unscented_transform(
                    points_pred, observation_function,
                    sigma_noise=obs_covar
                )
            )

            # Find the Mahalanobis distance between the filter observation
            # and our new observation, using the filter's observation
            # covariance as our expected distribution.
            innovation = obs - obs_moments_pred.mean
            vi = numpy.linalg.inv(obs_moments_pred.covariance)
            mdsq = numpy.dot(numpy.dot(innovation.T, vi), innovation)

            # If the Mahalanobis distance is very large this observation is an outlier
            if mdsq > 100:
                glogger.info("{ac.icao:06X} skip innov={innovation} mdsq={mdsq}".format(
                    ac=self.ac,
                    innovation=innovation,
                    mdsq=mdsq))

                self._outliers += 1
                if self._outliers < 3:
                    # don't use this one
                    return
                glogger.info("{ac.icao:06X} reset due to outliers.".format(ac=self.ac))
                self._reset()
                return

            self._outliers = 0

            # correct filter state using the current observations
            (self._mean, self._cov) = (
                pykalman.unscented.unscented_filter_correct(
                    observation_function=observation_function,
                    moments_pred=moments_pred,
                    points_pred=points_pred,
                    observation=obs,
                    sigma_observation=obs_covar
                )
            )

            # converged enough to start reporting?
            if self._new and numpy.trace(self._cov) < 2e6:
                glogger.info("{ac.icao:06X} acquired.".format(ac=self.ac))
                self._new = False

            self.last_update = position_time
            self._update_derived()

        except Exception:
            glogger.exception("Kalman filter update failed. " +
                              "dt={dt} obs={obs} obs_covar={obs_covar} mean={mean} covar={covar}".format(
                                  dt=dt,
                                  obs=obs,
                                  obs_covar=obs_covar,
                                  mean=self._mean,
                                  covar=self._cov))
            self._reset()
            return
<commit_msg>Don't scale trans_covar by acceleration twice.<commit_after># -*- mode: python; indent-tabs-mode: nil -*-

import math
import numpy
import pykalman.unscented
import functools
import logging

import mlat.geodesy
import mlat.constants

glogger = logging.getLogger("kalman")
_kalman_filter = pykalman.unscented.AdditiveUnscentedKalmanFilter()   # our shared filter

def _kalman_observation(state, *, positions):
    """Kalman filter observation function.

    Given state (position,velocity) and a list of N receiver positions,
    return N-1 pseudorange observations (each relative to the first receiver's
    pseudorange) and an altitude."""

    x, y, z, vx, vy, vz = state

    n = len(positions)
    obs = numpy.zeros(n)

    _, _, alt = mlat.geodesy.ecef2llh((x, y, z))
    obs[0] = alt

    zx, zy, zz = positions[0]
    zero_range = ((zx - x)**2 + (zy - y)**2 + (zz - z)**2)**0.5

    for i in range(1, n):
        rx, ry, rz = positions[i]
        obs[i] = ((rx - x)**2 + (ry - y)**2 + (rz - z)**2)**0.5 - zero_range

    return obs

def _kalman_transition(state, *, dt):
    """Kalman filter transition function.

    Given state (position,velocity) and a time delta dt,
    return the updated state after dt.

    This is a constant-velocity model."""

    x, y, z, vx, vy, vz = state
    return numpy.array([x + vx*dt, y + vy*dt, z + vz*dt, vx, vy, vz])

class KalmanState(object):
    """Kalman filter state for a single aircraft"""

    def __init__(self, ac):
        self.ac = ac
        self._reset()

    def _reset(self):
        # the filter itself:
        self._mean = None
        self._cov = None
        self._new = True
        self._outliers = 0
        self.last_update = None

        # does the filter have useful derived data?
        self.valid = False

        # most recent values derived from filter state
        self.position = None        # ECEF
        self.velocity = None        # ECEF
        self.position_error = None  # meters
        self.velocity_error = None  # m/s

        # .. some derived values in more useful reference frames
        self.position_llh = None    # LLH
        self.velocity_enu = None    # ENU
        self.heading = None         # degrees
        self.ground_speed = None    # m/s
        self.vertical_speed = None  # m/s

    def _update_derived(self):
        """Update derived values from self._mean and self._cov"""

        if self._mean is None or self._new:
            self.valid = False
            return

        self.position = self._mean[0:3]
        self.velocity = self._mean[3:6]

        pe = numpy.trace(self._cov[0:3, 0:3])
        self.position_error = 0 if pe < 0 else math.sqrt(pe)
        ve = numpy.trace(self._cov[3:6, 3:6])
        self.velocity_error = 0 if ve < 0 else math.sqrt(ve)

        lat, lon, alt = self.position_llh = mlat.geodesy.ecef2llh(self.position)

        # rotate velocity into the local tangent plane
        lat_r = lat * mlat.constants.DTOR
        lon_r = lon * mlat.constants.DTOR
        C = numpy.array([[-math.sin(lon_r), math.cos(lon_r), 0],
                         [math.sin(-lat_r) * math.cos(lon_r), math.sin(-lat_r) * math.sin(lon_r), math.cos(-lat_r)],
                         [math.cos(-lat_r) * math.cos(lon_r), math.cos(-lat_r) * math.sin(lon_r), -math.sin(-lat_r)]])
        east, north, up = numpy.dot(C, self.velocity.T).T

        # extract speeds, headings
        self.heading = math.atan2(east, north) * 180.0 / math.pi
        if self.heading < 0:
            self.heading += 360
        self.ground_speed = math.sqrt(north**2 + east**2)
        self.vertical_speed = up

        self.valid = True

    def update(self, position_time, measurements, altitude, leastsquares_position, leastsquares_cov, distinct):
        """Update the filter given a new set of observations.

        position_time:         the time of these measurements, UTC seconds
        measurements:          a list of (receiver, timestamp, variance) tuples
        altitude:              reported altitude in meters
        leastsquares_position: the ECEF position computed by the least-squares solver
        distinct:              the number of distinct receivers (<= len(measurements))
        """

        if self._mean is None or (position_time - self.last_update > 120.0):
            # reinitialize
            self._reset()
            if distinct >= 4:
                # accept this
                self.last_update = position_time
                self._mean = numpy.array(list(leastsquares_position) + [0, 0, 0])
                self._cov = numpy.zeros((6, 6))
                self._cov[0:3, 0:3] = leastsquares_cov
                self._cov[3, 3] = self._cov[4, 4] = self._cov[5, 5] = 200**2
                return
            else:
                # nope.
                return

        if self._new and distinct < 4:
            # don't trust 3 station results until we have converged
            return

        # update filter
        zero_pr = measurements[0][1] * mlat.constants.Cair
        positions = [measurements[0][0].position]

        n = len(measurements)
        obs = numpy.zeros(n)
        obs_var = numpy.zeros(n)

        obs[0] = altitude
        obs_var[0] = 50**2

        for i in range(1, n):
            receiver, timestamp, variance = measurements[i]
            positions.append(receiver.position)
            obs[i] = timestamp * mlat.constants.Cair - zero_pr
            obs_var[i] = (variance + measurements[0][2]) * mlat.constants.Cair**2

        obs_covar = numpy.diag(obs_var)

        dt = position_time - self.last_update
        accel = 0.5   # m/s^2

        trans_covar = numpy.zeros((6, 6))
        trans_covar[0, 0] = trans_covar[1, 1] = trans_covar[2, 2] = 0.25*dt**4
        trans_covar[0, 3] = trans_covar[3, 0] = 0.5*dt**3
        trans_covar[1, 4] = trans_covar[4, 1] = 0.5*dt**3
        trans_covar[2, 5] = trans_covar[5, 2] = 0.5*dt**3
        trans_covar[3, 3] = trans_covar[4, 4] = trans_covar[5, 5] = dt**2

        trans_covar *= accel**2

        try:
            transition_function = functools.partial(_kalman_transition, dt=dt)
            observation_function = functools.partial(_kalman_observation, positions=positions)

            #
            # This is extracted from pykalman's AdditiveUnscentedFilter.filter_update()
            # because we want to access the intermediate (prediction) result to decide
            # whether to accept this observation or not.
            #

            # make sigma points
            moments_state = pykalman.unscented.Moments(self._mean, self._cov)
            points_state = pykalman.unscented.moments2points(moments_state)

            # Predict.
            (_, moments_pred) = (
                pykalman.unscented.unscented_filter_predict(
                    transition_function=transition_function,
                    points_state=points_state,
                    sigma_transition=trans_covar
                )
            )
            points_pred = pykalman.unscented.moments2points(moments_pred)

            # Decide whether this is an outlier:
            # Get the current filter state mean and covariance
            # as an observation:
            (obs_points_pred, obs_moments_pred) = (
                pykalman.unscented.unscented_transform(
                    points_pred, observation_function,
                    sigma_noise=obs_covar
                )
            )

            # Find the Mahalanobis distance between the filter observation
            # and our new observation, using the filter's observation
            # covariance as our expected distribution.
            innovation = obs - obs_moments_pred.mean
            vi = numpy.linalg.inv(obs_moments_pred.covariance)
            mdsq = numpy.dot(numpy.dot(innovation.T, vi), innovation)

            # If the Mahalanobis distance is very large this observation is an outlier
            if mdsq > 100:
                glogger.info("{ac.icao:06X} skip innov={innovation} mdsq={mdsq}".format(
                    ac=self.ac,
                    innovation=innovation,
                    mdsq=mdsq))

                self._outliers += 1
                if self._outliers < 3:
                    # don't use this one
                    return
                glogger.info("{ac.icao:06X} reset due to outliers.".format(ac=self.ac))
                self._reset()
                return

            self._outliers = 0

            # correct filter state using the current observations
            (self._mean, self._cov) = (
                pykalman.unscented.unscented_filter_correct(
                    observation_function=observation_function,
                    moments_pred=moments_pred,
                    points_pred=points_pred,
                    observation=obs,
                    sigma_observation=obs_covar
                )
            )

            # converged enough to start reporting?
            if self._new and numpy.trace(self._cov) < 2e6:
                glogger.info("{ac.icao:06X} acquired.".format(ac=self.ac))
                self._new = False

            self.last_update = position_time
            self._update_derived()

        except Exception:
            glogger.exception("Kalman filter update failed. " +
                              "dt={dt} obs={obs} obs_covar={obs_covar} mean={mean} covar={covar}".format(
                                  dt=dt,
                                  obs=obs,
                                  obs_covar=obs_covar,
                                  mean=self._mean,
                                  covar=self._cov))
            self._reset()
            return
<|endoftext|>


<commit_before>from contextlib import contextmanager
from io import IOBase
from functools import partial

from ..lekvar.lekvar import *
from ..errors import *

# Temporary until LLVMType is replaced
LLVMMAP = {
    "String": "i8*",
    "Int": "i32",
    "Void": "void",
}

class Emitter:
    output = None
    stack = None
    current_stack = 0
    main = None

    def __init__(self, out:IOBase, library=False):
        self.output = out
        self.stack = []
        if not library:
            self.main = ""

    def finalize(self):
        # Finalize the emitter

        # Sanity Check
        if len(self.stack) != 0:
            raise InternalError("Emission stack item left at finalization")

        if self.main is not None:
            # Add main function
            self.writeGlobal("define i32 @main() {{\n{}ret i32 0\n}}".format(self.main))

    #
    # Output Writing
    #

    def write(self, string):
        # General write function
        if len(self.stack) > 0:
            self.writeLine(string)
        else:
            self.writeGlobal(string)

    def writeGlobal(self, string):
        # Write directly to the global output
        self.output.write(bytes(string, "UTF-8"))

    def writeLine(self, string):
        self.stack[-1] += string

    def writeStack(self, string):
        self.stack[self.current_stack] += string

    def writeMain(self, string):
        # Write directly to the main function
        self.main += string

    @property
    def in_line(self):
        # Return whether the current stack item is a line
        return self.current_stack < len(self.stack) - 1

    @contextmanager
    def lineWrite(self, entry=""):
        self.stack.append(entry)
        yield
        self.writeStack(self.stack.pop() + "\n")

    @contextmanager
    def stackWrite(self, entry=""):
        # Keep track of the current stack item
        previous_stack = self.current_stack
        self.current_stack = len(self.stack)

        self.stack.append(entry)
        yield
        self.writeGlobal(self.stack.pop() + "\n")
        # Revert to previous stack
        self.current_stack = previous_stack

    #
    # Name Generation
    #

    def resolveName(self, scope:Scope):
        # Resolves the name of a scope, starting with a extraneous .
        name = ""
        while scope.name is not None:
            name += "." + scope.name
            scope = scope.parent
        return name

    temp_name_index = 0
    def getTempName(self, prefix):
        # Return a temporary, but unique name. Temporary names always start with temp
        name = "{}temp.{}".format(prefix, self.temp_name_index)
        self.temp_name_index += 1
        return name

    #
    # LLVM IR Emission
    #

    def addMain(self, main:Function):
        # adds a function to the "main" function. Added function must be void(void) and emitted
        # Ignore for libraries
        if self.main is None:
            return

        self.writeMain("call void {}()\n".format(main.emit_data))

    def emitExternalFunction(self, function:ExternalFunction):
        function.emit_data = "@{}".format(function.external_name)

        # declare <return> @<name>(<arguments>)
        with self.stackWrite("declare "):

            self._emitType(function.return_type) # return

            self.write(" {}(".format(function.emit_data)) # name

            for index, type in enumerate(function.argument_types): # arguments
                if index > 0:
                    self.write(",")
                type.emit(self)
            self.write(")")

    @contextmanager
    def emitFunction(self, function:Function):
        function.emit_data = "@lekvar" + self.resolveName(function)

        # define <return> @<name>(<arguments>) {
        # <magic>
        # yield
        # label.return:
        # ret <return>
        # }

        with self.stackWrite("define "):
            not_void = function.return_type is not None

            if not_void:
                function.return_type.emit(self) # return
            else:
                self.write("void")

            self.write(" {}(".format(function.emit_data)) # name
            for index, argument in enumerate(function.arguments): # arguments
                if index > 0:
                    self.write(",")
                argument.emit_data = self.getTempName("%")
                argument.type.emit(self)
                self.write(" {}".format(argument.emit_data))
            self.write(") {\n")

            for argument in function.arguments: # magic
                name = argument.emit_data
                self._emitVariableAlloc(argument)
                def emit():
                    argument.type.emit(self)
                    self.write(" {}".format(name))
                self._emitVariableStore(argument, emit)

            if not_void: # only allocate return variable if function is not void
                self.write("%return = alloca ")
                function.return_type.emit(self)
                self.write("\n")
            self.write("\n")

            # Do other stuff
            yield
            # now finish off

            # fallthrough
            self.write("br label %label.return\nlabel.return:\n")
            if not_void:
                self.write("%return.value = load ")
                function.return_type.emit(self)
                self.write("* %return\nret ")
                function.return_type.emit(self)
                self.write(" %return.value\n")
            else:
                self.write("ret void\n")
            self.write("}\n")

    def emitFunctionValue(self, function:(Function, ExternalFunction)):
        # <return> @<name>
        if function.return_type is not None:
            function.return_type.emit(self) # return
        else:
            self.write("void")
        self.write(" {}".format(function.emit_data)) # @name

    def emitComment(self, comment:Comment):
        self.write(";{}\n".format(comment.contents))

    def emitLiteral(self, literal:Literal):
        # Emit a non-specific literal
        type = literal.resolveType()

        if not isinstance(type, LLVMType): #TODO: Get rid of LLVMType
            raise NotImplemented()

        if type.llvm_type == "String":
            # Create a global constant for it
            literal.emit_data = self.getTempName("@")
            # @<tempname> = internal constant [<size> x i8] c"<string>\00"
            self.writeGlobal("{} = internal constant [{} x i8] c\"{}\\00\"\n".format(literal.emit_data, len(literal.data) + 1, literal.data))
            # i8* getelementptr inbounds ([<size> x i8]* @<tempname>, i32 0, i32 0)
            self.write("i8* getelementptr inbounds ([{} x i8]* {}, i32 0, i32 0)".format(len(literal.data) + 1, literal.emit_data))
        else:
            raise NotImplemented()

    def emitCall(self, call:Call):
        # Since you can't nest calls in llvm, use a temporary variable to store the returned value

        def emit():
            # <function>(<arguments>)\n
            call.called.emit(self) # function
            self.write("(")
            for index, value in enumerate(call.values): # arguments
                if index > 0:
                    self.write(",")
                value.emit(self)
            self.write(")\n")

        if self.in_line:
            #.. %<temp> = call <emit>
            call.emit_data = self.getTempName("%") # temp
            with self.lineWrite("{} = call ".format(call.emit_data)):
                emit()
            self._emitType(call.called.return_type)
            self.write(" {}".format(call.emit_data))

        else:
            # call <emit>
            with self.lineWrite("call "):
                emit()

    def emitReturn(self, ret:Return):
        if ret.parent.return_type is not None:
            with self.lineWrite("store "):
                ret.value.emit(self)
                self.write(", ")
                ret.parent.return_type.emit(self)
                self.write("* %return")
        self.write("br label %label.return\n")

    def _emitType(self, type:Type):
        # just map the mentioned type to a llvm type
        if type is None:
            self.write("void")
        else:
            type.emit(self)

    def emitLLVMType(self, type):
        self.write(LLVMMAP[type.llvm_type])

    def emitVariable(self, var:Variable):
        if var.emit_data is None:
            self._emitVariableAlloc(var)

        temp = self.getTempName("%")
        with self.lineWrite("{} = load ".format(temp)):
            var.type.emit(self)
            self.write("* {}".format(var.emit_data))
        var.type.emit(self)
        self.write(" {}".format(temp))

    def _emitVariableAlloc(self, var):
        var.emit_data = "%lekvar.{}".format(var.name)

        with self.lineWrite("{} = alloca ".format(var.emit_data)):
            var.type.emit(self)

    def emitAssignment(self, assignment):
        self._emitVariableStore(assignment.variable, partial(assignment.value.emit, self))

    def _emitVariableStore(self, var:Variable, store):
        if var.emit_data is None:
            self._emitVariableAlloc(var)

        with self.lineWrite("store "):
            store()
            self.write(",")
            var.type.emit(self)
            self.write("* {}".format(var.emit_data))
<commit_msg>Fixed emitter to work with current implementation<commit_after>from contextlib import contextmanager
from io import IOBase
from functools import partial

from ..lekvar.lekvar import *
from ..errors import *

# Temporary until LLVMType is replaced
LLVMMAP = {
    "String": "i8*",
    "Int": "i32",
    "Void": "void",
}

class Emitter:
    output = None
    stack = None
    current_stack = 0
    main = None

    def __init__(self, out:IOBase, library=False):
        self.output = out
        self.stack = []
        if not library:
            self.main = ""

    def finalize(self):
        # Finalize the emitter

        # Sanity Check
        if len(self.stack) != 0:
            raise InternalError("Emission stack item left at finalization")

        if self.main is not None:
            # Add main function
            self.writeGlobal("define i32 @main() {{\n{}ret i32 0\n}}".format(self.main))

    #
    # Output Writing
    #

    def write(self, string):
        # General write function
        if len(self.stack) > 0:
            self.writeLine(string)
        else:
            self.writeGlobal(string)

    def writeGlobal(self, string):
        # Write directly to the global output
        self.output.write(string)

    def writeLine(self, string):
        self.stack[-1] += string

    def writeStack(self, string):
        self.stack[self.current_stack] += string

    def writeMain(self, string):
        # Write directly to the main function
        self.main += string

    @property
    def in_line(self):
        # Return whether the current stack item is a line
        return self.current_stack < len(self.stack) - 1

    @contextmanager
    def lineWrite(self, entry=""):
        self.stack.append(entry)
        yield
        self.writeStack(self.stack.pop() + "\n")

    @contextmanager
    def stackWrite(self, entry=""):
        # Keep track of the current stack item
        previous_stack = self.current_stack
        self.current_stack = len(self.stack)

        self.stack.append(entry)
        yield
        self.writeGlobal(self.stack.pop() + "\n")
        # Revert to previous stack
        self.current_stack = previous_stack

    #
    # Name Generation
    #

    def resolveName(self, scope:Scope):
        # Resolves the name of a scope, starting with a extraneous .
        name = ""
        while scope.parent is not None:
            name += "." + scope.name
            scope = scope.parent
        return name

    temp_name_index = 0
    def getTempName(self, prefix):
        # Return a temporary, but unique name. Temporary names always start with temp
        name = "{}temp.{}".format(prefix, self.temp_name_index)
        self.temp_name_index += 1
        return name

    #
    # LLVM IR Emission
    #

    def addMain(self, main:Function):
        # adds a function to the "main" function. Added function must be void(void) and emitted
        # Ignore for libraries
        if self.main is None:
            return

        self.writeMain("call void {}()\n".format(main.emit_data))

    def emitExternalFunction(self, function:ExternalFunction):
        function.emit_data = "@{}".format(function.external_name)

        # declare <return> @<name>(<arguments>)
        with self.stackWrite("declare "):

            self._emitType(function.return_type) # return

            self.write(" {}(".format(function.emit_data)) # name

            for index, type in enumerate(function.argument_types): # arguments
                if index > 0:
                    self.write(",")
                type.emit(self)
            self.write(")")

    @contextmanager
    def emitFunction(self, function:Function):
        function.emit_data = "@lekvar" + self.resolveName(function)

        # define <return> @<name>(<arguments>) {
        # <magic>
        # yield
        # label.return:
        # ret <return>
        # }

        with self.stackWrite("define "):
            not_void = function.return_type is not None

            if not_void:
                function.return_type.emit(self) # return
            else:
                self.write("void")

            self.write(" {}(".format(function.emit_data)) # name
            for index, argument in enumerate(function.arguments): # arguments
                if index > 0:
                    self.write(",")
                argument.emit_data = self.getTempName("%")
                argument.type.emit(self)
                self.write(" {}".format(argument.emit_data))
            self.write(") {\n")

            for argument in function.arguments: # magic
                name = argument.emit_data
                self._emitVariableAlloc(argument)
                def emit():
                    argument.type.emit(self)
                    self.write(" {}".format(name))
                self._emitVariableStore(argument, emit)

            if not_void: # only allocate return variable if function is not void
                self.write("%return = alloca ")
                function.return_type.emit(self)
                self.write("\n")
            self.write("\n")

            # Do other stuff
            yield
            # now finish off

            # fallthrough
            self.write("br label %label.return\nlabel.return:\n")
            if not_void:
                self.write("%return.value = load ")
                function.return_type.emit(self)
                self.write("* %return\nret ")
                function.return_type.emit(self)
                self.write(" %return.value\n")
            else:
                self.write("ret void\n")
            self.write("}\n")

    def emitFunctionValue(self, function:(Function, ExternalFunction)):
        # <return> @<name>
        if function.return_type is not None:
            function.return_type.emit(self) # return
        else:
            self.write("void")
        self.write(" {}".format(function.emit_data)) # @name

    def emitComment(self, comment:Comment):
        self.write(";{}\n".format(comment.contents))

    def emitLiteral(self, literal:Literal):
        # Emit a non-specific literal
        type = literal.resolveType()

        if not isinstance(type, LLVMType): #TODO: Get rid of LLVMType
            raise NotImplemented()

        if type.llvm_type == "String":
            # Create a global constant for it
            literal.emit_data = self.getTempName("@")
            # @<tempname> = internal constant [<size> x i8] c"<string>\00"
            self.writeGlobal("{} = internal constant [{} x i8] c\"{}\\00\"\n".format(literal.emit_data, len(literal.data) + 1, literal.data))
            # i8* getelementptr inbounds ([<size> x i8]* @<tempname>, i32 0, i32 0)
            self.write("i8* getelementptr inbounds ([{} x i8]* {}, i32 0, i32 0)".format(len(literal.data) + 1, literal.emit_data))
        else:
            raise NotImplemented()

    def emitCall(self, call:Call):
        # Since you can't nest calls in llvm, use a temporary variable to store the returned value

        def emit():
            # <function>(<arguments>)\n
            call.called.emit(self) # function
            self.write("(")
            for index, value in enumerate(call.values): # arguments
                if index > 0:
                    self.write(",")
                value.emit(self)
            self.write(")\n")

        if self.in_line:
            #.. %<temp> = call <emit>
            call.emit_data = self.getTempName("%") # temp
            with self.lineWrite("{} = call ".format(call.emit_data)):
                emit()
            self._emitType(call.called.return_type)
            self.write(" {}".format(call.emit_data))

        else:
            # call <emit>
            with self.lineWrite("call "):
                emit()

    def emitReturn(self, ret:Return):
        if ret.parent.return_type is not None:
            with self.lineWrite("store "):
                ret.value.emit(self)
                self.write(", ")
                ret.parent.return_type.emit(self)
                self.write("* %return")
        self.write("br label %label.return\n")

    def _emitType(self, type:Type):
        # just map the mentioned type to a llvm type
        if type is None:
            self.write("void")
        else:
            type.emit(self)

    def emitLLVMType(self, type):
        self.write(LLVMMAP[type.llvm_type])

    def emitVariable(self, var:Variable):
        if var.emit_data is None:
            self._emitVariableAlloc(var)

        temp = self.getTempName("%")
        with self.lineWrite("{} = load ".format(temp)):
            var.type.emit(self)
            self.write("* {}".format(var.emit_data))
        var.type.emit(self)
        self.write(" {}".format(temp))

    def _emitVariableAlloc(self, var):
        var.emit_data = "%lekvar.{}".format(var.name)

        with self.lineWrite("{} = alloca ".format(var.emit_data)):
            var.type.emit(self)

    def emitAssignment(self, assignment):
        self._emitVariableStore(assignment.variable, partial(assignment.value.emit, self))

    def _emitVariableStore(self, var:Variable, store):
        if var.emit_data is None:
            self._emitVariableAlloc(var)

        with self.lineWrite("store "):
            store()
            self.write(",")
            var.type.emit(self)
            self.write("* {}".format(var.emit_data))
<|endoftext|>


<commit_before><commit_msg>init file so refactored models can be accessed like before<commit_after>from involvement.models.application import Application
from involvement.models.contact_card import ContactCard
from involvement.models.contact_card_block import ContactCardBlock
from involvement.models.mandate_history import MandateHistory
from involvement.models.position import Position
from involvement.models.recruitment_page import RecruitmentPage
from involvement.models.reference import Reference
from involvement.models.role import Role
from involvement.models.team import Team<|endoftext|>


<commit_before>## Copyright (c) 2012-2015 Aldebaran Robotics. All rights reserved.
## Use of this source code is governed by a BSD-style license that can be
## found in the COPYING file.

""" Output information about the given project """

from qisys import ui
import qisys.parsers
import qisrc.parsers
import qibuild.parsers

def configure_parser(parser):
    """ Configure parser for this action """
    qisys.parsers.worktree_parser(parser)
    parser.add_argument("name", nargs="?")

def do(args):
    """ Main entry point """
    name = args.name
    build_worktree = qibuild.parsers.get_build_worktree(args, verbose=False)
    if name:
        build_project = build_worktree.get_build_project(name, raises=True)
    else:
        args.projects = list()
        build_project = qibuild.parsers.get_one_build_project(build_worktree, args)
    git_worktree = qisrc.parsers.get_git_worktree(args)
    git_project = qisys.parsers.find_parent_project(git_worktree.git_projects,
            build_project.path)
    mess = "Build project: %s\n" % build_project.name
    mess += "src: %s\n" % build_project.src
    if git_project:
        mess += "repo: %s" % git_project.name
    ui.info(mess)

<commit_msg>qibuild info: remove blank lines at the end of file<commit_after>## Copyright (c) 2012-2015 Aldebaran Robotics. All rights reserved.
## Use of this source code is governed by a BSD-style license that can be
## found in the COPYING file.

""" Output information about the given project """

from qisys import ui
import qisys.parsers
import qisrc.parsers
import qibuild.parsers

def configure_parser(parser):
    """ Configure parser for this action """
    qisys.parsers.worktree_parser(parser)
    parser.add_argument("name", nargs="?")

def do(args):
    """ Main entry point """
    name = args.name
    build_worktree = qibuild.parsers.get_build_worktree(args, verbose=False)
    if name:
        build_project = build_worktree.get_build_project(name, raises=True)
    else:
        args.projects = list()
        build_project = qibuild.parsers.get_one_build_project(build_worktree, args)
    git_worktree = qisrc.parsers.get_git_worktree(args)
    git_project = qisys.parsers.find_parent_project(git_worktree.git_projects,
            build_project.path)
    mess = "Build project: %s\n" % build_project.name
    mess += "src: %s\n" % build_project.src
    if git_project:
        mess += "repo: %s" % git_project.name
    ui.info(mess)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright (c) 2009 Ars Aperta, Itaapy, Pierlis, Talend.
#
# Authors: David Versmisse <david.versmisse@itaapy.com>
#
# This file is part of Lpod (see: http://lpod-project.org).
# Lpod is free software; you can redistribute it and/or modify it under
# the terms of either:
#
# a) the GNU General Public License as published by the Free Software
#    Foundation, either version 3 of the License, or (at your option)
#    any later version.
#    Lpod is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with Lpod.  If not, see <http://www.gnu.org/licenses/>.
#
# b) the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#    http://www.apache.org/licenses/LICENSE-2.0
#

# Import from the standard library
from optparse import OptionParser
from sys import exit, stdout

# Import from lpod
from lpod import __version__
from lpod.document import odf_new_document_from_type, odf_get_document
from lpod.heading import odf_create_heading
from lpod.link import odf_create_link
from lpod.list import odf_create_list, odf_create_list_item
from lpod.note import odf_create_note
from lpod.paragraph import odf_create_paragraph, odf_create_line_break
from lpod.paragraph import odf_create_undividable_space
from lpod.span import odf_create_span
from lpod.style import odf_create_style
from lpod.toc import odf_create_toc

# Import from docutils
from docutils.readers.standalone import Reader
from docutils.core import publish_doctree

def find_convert(node, context):
    tagname = node.tagname
    if tagname == "#text":
        convert_text(node, context)
    elif tagname == "section":
        convert_section(node, context)
    elif tagname == "paragraph":
        convert_paragraph(node, context)
    elif tagname == "enumerated_list":
        convert_list(node, context, "enumerated")
    elif tagname == "bullet_list":
        convert_list(node, context, "bullet")
    elif tagname == "topic":
        convert_topic(node, context)
    elif tagname == "footnote":
        convert_footnote(node, context)
    elif tagname == "footnote_reference":
        convert_footnote_reference(node, context)
    elif tagname == "emphasis":
        convert_emphasis(node, context)
    elif tagname == "strong":
        convert_strong(node, context)
    elif tagname == "literal":
        convert_literal(node, context)
    elif tagname == "literal_block":
        convert_literal_block(node, context)
    elif tagname == "reference":
        convert_reference(node, context)
    elif tagname == "definition_list":
        convert_definition_list(node, context)
    elif tagname == "block_quote":
        convert_block_quote(node, context)
    else:
        print "Warning node not supported: %s" % tagname

def convert_text(node, context):
    context["top"].append_element(node.astext())

def convert_section(node, context):
    # Inc the heading level
    context["heading-level"] += 1

    # Reset the top to body
    context["top"] = context["body"]

    # Convert
    for children in node:
        if children.tagname == "title":
            title = children.astext()
            heading = odf_create_heading(level=context["heading-level"],
                                         text=title)
            context["body"].append_element(heading)
        else:
            find_convert(children, context)

    # Restore the heading level
    context["heading-level"] -= 1

def convert_paragraph(node, context):
    paragraph = odf_create_paragraph()
    context["top"].append_element(paragraph)

    # Save the current top
    old_top = context["top"]

    # Convert
    context["top"] = paragraph
    for children in node:
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_list(node, context, list_type):
    # XXX unused
    enumtype = node.get("enumtype") #enumerated
    bullet = node.get("bullet") #bullet

    odf_list = odf_create_list()
    context["top"].append_element(odf_list)

    # Save the current top
    old_top = context["top"]

    for item in node:

        if item.tagname != "list_item":
            print "Warning node not supported: %s" % item.tagname
            continue

        # Create a new item
        odf_item = odf_create_list_item()
        odf_list.append_element(odf_item)

        # A new top
        context["top"] = odf_item

        for children in item:
            find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_topic(node, context):
    # Reset the top to body
    context["top"] = context["body"]

    # Yet an other TOC ?
    if context["toc"] is not None:
        print "Warning: a TOC is already inserted"
        return

    toc = odf_create_toc()
    context["body"].append_element(toc)
    context["toc"] = toc

def convert_footnote(node, context):
    # XXX ids is a list ??
    refid = node.get("ids")[0]

    # Find the footnote
    footnotes = context["footnotes"]
    if refid not in footnotes:
        print 'Warning: unknown footnote "%s"' % refid
        return
    footnote_body = footnotes[refid].get_element("text:note-body")

    # Save the current top
    old_top = context["top"]

    # Fill the note
    context["top"] = footnote_body
    for children in node:
        # We skip the label (already added)
        if children.tagname == "label":
            continue
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_footnote_reference(node, context):
    refid = node.get("refid")
    citation = node.astext()

    footnote = odf_create_note(note_id=refid, citation=citation)
    context["top"].append_element(footnote)

    context["footnotes"][refid] = footnote

def _convert_style_like(node, context, style):
    # Create the span
    span = odf_create_span(style=style.get_style_name())
    context["top"].append_element(span)

    # Save the current top
    old_top = context["top"]

    # Convert
    context["top"] = span
    for children in node:
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_emphasis(node, context):
    # Yet an emphasis style ?
    styles = context["styles"]
    if "emphasis" in styles:
        emphasis = styles["emphasis"]
    else:
        emphasis = odf_create_style("text", italic=True)
        styles["emphasis"] = emphasis
        context["doc"].insert_style(emphasis, automatic=True)

    # Convert
    _convert_style_like(node, context, emphasis)

def convert_strong(node, context):
    # Yet a strong style ?
    styles = context["styles"]
    if "strong" in styles:
        strong = styles["strong"]
    else:
        strong = odf_create_style("text", bold=True)
        styles["strong"] = strong
        context["doc"].insert_style(strong, automatic=True)

    # Convert
    _convert_style_like(node, context, strong)

def _get_literal_style(context, family):
    # family = "text" or "paragraph"

    FONT = "FreeMono"

    # Yet a literal style ?
    styles = context["styles"]
    style_name = "%s-literal" % family
    if  style_name in styles:
        return styles[style_name]

    # A monospace font
    if not ("text-literal" in styles or "paragraph-literal" in styles):
        font = odf_create_style("font-face", name=FONT)
        font.set_attribute("svg:font-family", FONT)
        font.set_attribute("style:font-family-generic", "modern")
        font.set_attribute("style:font-pitch", "fixed")
        context["doc"].insert_style(font)

    # And the style
    if family == "paragraph":
        style = odf_create_style(family, parent="Standard")
    else:
        style = odf_create_style(family)
    style.set_style_properties(properties={"style:font-name": FONT},
                               area="text")
    context["doc"].insert_style(style, automatic=True)

    # Save it
    styles[style_name] = style
    return style

def convert_literal(node, context):
    literal = _get_literal_style(context, "text")

    # Convert
    _convert_style_like(node, context, literal)

def convert_literal_block(node, context):
    literal = _get_literal_style(context, "paragraph")
    paragraph = odf_create_paragraph(style=literal.get_style_name())
    context["top"].append_element(paragraph)

    # Convert
    for children in node:
        # Only text
        if children.tagname != "#text":
            print 'node "%s" not supported in literal block' % children.tagname
            continue
        text = children.astext()

        tmp = []
        spaces = 0
        for c in text:
            if c == '\n':
                if tmp:
                    tmp = u"".join(tmp)
                    paragraph.append_element(tmp)
                    tmp = []
                spaces = 0
                paragraph.append_element(odf_create_line_break())
            elif c == '\r':
                continue
            elif c == ' ':
                spaces += 1
            elif c == '\t':
                # Tab = 4 spaces
                spaces += 4
            else:
                if spaces >= 2:
                    if tmp:
                        tmp = u"".join(tmp)
                        paragraph.append_element(tmp)
                        tmp = []
                    paragraph.append_element(
                              odf_create_undividable_space(spaces))
                    spaces = 0
                elif spaces == 1:
                    tmp.append(' ')
                    spaces = 0
                tmp.append(c)
        if tmp:
            tmp = u"".join(tmp)
            paragraph.append_element(tmp)

def convert_reference(node, context):
    refuri = node.get("refuri")
    text = node.astext()

    link = odf_create_link(refuri)
    link.set_text(text)
    context["top"].append_element(link)

def convert_definition_list(node, context):
    # TODO Add the style
    for item in node:
        if item.tagname != "definition_list_item":
            print 'node "%s" not supported in definition_list' % item.tagname
            continue

        for children in item:
            tagname = children.tagname
            if tagname == "term":
                paragraph = odf_create_paragraph(text=children.astext())
                context["top"].append_element(paragraph)
            elif tagname == "definition":
                for subchildren in children:
                    find_convert(subchildren, context)
            else:
                print ('node "%s" not supported in definition_list_item' %
                       item.tagname)

def convert_block_quote(node, context):
    # TODO Add the style
    for children in node:
        find_convert(children, context)

def convert(rst_txt, styles_from):
    # From styles ?
    if styles_from is not None:
        doc = odf_get_document(styles_from)
        doc = doc.clone()
        body = doc.get_body()

        # Clean the body
        body.clear()
    # Or create a new document
    else:
        doc = odf_new_document_from_type("text")
        body = doc.get_body()

    # Convert
    reader = Reader(parser_name="restructuredtext")
    domtree = publish_doctree(rst_txt, reader=reader)

    # Init a context
    context = {"doc": doc, "body": body, "top": body, "styles": {},
               "heading-level": 0, "toc": None, "footnotes": {}}

    # Go!
    for children in domtree:
        if children.tagname == "title":
            title =  children.astext()

            # Meta info
            meta = doc.get_meta()
            meta.set_title(title)

            # XXX Add style
            paragraph = odf_create_paragraph(text=title)
            body.append_element(paragraph)
        else:
            find_convert(children, context)

    # Finish the work
    toc = context["toc"]
    if toc is not None:
        toc.auto_fill(doc)

    return doc

if  __name__ == "__main__":

    # Options initialisation
    usage = "%prog [-o output] <filename>"
    description = "Convert a rst file into an odt file"
    parser = OptionParser(usage, version=__version__,
            description=description)

    # --output
    parser.add_option("-o", "--output", action="store", type="string",
            dest="output", metavar="FILE",
            help="dump the output into the file FILE instead of the standard "
                 "output")

    # --styles
    parser.add_option("-s", "--styles", action="store", type="string",
            dest="styles", metavar="FILE",
            help="import the styles from the given file")

    # Parse !
    opts, args = parser.parse_args()

    # Source
    if len(args) != 1:
        parser.print_help()
        exit(1)
    source = args[0]

    # Convert
    document = convert(open(source).read(), styles_from=opts.styles)

    # Save
    if opts.output is not None:
        document.save(target=opts.output)
    else:
        document.save(target=stdout)

<commit_msg>python/scripts/lpod-rst2odt.py: Now we can insert figure (part I)<commit_after>#!/usr/bin/env python
# -*- coding: UTF-8 -*-
#
# Copyright (c) 2009 Ars Aperta, Itaapy, Pierlis, Talend.
#
# Authors: David Versmisse <david.versmisse@itaapy.com>
#
# This file is part of Lpod (see: http://lpod-project.org).
# Lpod is free software; you can redistribute it and/or modify it under
# the terms of either:
#
# a) the GNU General Public License as published by the Free Software
#    Foundation, either version 3 of the License, or (at your option)
#    any later version.
#    Lpod is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#    You should have received a copy of the GNU General Public License
#    along with Lpod.  If not, see <http://www.gnu.org/licenses/>.
#
# b) the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#    http://www.apache.org/licenses/LICENSE-2.0
#

# Import from the standard library
from optparse import OptionParser
from sys import exit, stdout

# Import from lpod
from lpod import __version__
from lpod.document import odf_new_document_from_type, odf_get_document
from lpod.frame import odf_create_image_frame
from lpod.heading import odf_create_heading
from lpod.link import odf_create_link
from lpod.list import odf_create_list, odf_create_list_item
from lpod.note import odf_create_note
from lpod.paragraph import odf_create_paragraph, odf_create_line_break
from lpod.paragraph import odf_create_undividable_space
from lpod.span import odf_create_span
from lpod.style import odf_create_style
from lpod.toc import odf_create_toc
from lpod.vfs import vfs, Error

# Import from docutils
from docutils.readers.standalone import Reader
from docutils.core import publish_doctree

# Import from PIL
from PIL import Image

def find_convert(node, context):
    tagname = node.tagname
    if tagname == "#text":
        convert_text(node, context)
    elif tagname == "section":
        convert_section(node, context)
    elif tagname == "paragraph":
        convert_paragraph(node, context)
    elif tagname == "enumerated_list":
        convert_list(node, context, "enumerated")
    elif tagname == "bullet_list":
        convert_list(node, context, "bullet")
    elif tagname == "topic":
        convert_topic(node, context)
    elif tagname == "footnote":
        convert_footnote(node, context)
    elif tagname == "footnote_reference":
        convert_footnote_reference(node, context)
    elif tagname == "emphasis":
        convert_emphasis(node, context)
    elif tagname == "strong":
        convert_strong(node, context)
    elif tagname == "literal":
        convert_literal(node, context)
    elif tagname == "literal_block":
        convert_literal_block(node, context)
    elif tagname == "reference":
        convert_reference(node, context)
    elif tagname == "definition_list":
        convert_definition_list(node, context)
    elif tagname == "block_quote":
        convert_block_quote(node, context)
    elif tagname == "figure":
        convert_figure(node, context)
    else:
        print "Warning node not supported: %s" % tagname

def convert_text(node, context):
    context["top"].append_element(node.astext())

def convert_section(node, context):
    # Inc the heading level
    context["heading-level"] += 1

    # Reset the top to body
    context["top"] = context["body"]

    # Convert
    for children in node:
        if children.tagname == "title":
            title = children.astext()
            heading = odf_create_heading(level=context["heading-level"],
                                         text=title)
            context["body"].append_element(heading)
        else:
            find_convert(children, context)

    # Restore the heading level
    context["heading-level"] -= 1

def convert_paragraph(node, context):
    paragraph = odf_create_paragraph()
    context["top"].append_element(paragraph)

    # Save the current top
    old_top = context["top"]

    # Convert
    context["top"] = paragraph
    for children in node:
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_list(node, context, list_type):
    # XXX unused
    enumtype = node.get("enumtype") #enumerated
    bullet = node.get("bullet") #bullet

    odf_list = odf_create_list()
    context["top"].append_element(odf_list)

    # Save the current top
    old_top = context["top"]

    for item in node:

        if item.tagname != "list_item":
            print "Warning node not supported: %s" % item.tagname
            continue

        # Create a new item
        odf_item = odf_create_list_item()
        odf_list.append_element(odf_item)

        # A new top
        context["top"] = odf_item

        for children in item:
            find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_topic(node, context):
    # Reset the top to body
    context["top"] = context["body"]

    # Yet an other TOC ?
    if context["toc"] is not None:
        print "Warning: a TOC is already inserted"
        return

    toc = odf_create_toc()
    context["body"].append_element(toc)
    context["toc"] = toc

def convert_footnote(node, context):
    # XXX ids is a list ??
    refid = node.get("ids")[0]

    # Find the footnote
    footnotes = context["footnotes"]
    if refid not in footnotes:
        print 'Warning: unknown footnote "%s"' % refid
        return
    footnote_body = footnotes[refid].get_element("text:note-body")

    # Save the current top
    old_top = context["top"]

    # Fill the note
    context["top"] = footnote_body
    for children in node:
        # We skip the label (already added)
        if children.tagname == "label":
            continue
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_footnote_reference(node, context):
    refid = node.get("refid")
    citation = node.astext()

    footnote = odf_create_note(note_id=refid, citation=citation)
    context["top"].append_element(footnote)

    context["footnotes"][refid] = footnote

def _convert_style_like(node, context, style):
    # Create the span
    span = odf_create_span(style=style.get_style_name())
    context["top"].append_element(span)

    # Save the current top
    old_top = context["top"]

    # Convert
    context["top"] = span
    for children in node:
        find_convert(children, context)

    # And restore the top
    context["top"] = old_top

def convert_emphasis(node, context):
    # Yet an emphasis style ?
    styles = context["styles"]
    if "emphasis" in styles:
        emphasis = styles["emphasis"]
    else:
        emphasis = odf_create_style("text", italic=True)
        styles["emphasis"] = emphasis
        context["doc"].insert_style(emphasis, automatic=True)

    # Convert
    _convert_style_like(node, context, emphasis)

def convert_strong(node, context):
    # Yet a strong style ?
    styles = context["styles"]
    if "strong" in styles:
        strong = styles["strong"]
    else:
        strong = odf_create_style("text", bold=True)
        styles["strong"] = strong
        context["doc"].insert_style(strong, automatic=True)

    # Convert
    _convert_style_like(node, context, strong)

def _get_literal_style(context, family):
    # family = "text" or "paragraph"

    FONT = "FreeMono"

    # Yet a literal style ?
    styles = context["styles"]
    style_name = "%s-literal" % family
    if  style_name in styles:
        return styles[style_name]

    # A monospace font
    if not ("text-literal" in styles or "paragraph-literal" in styles):
        font = odf_create_style("font-face", name=FONT)
        font.set_attribute("svg:font-family", FONT)
        font.set_attribute("style:font-family-generic", "modern")
        font.set_attribute("style:font-pitch", "fixed")
        context["doc"].insert_style(font)

    # And the style
    if family == "paragraph":
        style = odf_create_style(family, parent="Standard")
    else:
        style = odf_create_style(family)
    style.set_style_properties(properties={"style:font-name": FONT},
                               area="text")
    context["doc"].insert_style(style, automatic=True)

    # Save it
    styles[style_name] = style
    return style

def convert_literal(node, context):
    literal = _get_literal_style(context, "text")

    # Convert
    _convert_style_like(node, context, literal)

def convert_literal_block(node, context):
    literal = _get_literal_style(context, "paragraph")
    paragraph = odf_create_paragraph(style=literal.get_style_name())
    context["top"].append_element(paragraph)

    # Convert
    for children in node:
        # Only text
        if children.tagname != "#text":
            print 'node "%s" not supported in literal block' % children.tagname
            continue
        text = children.astext()

        tmp = []
        spaces = 0
        for c in text:
            if c == '\n':
                if tmp:
                    tmp = u"".join(tmp)
                    paragraph.append_element(tmp)
                    tmp = []
                spaces = 0
                paragraph.append_element(odf_create_line_break())
            elif c == '\r':
                continue
            elif c == ' ':
                spaces += 1
            elif c == '\t':
                # Tab = 4 spaces
                spaces += 4
            else:
                if spaces >= 2:
                    if tmp:
                        tmp = u"".join(tmp)
                        paragraph.append_element(tmp)
                        tmp = []
                    paragraph.append_element(
                              odf_create_undividable_space(spaces))
                    spaces = 0
                elif spaces == 1:
                    tmp.append(' ')
                    spaces = 0
                tmp.append(c)
        if tmp:
            tmp = u"".join(tmp)
            paragraph.append_element(tmp)

def convert_reference(node, context):
    refuri = node.get("refuri")
    text = node.astext()

    link = odf_create_link(refuri)
    link.set_text(text)
    context["top"].append_element(link)

def convert_definition_list(node, context):
    # TODO Add the style
    for item in node:
        if item.tagname != "definition_list_item":
            print 'node "%s" not supported in definition_list' % item.tagname
            continue

        for children in item:
            tagname = children.tagname
            if tagname == "term":
                paragraph = odf_create_paragraph(text=children.astext())
                context["top"].append_element(paragraph)
            elif tagname == "definition":
                for subchildren in children:
                    find_convert(subchildren, context)
            else:
                print ('node "%s" not supported in definition_list_item' %
                       item.tagname)

def convert_block_quote(node, context):
    # TODO Add the style
    for children in node:
        find_convert(children, context)

def convert_figure(node, context):
    DPI = 72

    image = None
    caption = None

    for children in node:
        tagname = children.tagname
        if tagname == "image":
            if image is not None:
                print "unexpected image (just a image / figure) for a figure"
                continue
            image = children.get("uri")
        elif tagname == "caption":
            if caption is not None:
                print ("unexpected caption (just a caption / figure) for a "
                       "figure")
                continue
            caption = children.astext()

    # Load the image to find its size
    encoding = stdout.encoding if stdout.encoding is not None else "utf-8"
    try:
        image_file = vfs.open(image.encode(encoding))
        image_object = Image.open(image_file)
    except (Error, UnicodeEncodeError, IOError, OverflowError):
        print 'Warning, unable to insert the image "%s"' % image
        return
    size = image_object.size
    size = (str(float(size[0]) / DPI)+"in", str(float(size[1]) / DPI)+"in")

    # Add the image
    local_uri = context["doc"].add_file(image)
    odf_image = odf_create_image_frame(local_uri, size=size)

    # XXX An image must be inserted in a paragraph ??
    if context["top"].get_tagname() == "office:text":
        paragraph = odf_create_paragraph()
        paragraph.append_element(odf_image)
        context["top"].append_element(paragraph)
    else:
        context["top"].append(odf_image)

def convert(rst_txt, styles_from):
    # From styles ?
    if styles_from is not None:
        # XXX Must be a text!
        doc = odf_get_document(styles_from)
        doc = doc.clone()
        body = doc.get_body()

        # Clean the body
        body.clear()
    # Or create a new document
    else:
        doc = odf_new_document_from_type("text")
        body = doc.get_body()

    # Convert
    reader = Reader(parser_name="restructuredtext")
    domtree = publish_doctree(rst_txt, reader=reader)

    # Init a context
    context = {"doc": doc, "body": body, "top": body, "styles": {},
               "heading-level": 0, "toc": None, "footnotes": {}}

    # Go!
    for children in domtree:
        if children.tagname == "title":
            title =  children.astext()

            # Meta info
            meta = doc.get_meta()
            meta.set_title(title)

            # XXX Add style
            paragraph = odf_create_paragraph(text=title)
            body.append_element(paragraph)
        else:
            find_convert(children, context)

    # Finish the work
    toc = context["toc"]
    if toc is not None:
        toc.auto_fill(doc)

    return doc

if  __name__ == "__main__":

    # Options initialisation
    usage = "%prog [-o output] <filename>"
    description = "Convert a rst file into an odt file"
    parser = OptionParser(usage, version=__version__,
            description=description)

    # --output
    parser.add_option("-o", "--output", action="store", type="string",
            dest="output", metavar="FILE",
            help="dump the output into the file FILE instead of the standard "
                 "output")

    # --styles
    parser.add_option("-s", "--styles", action="store", type="string",
            dest="styles", metavar="FILE",
            help="import the styles from the given file")

    # Parse !
    opts, args = parser.parse_args()

    # Source
    if len(args) != 1:
        parser.print_help()
        exit(1)
    source = args[0]

    # Convert
    document = convert(open(source).read(), styles_from=opts.styles)

    # Save
    if opts.output is not None:
        document.save(target=opts.output)
    else:
        document.save(target=stdout)

<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .particles import (
    Particles,
    makeCopy,
    calcParticlesDifference,
    compareParticlesDifference,
    ParticlesSet,
    ParticlesAddr,
)
from .beam_elements import *
from .buffer import Buffer, get_cbuffer_from_obj, AssignAddressItem
from .control import (
    NodeId,
    NodeInfoBase,
    ControllerBase,
    NodeControllerBase,
    ArgumentBase,
)
from .cuda import CudaArgument, CudaController, CudaNodeInfo, CudaTrackJob
from .opencl import ClNodeId, ClController, ClArgument
from .trackjob import TrackJob
from .config_helper import supports

from .tricub import (
    TriCub,
    TriCubData,
    TriCub_buffer_create_assign_address_item,
)
<commit_msg>python: expose the interpolation method to the whole SixTrackLib python bindings<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from .particles import (
    Particles,
    makeCopy,
    calcParticlesDifference,
    compareParticlesDifference,
    ParticlesSet,
    ParticlesAddr,
)
from .beam_elements import *
from .buffer import Buffer, get_cbuffer_from_obj, AssignAddressItem
from .control import (
    NodeId,
    NodeInfoBase,
    ControllerBase,
    NodeControllerBase,
    ArgumentBase,
)
from .cuda import CudaArgument, CudaController, CudaNodeInfo, CudaTrackJob
from .opencl import ClNodeId, ClController, ClArgument
from .trackjob import TrackJob
from .config_helper import supports

from .interpol import LineDensityProfileData

from .tricub import (
    TriCub,
    TriCubData,
    TriCub_buffer_create_assign_address_item,
)
<|endoftext|>