Boing enables to create pipelines for connecting different input sources to multiple target destinations (e.g. applications, logs, etc.) and eventually process the data before being dispatched.
As an example, consider the pipeline in figure 1.1: two tactile devices (left side) are connected to a single user application (top-right). At the same time, the contact events from both the devices are forwarded as a JSON stream to a second remote application (e.g. a contact visualiser), while an event recorder is used to log into a file the data stream provided by the second device only.
Figure 1.1: Example of pipeline created using Boing.
Even if the tactile devices provides different data structures, Boing enables to merge them in a single data stream (in this example the TUIO and the JSON stream). Contact events are also processed before being passed to the application: Boing provides nodes to smooth or calibrate the input data (e.g. position, speed, etc.). As shown in the example, pipelines can be composed by parallel branches so that each input/output can have its own processing suite.
Boing does not impose a specific data model; instead it exploits a query path language (similar to JSONPath) for accessing the data to be processed, so that it can fit a wide range of application domains.
The current version is 0.3.1, released on September 18, 2012. Read the ChangeLog.
Download one of the following depending on your platform:
File | Type | Py Version | Size |
---|---|---|---|
boing-0.3.1.tar.gz | Source | 3.2 | 702KB |
boing-0.3.1.zip | Source | 3.2 | 833KB |
boing-0.3.1.win32.msi | MS Windows MSI installer | 3.2 | 544KB |
If you are interested to the development version, you can clone the source repository. Open a terminal and type:
git clone https://github.com/olivopaolo/boing
Boing requires the Python 3.2 interpreter (or newer) and the PyQt4 package (a set of Python bindings for Nokia’s Qt application framework). Moreover, it also requires the following Python packages:
Extensive installation instructions are available for the following platforms:
It is possible to install both Python and PyQt directly from the standard repositories by typing in a terminal:
sudo apt-get install python3-pyqt4 python3-setuptools python3-numpy
In order to complete the installation, open a terminal and type:
cd <BOING-DIRECTORY>
sudo python3.2 setup.py install
If you have Mac Ports, getting PyQt4, numpy and Distribute is as simple as typing:
sudo port install py32-pyqt4 py32-distribute py32-numpy
In order to complete the installation, open a terminal and type:
cd <BOING-DIRECTORY>
sudo python3.2 setup.py install
The boing executable may be not installed into a directory
indexed by the PATH
variable, so that it is always necessary
to use the full path to launch it. To avoid this annoying behaviour, a
simple solution is to set the installer target directory using the option
--install-scripts
. As an example:
sudo python3.2 setup.py install --install-scripts /usr/local/bin
First download the Python 3.2 binary installer and run it.
After Python has been installed, it may be useful to modify the PATH environment variable, so that Windows can find Python binaries and scripts without the need of specifing all the times the entire path. As an example, the PATH variable has been set to:
PATH = C:\Python32;C:\Python32\Scripts
The package Distribute is necessary to run the boing’s installer script. Download the file distribute_setup.py and type in a terminal:
cd <DOWNLOAD-DIRECTORY>
python distribute_setup.py
Download the source code of pyparsing, extract the archive and type in a terminal:
cd <PYPARSING-DIRECTORY>
python setup.py install
If you downloaded the binary installer you just have to launch it, otherwise extract the source archive and type in the terminal:
cd <BOING-DIRECTORY>
python setup.py install
After the installation has been completed, it may be useful to run the test suite in order to verify that everything has been correctly installed. In order to do so, type in a terminal:
python3 setup.py test
It is also possible to test only a subset of the Boing‘s modules:
cd <BOING-DIRECTORY>
python3 boing/test/run.py [MODULE [MODULE ...]]
The available modules are: core
, filtering
,
gesture
, net
, nodes
, utils
. If no
module is specified, all the available modules will be tested.
If you are interested to check the code coverage, you may use the tool called coverage by Ned Batchelder. Once the tool has been installed, you simply have to type:
cd <BOING-DIRECTORY>
coverage run --source boing boing/test/run.py
coverage report -m
This section contains various tutorials to easily learn to use the toolkit Boing:
This tutorial provides few simple examples of the functionality of the toolkit to help you starting to use the Boing toolkit.
Let’s consider to have a multi-touch input device, like a tablet or a touch-screen. What cool things can I do with Boing? Boing enables to create a pipeline for connecting your device to different targets, like applications, frameworks, debuggers and eventually processing the gesture events before having being dispatched, like for example calibrate the contacts’ position or apply a smoothing filter.
To make things easier, let’s consider that your device can send the information of the contact events as a TUIO stream on the local port 3333. [1]
First of all, it is important to know that all the Boing‘s tools are invoked by using the script boing. Open a terminal and type:
boing "in.tuio://:3333 + viz:"
The script should have opened a window displaying a grid. Now when you touch your multi-touch device, you will be able to see the contact points appear on the window.
It’s not difficult to notice that the script accepts a single argument that defines the configuration of the pipeline that is to be created. Configurations are defined by a formula where the operands define the functionality of the nodes of the pipeline, while the operators define how the nodes are connected, therefore also the structure of the pipeline.
In the previous example, the pipeline was composed by two nodes:
in.tuio://:3333
corresponds to a node that reads the socket,
decodes the TUIO stream and provides the multi-touch events;viz:
corresponds to the Contact Visualizer, a widget
that shows the information of the contact points, such as position,
track and speed.The two nodes are joined using the +
operator, which stands
for connection in series. The structure of the pipeline is
represented in figure 3.1.
Figure 3.1: Pipeline obtained from the configuration
in.tuio://:3333 + viz:
.
Congratulations! You have created your first Boing pipeline!
Now, let’s try new functionalities by adding a new node. Stop the previous pipeline by closing the visualizer widget or pressing Ctrl-C on the terminal, and type in the terminal:
boing "in.tuio://:3333 + (viz: | dump:)"
As before the contact visualizer appears again, but this time, when
you touch the multi-touch device, the terminal prints a lot of data!
The terminal output represents all the data that the in.tuio://:3333
node can produce and send to the connected nodes. This tutorial is not
aimed to provide an exaustive description of the message structure;
for the moment, simply observe that data messages are hierarchical
structures mainly composed by Python built-in types, such as
dictionaries, lists, strings, bytearrays, etc. Thanks to such standard
structure, Boing exploits a query language, similar to JSONPath,
for the indexing or the filtering of data messages. In order to
understand the usefulness of such query language, stop the pipeline
and type in the terminal:
boing "in.tuio://:3333 + (viz: | dump:?request=$..contacts)"
Now, when you touch your multi-touch device, you can see that the
terminal prints the subset of the data structures that refers only to
the contact data. This is because the query $..contacts
addresses to any data named as contacts
, searched at any level
of the structure. Such query language can be very useful during
development and testing phases for highlighting only the relevant
information.
A more exhaustive description of the data structure and of the query
language can be found in the data model section. For
now, let’s leave the data structure and we consider the functioning of
the pipeline: it’s not difficult to understand that the |
operator (Pipe) is used to connect in parallel the nodes viz:
and
dump:
, so that the products are sent to both of
them. Figure 3.2 shows the structure of the current
pipeline.
Figure 3.2: Pipeline obtained from the configuration
in.tuio://:3333 + (viz: | dump:)
.
A key feature of Boing is the ability to provide the captured input events to external applications. This enables in most of the cases to take advantage of the toolkit’s features without the need to adapt or to modify the applications, while sometimes a simple configuration may be required. As shown in figure 3.3, the Boing toolkit works as a semi-transparent layer placed between the input sources and the final applications.
Figure 3.3: Boing works as a semi-transparent layer placed in between the devices and the applications for processing and transmitting the input events.
Thanks to the many supported encodings, Boing can easily fit different combinations of devices and applications. In this basic example, let’s consider to have an application listening for a TUIO stream on the local port 3335 [2]. If you don’t have a TUIO application, simply open a new terminal and launch a new Boing instance using the command:
boing "in.tuio://:3335 + viz:"
In the previous example you connected one input device to two output
nodes. The |
operator also enables to put in parallel
different inputs, like for example a second multi-touch device enabled
to send its TUIO messages to the local port 3334. Let’s try a new
pipeline by running the command:
boing "(in.tuio://:3333 | in.tuio://:3334) + (viz: | out.tuio://127.0.0.1:3335)"
Figure 3.4 shows the structure of the new pipeline.
Figure 3.4: Pipeline obtained from the configuration
(in.tuio://:3333 | in.tuio://:3334) + (viz: | out.tuio://127.0.0.1:3335)
.As you can see, a very important feature of Boing is that you can simultaneously connect many devices to different applications. Such feature eases the usage of debugging tools and it enables multi-device and multi-user applications.
The Boing toolkit is not only able to redirect input data to different destinations, but it also enables to process the transferred data. With regard to the multi-touch devices, recurring operations are the removal of the sensor noise and the calibration of the touch points. In order to accomplish these tasks, the toolkit provides two functional nodes that can be easily employed in our pipelines. As an example, let’s run a new pipeline using the following command:
boing "in.tuio://:3333 + filtering: + calib:?screen=left + viz:"
Now, when you touch your tactile device you should still see the
interactions on the visualizer widget, but now they look more smooth
and they are rotated 90 degrees counterclockwise. By employing the
filtering:
node, we added the default smoothing filter, which
is applied by default to the position of the contact points, while the
node calib:
performs the calibration of the touch points.
The structure of the current pipeline is shown in figure 3.5.
Figure 3.5: Pipeline obtained from the configuration
in.tuio://:3333 + filtering: + calib:?screen=left + viz:
In order to better understand the result of the processing stage, it may be useful to show at the same time the raw data and the processed one. In order to achieve such result, stop the previous pipeline and run the following command:
boing "in.tuio://:3333 + (filtering: + calib:?screen=left + edit:?source=filtered | nop:) + viz:"
Now, when you touch your input device you can see on the visualizer
widget both the raw tracks and the processed tracks, so that it is
easier to note the effect of the processing stage. The structure of
the modified pipeline is shown in figure 3.6. Note
that this behaviour has been obtained by adding a parallel branch
constituted only by the node nop:
, which simply forwards the
incoming data without making any modifications, and adding the node
edit:?source=filtered
, which labels the events of the
processing branch so that they belong to the source filtered (the
name is not relevant). This latter step is necessary since the data of
the two parallel branches is merged into a single stream before being
passed to the visualizer widget.
Figure 3.6: Pipeline obtained from the configuration
in.tuio://:3333 + (filtering: + calib:?screen=left +
edit:?source=filtered | nop:) + viz:
The Boing toolkit also provides some tools for recording input
events into log files and some other tools for replaying them. These
operations are often really helpful during the development and
debugging of applications. The simplest way to log events into a file
is to use the node log:
. As an example, consider running the
following command:
boing "in.tuio://:3333 + (viz: | log:./log.bz2)"
Now, all the gestures you make on your tactile device will be recorded
and written to the file ./log.bz2
. Then, stop the pipeline by
pressing Ctrl-C and let’s replay the recorded gestures by executing
the command:
boing "play:./log.bz2 + viz:"
Quite easy, isn’t it? It is also possible to configure the player to endlessly rerun the log and set the replay speed. To do so, simply run this command:
boing "play:./log.bz2?loop&speed=0.2 + viz:"
A more powerful tool for replaying log files is the player:
node: thanks to its GUI, it enables users to easily define a playlist
of log files that the node will reproduce. As an example, run the
following command:
boing "player: + viz:"
Playlists can be exported so that the player:
tool becomes
very useful during the application testing for executing the unit
test.
Footnotes
[1] | If you are unfamiliar with the TUIO protocol, consider having a look to the available TUIO trackers, or jumping to the Nodes reference table, in order to discover the different ways Boing exploits to connect to the input devices. |
[2] | For more output sources, see the Nodes reference table. |
Sometimes it can be useful to store the configuration of the pipeline
for later reuse. Writing long configurations in a terminal may also be
quite annoying. For these reasons, Boing lets users to write the
configuration of the pipeline in a text file and then to load such
configuration using the special node conf:
.
As an example, consider you have finally wrote the configuration of a
pipeline for comparing the result of different smoothing filters. Now
you want to save it in a file (e.g. config-filters.txt
) and maybe
you want to add some comments that will help you understanding the
structure of the pipeline. The file may look like the following:
# Pipeline for comparing the result of different smoothing filters.
#
# Author: Me
# Date: Sept 12, 2012
# File: config-filters.txt
# ONE INPUT: a standard TUIO source
in.tuio://:3333
# PARALLEL BRANCHES
+ (
# Raw input
nop:
# Default filter
| filtering: + edit:?source=Default
# Moving mean filter
| filtering:/moving/average?winsize=5 + edit:?source=Mean
# Moving median filter
| filtering:/moving/median?winsize=5 + edit:?source=Median
# Exponential double filter
| filtering:/exponential/double?alpha=1&gamma=1 + edit:?source=Exponential
# OneEuro filter
| filtering:/oneeuro?freq=1 + edit:?source=OneEuro
# ---
)
# ONE OUTPUT: the visualizer
+ viz:
Now, in order to run the pipeline you just have to enter the command:
boing conf:./config-filters.txt
Quite easy, isn’t it?
The node conf:
is actually a composite node that contains the
pipeline defined in the configuration file. For this reason, it is
also possible to use the conf:
node into another
pipeline. Consider as an example that you have a multi-touch table
sending contact information via the TUIO protocol, you found a good
smoothing filter since the input is quite noisy and you also
determined the calibration matrix to fit the touch position to the
correct screen space. You are not going to change these parameters so
you would like to consider all these elements as an atomic input
source that does not mess up a larger configuration. Thus, first you
could write the configuration of your input source into a file
(e.g. my-mt-table.txt
), which may look like the following:
# My multi-touch table without its ugly noise and well calibrated.
#
# Author: Me
# Date: Sept 12, 2012
# File: my-mt-table.txt
# INPUT: standard TUIO source
in.tuio://:3333
# FILTERING: OneEuro filter
+ filtering:/oneeuro?freq=60&merge
# CALIBRATION: my 4x4 matrix
+ calib:?merge&matrix=0.98,0,0,0.021,0,0.83,0,0.010,0,0,1,0,0,0,0,1
# NO OUTPUT, so I can reuse this into an external pipeline.
Then, you can reuse your configured input device as an atomic item in
a new pipeline. As an example, let’s show the contact events using the
viz:
node, and at the same time use the recorder widget and
forward the contacts to an other application listening for a TUIO
source on the local port 3334. The command to run is the following:
boing "conf:./my-mt-table.txt + (viz: | rec: | out.tuio://127.0.0.1:3334)"
As you can see, saving pipeline configurations into files can be quite
useful in different situations. Needless to say that you can also use
the conf:
node inside a configuration written in a file, so that
it is possible to arrange items in a hierarchical structure.
Developers can easily deploy pipelines by invoking the Boing’s
API in their Python code. The function boing.create()
can be used to instantiate the pipeline’s nodes. This method requires
as argument an URI expression that is used to specify the
functionality of the nodes to be created and how they are
connected. The Nodes reference table is the same as for the command line
script. Then, the operators +
and |
can be used
compose the pipeline.
The following code can be used as an example for creating Boing pipelines:
#!/usr/bin/env python3
import sys
import PyQt4
import boing
# Init application
app = PyQt4.QtGui.QApplication(sys.argv)
# Create nodes
n1 = boing.create("in.tuio://:3333")
n2 = boing.create("viz:")
n3 = boing.create("dump:?request=$..contacts")
# Compose the pipeline
graph = n1 + (n2 | n3)
# Run
sys.exit(app.exec_())
Todo
Describe an example of functional node.
The documentation is structured into the following sections:
Boing pipelines are made by directed graphs, where the edge direction defines the data flow between the nodes. There are three types of nodes:
The type of a node directly influences how the node can be connected to the other nodes: producers only accept outgoing connections, while consumers accept incoming connections only. Workers are composed by both the producer and consumer interfaces, so they can have both incoming and outgoing connections. Figure 4.1 shows an example of both valid and invalid connections.
The core infrastructure of Boing pipelines is the producer-consumer model, which defines how the data is propagated through the pipeline. The model performs a pull technology, but it is extended by using the Observer pattern: consumers must subscribe to the producers in order to receive their products; for each subscribed consumer, producers keep a record containing the list of the pending products. When a producer has a new product, for each registered consumer it enqueues the product in the associated product list and it triggers the consumer, which synchronously or asynchronously can require its own pending products. Then, at the consumer’s request, the producer sends all the correspondent pending products to the consumer and it cleans the correspondent buffer. The entire pipeline is run in a single thread, thus an eventloop is used to handle the asynchronous nodes. Figure 4.2 shows the UML sequence diagram that defines the data exchange between producers and consumers.
See also
classes boing.core.Producer
and
boing.core.Consumer
In many situations, a data source can provide a wide range of information, but consumers may not be interested in all of it. For this reason, in order to save processing time, the model permits to assign a request to each consumer. Every time a producer has a new product, it tests the request of each registered consumer and only if it matches the product, the producer notifies the consumer the new product. This behavior enables to process and transfer only the useful information, while the useless part is not processed. Requests can be added up so that a producer can easily know the entire request of all its registered consumers. The union of all the registered consumers’ requests is called aggregate demand.
On the other side, it is good to know what a producer can supply. For this reason the model permits to assign an offer to the producers, which must be the list of templates of the products it can provide. Using its offer, a producer can say a priori whether it can meet a consumer’s request. Composing the offer and the aggregate demand, it is possible to calculate the demanded offer, which represents the subset of the offer that is currently being demanded.
As an example, consider two producers P1 and P2 and two consumers C1 and C2 connected as shown in figure 4.3. It is possible to observe that the aggregate demand of P1 is equal to the union of the requests of both C1 and C2. Moreover, even if P1 produces both A and B, only the products A are sent to C1, while both A and B products are sent to C2. Also note that P2‘s demandedOffer is only B, because P2 is only connected to C2 and this one does not require the products C.
Note
It is important to understand that a node’s offer does not impose that the only products that the nodes produces are coherent with the offer and even that it is sure that the node will ever produce such products. The offer is only used to describe the node standard behavior. It’s easier said than done!
See also
classes boing.core.Offer
and boing.core.Request
As previously seen, it is possible to create long pipelines by serializing worker nodes. In order to spread the supply and demand strategy, a worker node must be able to propagate the requests of the consumers it is connected to in addition to its own request and to propagate the offer of the producers it is connected to in addition to its own offer. In order to understand such necessity, consider the pipeline shown in figure 4.4: in this case the worker W is not propagating its neighbors’ requests and offers (the variables isPropagantingRequest and isPropagatingOffer are false), so that its own request and offer, which are defined by the variables _selfRequest and _selfOffer, are actually the same of its (public) request and offer. In this case, it is possible to notice that even if the consumer C require the products B, such demand is hidden by the worker W, so that even if the producer P can provide B products, it can’t see anyone interested to them, so they are not produced.
Figure 4.4: The worker W is not propagating its connected consumers’ requests, thus the producer P does not provides the products B.
The figure 4.5 shows the same pipeline as before with the difference that the worker W is now propagating its neighbors’ requests and offers. It is possible to notice that the request of W is equal to the union of the request of C and its own request, and its public offer is equal to the union of the offer of P and its own offer. W is now requiring B products because a subsequent node is also requiring them, thus P will produce and dispatch them.
Note
It is important to understand that the variables
isPropagatingRequest and isPropagatingOffer do not control the
output of W, but only the fact that its request and offer are
determined by accumulating the neighbors requests and offers. The
fact that W forwards B products only depends on the specific
implementation of W. See class boing.core.Functor
for
product forwarding cases.
As formerly described, worker nodes are both consumers and producers, and they can be considered as the pipeline’s processing units. Workers normally calculate simple or atomic operations because they can be easily serialized in order to compose more complex processing pipelines. Boing pipelines can be modified dynamically in order to evolve and fit a flexible environment. This may entail that not all the processing units are really necessary in order to compute the expected result. In order to avoid a waste of time, the pipeline exploits a auto-configuration technique based on the nodes’ supply-demand knowledge. This technique, exploited by the Wise Workers, can be summarized into the following two rules:
As an example consider the pipeline in figure 4.6: the producer P provides the products A, which are required by the consumer C; this one also requires the products B, but P cannot provide them. For this reason the worker W, which can produce B from A, has been employed. Since B is required by C, W is currently active. In this example the worker W is set to forward all the products it receives even it is not directly interested to them.
Figure 4.6: The producer P provides the products A, while the worker W produces the products B using the products A. Both A and B are actually required by the consumer C.
Now suppose that the consumer C changes its own request to A only. In this case, nobody is interested to B anymore, thus, following the first rule of the Wise Worker, the worker stops requiring A for itself and it passes into an inactive state, but, since it is propagating C‘s requests, it still requires A products. Figure 4.7 shows the state of the pipeline in this case.
Figure 4.7: If C does not require products B anymore, the worker W automatically stops producing them and requiring A products for itself, but since it is propagating C‘s requests, it still requires A products so it can forward them to C.
Considering the pipeline in figure 4.6, a different situation may arrive: if the producer P changes its offer to D, no one will provide the products A, thus, following the second rule of the Wise Worker, since the worker’s request is not satisfied anymore, it nullifies its own offer. The resulted pipeline is shown in figure 4.8. In this case requests do not change, so that no more products are exchanged between the nodes.
Figure 4.8: Considering the pipeline of figure 4.6, if the producer P starts producing B only, the worker’s request is not satisfied anymore, so it automatically nullifies its default offer.
In some cases workers do not previously know the products they provide since it only depends on the products they will receive. As an example, a worker may forward only a subset of the products it receives or it may make simple changes to the products it requires and then forward them. In those cases, it is not possible to set the offer in advance of the pipeline execution, thus the first rule of the Wise Worker cannot be applied. In order to handle those cases, the Wise Workers can use the Tunneling exception, that makes the first rule considering the entire propagated offer instead of the worker’s own offer.
As an example consider the pipeline in figure 4.9: the worker W simply forwards the products it receives so it has not its own offer. Despite this, thanks to the tunneling exception, W is still active, since its global offer matches the request of C.
Figure 4.9: When using the tunneling option, the propagated offer is considered to determine if the worker is active instead of its own offer only.
Concrete workers using the tunneling feature are the
Filter
and
Calibration
classes.
See also
classes boing.core.economy.WiseWorker
and
boing.core.Functor
Todo
Node URIs | ||||
---|---|---|---|---|
OSs | Mode | Value | Query keys [1] | Description |
Data Redirection | ||||
LWX | I | in[.<encoding>]<InputDevice> | listen and decode data from an input device | |
LWX | O | out[.<encoding>]<OutputDevice> | encode and forward the data to a target destination | |
Record/Replay | ||||
LWX | I | play[.<encoding>]:<filepath> | loop, speed, interval | replay a log file (default encoding pickle) |
LWX | O | log[.<encoding>]:<filepath> | record data to log file (default encoding pickle) | |
LWX | O | rec: | request, timelimit, sizelimit, oversizecut, fps, timewarping | data recorder with GUI |
LWX | I | player[.<encoding>]: | interval, open | log files player with GUI (default encoding pickle) |
Data Debug | ||||
LWX | O | dump[.<encoding>]<OutputDevice> | request, mode, separator, src, dest, depth | dump products to an output device |
LWX | O | stat[.<encoding>]<OutputDevice> | request, fps | print products statistics to an output device |
LWX | O | viz: | antialiasing, fps | display multi-touch contacts |
Data Processing | ||||
LWX | W | nop: | no operation node | |
LWX | W | edit: | merge, copy, result, **dict | apply to all the received products **dict |
LWX | W | calib: | matrix, screen, attr, request, merge, copy, result | apply a 4x4 transformation matrix |
LWX | W | filtering:[<filter-path>] | attr, request, merge, copy, result, <filter-attr> [2] | filter product data |
LWX | W | timekeeper: | merge, copy, result | mark each received product with a timetag |
LWX | W | lag:[<msec>] | add a lag to each received product | |
Utils | ||||
LWX | [3] | conf:<filepath> | composite node containing the pipeline defined into the specified configuration file. |
Encodings [4] | ||||
---|---|---|---|---|
OSs | Mode | Value | Query keys | Description |
LWX | IO | slip | bytestream from/to SLIP | |
LWX | I | pickle | noslip | pickle to products |
LWX | O | pickle | protocol, request, noslip | Products to pickle |
LWX | I | json | noslip | JSON to products |
LWX | O | json | request, noslip | products to JSON |
LWX | IO | osc | rt, noslip | bytestream from/to OSC |
LWX | IO | tuio[.osc] | rawsource | Multi-touch events from/to TUIO |
Input/Output devices | ||||
---|---|---|---|---|
OSs | Mode | Value | Query keys | Description |
LX | I | :[stdin] | read from standard input | |
LWX | I | :[stdout] | write to standard output | |
LWX | I | [.file]:<filepath> | uncompress, postend | read from file |
LWX | O | [.file]:<filepath> | write to file | |
LWX | I | [.udp]://<host>:<port> | read from UDP socket | |
LWX | O | [.udp]://<host>:<port> | writeend | write to UDP socket |
LWX | IO | .tcp://<host>:<port> | writeend | read/write on TCP socket |
Hosts | |||
---|---|---|---|
OSs | Mode | Value | Description |
LWX | I | empty | same as IPv4 any address |
LWX | I | 0.0.0.0 | IPv4 any address |
LWX | I | [::] | IPv6 any address |
LWX | IO | 127.0.0.1 | IPv4 loopback |
LWX | IO | [::1] | IPv6 loopback |
LWX | IO | x.x.x.x | specific IPv4 address |
LWX | IO | [x:x:x:x:x:x:x:x] | specific IPv6 address |
LWX | IO | <hostname> | specific hostname |
OS support | |
---|---|
Value | Description |
L | Linux |
W | Windows 7 [5] |
X | OS X |
Footnotes
[1] | The available query keys are obtained from the union of the
available query keys of all the uri components. As an
example, the URI out.json://[::1]:7777 is by default
translated to out.json.udp://[::1]:7777 , so it owns the
query keys of the JSON encoder (request and filter ) and of
the udp socket node (writeend ). |
[2] | <filter-attr> dependes on the requested filter. |
[3] | The mode depends on the pipeline defined into the configuration file. It is important to note that pipelines may have a closed configuration, which means they do not behave neither as input nor output, nor worker. This happens when all the inputs are connected in series to the outputs. |
[4] | Some encodings have default input/output devices
(e.g. in.tuio: is by default translated into
in.tuio.udp://[::]:3333 ). |
[5] | On Windows, in order to define a file using the scheme
file: it is necessary to place the character ‘/’ (slash)
before the drive letter
(e.g. file:///C:/Windows/explorer.exe ). |
This section presents the different modules that constitute the toolkit Boing. The documentation of the classes and functions of the toolkit’s API is hereinafter provided.
The Boing toolkit is structured into the following modules:
boing
— Creating and managing pipelines¶Developers can easily deploy Boing pipelines by invoking the toolkit’s
API in their Python code. The most important element is the function
boing.create()
, which is used to instantiate the nodes of
the pipeline.
boing.
create
(expr, parent=None)¶Return a new node created as defined in the expression expr, with parent object parent. If expr is composed by a single URI, the returned object will be a new node correspondent to the provided URI; if expr is formed by an URI expression, the returned object will be a composed node.
All the available nodes are listed and described in the Nodes reference table.
In order to compose the pipeline, the nodes can be attached using the
Python operators +
and |
, which work the same as the
operators used in the URI expressions. As an example, consider the
following code:
n1 = boing.create("in.tuio:")
n2 = boing.create("viz:")
n3 = boing.create("dump:")
pipeline = n1 + (n2 | n3)
The same pipeline can be obtained using the following code:
pipeline = boing.create("in.tuio:+(viz:|dump:)")
In order to run the pipeline it is necessary to launch the Qt Application that should have been initialized before creating the pipeline. The following code can be used as an example for creating custom Boing pipelines:
#!/usr/bin/env python3
import sys
import PyQt4
import boing
# Init application
app = PyQt4.QtGui.QApplication(sys.argv)
# Create nodes
n1 = boing.create("in.tuio:")
n2 = boing.create("viz:")
n3 = boing.create("dump:?request=$..contacts")
# Compose the pipeline
graph = n1 + (n2 | n3)
# Run
sys.exit(app.exec_())
Global configuration
The attribute boing.config
is a dict
object used to
store any global configuration variable.
boing.
config
¶dict
object used to store any global configuration
variable. Boing‘s own variables:
"--no-gui"
: set to True
when GUI is disabled.Dynamic configuration
Todo
Describe how to configure the pipeline dinamically
boing.
activateConsole
(url="", locals=None, banner=None)¶Enable a Python interpreter at url.
The optional locals argument specifies the dictionary in which code will be executed; it defaults to a newly created dictionary with key “__name__” set to “__console__” and key “__doc__” set to None.
The optional banner argument specifies the banner to print before the first interaction; by default it prints a banner similar to the one printed by the real Python interpreter.
boing.core
— The pipeline infrastructure¶The module boing.core
contains the classes that constitute the
infrastructure of Boing pipelines.
boing.core.
Offer
(*args, iter=None)¶An offer defines the list of products that a producer advertises to be its deliverable objects.
Offer.UNDEFINED
can be used to define the producer’s
offer, when the real offer cannot be defined a priori. This avoids
to have empty offers, when they cannot be predeterminated.
boing.core.
Request
¶The class Request
is an abstract class used by
Consumer
objects for specifing the set of products they
are insterested to. The method test()
is used to check
whether a product matches the request.
Request.NONE
and Request.ANY
define respectively
a “no product” and “any product” requests.
Request
objects may also indicate the internal parts of a
product to which a producer may be interested. The method
items()
returns the sequence of the product’s parts a
producer is interested to.
The class Request
implements the design pattern
“Composite”: different requests can be combined into a single
request by using the sum operation (e.g. comp = r1 +
r2
). A composite request matches the union of the products that
are matched by the requests whom it is
composed. Request.NONE
is the identity element of the sum
operation.
Request
objects are immutable.
test
(product)¶Return whether the product matches the request.
items
(product)¶Return an iterator over the product‘s internal parts (i.e. (key, value) pairs) that match the request.
boing.core.
QRequest
(string)¶The QRequest is a Request defined by a QPath.
boing.core.
Producer
(offer, tags=None, store=None, retrieve=None, haspending=None, parent=None)¶A Producer is an observable object enabled to post products to a set of subscribed consumers.
When a producer is demanded to posts a product, for each registered consumer it tests the product with the consumer’s request and only if the match is valid it triggers the consumer.
Each Producer has an Offer (a list of product templates), so it can say if a priori it can meet a consumer’s request.
demandChanged
¶Signal emitted when the aggregate demand changes.
offerChanged
¶Signal emitted when its own offer changes.
demandedOfferChanged
¶Signal emitted when its own demanded offer changes.
aggregateDemand
()¶Return the union of all the subscribed consumers’ requests.
demandedOffer
()¶Return the producer’s demanded offer.
meetsRequest
()¶Return whether the product’s offer meets request.
offer
()¶Return the producer’s offer.
postProduct
(product)¶Post product. In concrete terms, it triggers the registered consumers that require product, then it stores the product.
boing.core.
Consumer
(request, consume=None, hz=None, parent=None)¶A Consumer is an observer object that can be subscribed to many producers for receiving their products. When a producer posts a product, it triggers the registered consumers; the triggered consumers will immediately or at regular time interval demand the producer the new products.
Many consumers can be subscribed to a single producer. Each new product is actually shared within the different consumers, therefore a consumer SHOULD NOT modify any received product, unless it is supposed to be the only consumer.
Consumers have a request. When a producer is demanded to posts a product, it tests the product with the consumer’s request and only if the match is valid it triggers the consumer.
A consumer’s request must be an instance of the class Request. The requests “any product” and “no product” are available.
request
()¶Return the consumer’s request.
_consume
(products, producer)¶Consume the products posted from producer.
boing.filtering
- Filters and noise generators¶Smoothing filters and noise generators.
Todo
Comment module boing.filtering
.
boing.gesture
— Gesture recognition tools¶Recognition algorithms and common utilities have been placed in separated submodules:
boing.gesture.rubine
— The Rubine’s recognition algorithm¶The module boing.gesture.rubine
provides an implementation of
the Rubine’s gesture recognition algorithm.
boing.gesture.utils
— Recognizers’ common utilities¶The boing.gesture.utils module contains common method used by different recognizers.
boing.gesture.utils.
boundingBox
(points)¶Return the tuple (minx, miny, maxx, maxy) defining the bounding box for points.
boing.gesture.utils.
updateBoundingBox
(bb1, bb2)¶Return the tuple (minx, miny, maxx, maxy) defining the bounding box containing the bounding boxes bb1 and bb2.
boing.net
— Networking and encoding tools¶The module boing.net
provides classes and methods to ease the
usage of sockets and networking encodings, like for example JSON, OSC,
SLIP, etc.
boing.net.
Encoder
¶The Encoder class is the abstract base class for implementing the encoders of all the different encodings.
boing.net.
Decoder
¶The Decoder class is the abstract base class for implementing the decoders of all the different encodings.
The Decoder class implements the composite pattern. Many decoders can be put in sequence into a single composed decoder using the sum operator.
Each encoding has been implemented in a different submodule:
boing.net.bytes
— UNICODE encoding¶The boing.net.bytes
module implements the adapter design
pattern by providing the standard string encoding functionalities as
Encoder and Decoder objects.
boing.net.bytes.
encode
(string, encoding="utf-8", errors="strict")¶Return an encoded version of string as a bytes object. Default encoding is ‘utf-8’. errors may be given to set a different error handling scheme. The default for errors is ‘strict’, meaning that encoding errors raise a UnicodeError. Other possible values are ‘ignore’, ‘replace’, ‘xmlcharrefreplace’, ‘backslashreplace’
boing.net.bytes.
decode
(data, encoding="utf-8", errors="strict")¶Return a string decoded from the given bytes. Default encoding is ‘utf-8’. errors may be given to set a different error handling scheme. The default for errors is ‘strict’, meaning that encoding errors raise a UnicodeError. Other possible values are ‘ignore’, ‘replace’ and any other name registered via codecs.register_error().
boing.net.slip
— SLIP encoding¶The module boing.net.slip
provides methods and classes for
supporting the SLIP protocol encoding and decoding.
boing.net.slip.
encode
(data)¶Return a slip encoded version of data.
boing.net.slip.
decode
(data, previous=None)¶Return the list of bytearrays obtained from the slip decoding of data followed by the undecoded bytes. If previous is not None, data is appended to previous before decoding. A typical usage would be:
buffer = bytearray()
decoded, buffer = decode(data, buffer)
boing.net.json
— JSON encoding¶The module boing.net.json
provides methods and classes for
supporting JSON object serialization. It uses the python json standard
module, but it provides a default solution for serializing bytestrings
and datetime.datetime objects.
Encoder and Decoder classes provide a standard interface for the JSON encoding.
boing.net.json.
encode
(obj)¶Return a string containing the json serialization of obj.
boing.net.json.
decode
(string)¶Return the object obtained for decoding string using the JSON decoding.
boing.net.osc
— OSC encoding¶The module boing.net.osc
provides methods and classes for
handling OSC formatted messages.
Encoder and Decoder classes provide a standard interface for the OSC encoding.
boing.net.pickle
— Python pickle encoding¶The module boing.net.pickle
provides methods and classes for
supporting Python object serialization. It uses the python pickle
standard module.
Encoder and Decoder classes provide a standard interface for the pickle encoding.
boing.net.pickle.
encode
(obj, protocol=None)¶Return the pickled representation of obj as a bytes object.
The optional protocol argument tells the pickler to use the given protocol; supported protocols are 0, 1, 2, 3. The default protocol is 3; a backward-incompatible protocol designed for Python 3.0.
Specifying a negative protocol version selects the highest protocol version supported. The higher the protocol used, the more recent the version of Python needed to read the pickle produced.
boing.net.pickle.
decode
(data)¶Read a pickled object hierarchy from the bytes object data and return the reconstituted object hierarchy specified therein.
The protocol version of the pickle is detected automatically, so no protocol argument is needed. Bytes past the pickled object’s representation are ignored.
boing.net.pickle.
Encoder
¶The Encoder is able to serialize Python objects into pickle bytestrings.
encode
(obj)¶Return the pickled representation of obj as a bytes object.
The optional protocol argument tells the pickler to use the given protocol; supported protocols are 0, 1, 2, 3. The default protocol is 3; a backward-incompatible protocol designed for Python 3.0.
Specifying a negative protocol version selects the highest protocol version supported. The higher the protocol used, the more recent the version of Python needed to read the pickle produced.
reset
()¶NOP method.
boing.net.pickle.
Decoder
¶The Decoder object is able to decode pickle bytestrings into the corrispetive objects hierarchy.
decode
(obj)¶Read a pickled object hierarchy from the bytes object data and return the reconstituted object hierarchy specified therein.
The protocol version of the pickle is detected automatically, so no protocol argument is needed. Bytes past the pickled object’s representation are ignored.
reset
()¶Reset the slip internal buffer.
Common networking utilities:
boing.net.ip
— IP utilities¶The module boing.net.ip
provides few functions related to
IP addressing.
boing.net.ip.
resolve
(addr, port, family=0, type=0)¶Return a pair (addr, port) representing the IP address associated to the host host for the specified port, family and socket type.
boing.net.ip.
addrToString
(addr)¶Return a string representing the QHostAddress addr.
boing.net.tcp
— TCP utilities¶Todo
Improve docs for the module boing.net.tcp
boing.net.udp
— UDP utilities¶Todo
Improve docs for the module boing.net.udp
boing.net.ntp
— NTP utilities¶The module boing.net.ntp
provides few functions for handling
the Network Time Protocol (NTP).
Example:
import datetime
from boing.net import ntp
srvtime = ntp.ntpFromServer("europe.pool.ntp.org")
srvdatetime = ntp.ntp2datetime(srvtime)
now = datetime.datetime.now()
print("Server time:", srvdatetime)
print("Local time:", now)
print("Delta:", now - srvdatetime)
boing.net.ntp.
ntpEncode
(t)¶Return the bytes object obtained from encoding the POSIX timestamp t.
boing.net.ntp.
ntpDecode
(data)¶Return the POSIX timestamp obtained from decoding the bytes object data.
boing.net.ntp.
ntpFromServer
(server)¶Send an ntp time query to the server and return the obtained POSIX timestamp. The request is sent by using an UDP connection to the port 123 of the NTP server.
boing.net.ntp.
ntp2datetime
(t)¶Return the datetime.datetime
instance corresponding to
the POSIX timestamp t.
boing.net.ntp.
datetime2ntp
(dt)¶Return the POSIX timestamp corresponding to the
datetime.datetime
instance dt.
boing.nodes
— The nodes of the pipeline¶The module boing.nodes
contains a set of generic utility nodes.
Products debugging
boing.nodes.
Dump
(request=Request.ANY, mode='items', separator='\n\n', src=False, dest=False, depth=None, parent=None)¶Instances of the Dump
class produce a string
representation of the products they receive. The string is
obtained using the function boing.utils.deepDump()
.
The parameter request must be an instance of the class
boing.core.Request
and it is used to select the product
to be dumped. The default value for request is
Request.ALL
. mode defines how the received
products will be dumped. The available values are:
'keys'
, only the matched keys are written;'values'
, only the values of the matched keys are written;'items'
, both the keys and values are written.separator defines the string to be written between two
products. The default value for separator is '\n\n'
. src
defines whether the node also dumps the producer of the received
products. The default for src is False. The paramenter dest
defines whether the node adds a reference to itself when it dumps
the received products; its default value is False. The parameter
depth defines how many levels of the data hierarchy are explored
and it is directly passed to the boing.utils.deepDump()
function.
mode
()¶Return the node’s mode.
setMode
(mode)¶Set the node’s dump mode.
Products editing
boing.nodes.
Editor
(dict, blender, parent=None)¶Instances of the Editor
class apply to the received
products the (key, values) pairs of dict.
blender defines the output of the node (see
boing.core.Functor
). parent must be a
PyQt4.QtCore.QObject
and it defines the node’s parent.
get
(key, default=None)¶Return the value for key if key is in the editor’s dictionary, else default. If default is not given, it defaults to None.
set
(key, value)¶Set the value for key to value.
items
()¶Return a new view of the editor dictionary’s items ((key, value) pairs).
boing.nodes.
DiffArgumentFunctor
(functorfactory, request, blender=Functor.MERGECOPY, parent=None)¶It takes a functorfactory and for each different argument path, it creates a new functor which is applied to the argument value. The args must be a diff-based path so that functor can be removed depending on ‘diff.removed’ instances.
Timing utilities
boing.nodes.
Timekeeper
(blender=Functor.MERGECOPY, parent=None)¶Instances of the Timekeeper
class tag each received
product with the timestamp when the product is received; then they
forward the product.
blender defines the output of the node (see
boing.core.Functor
). parent must be a
PyQt4.QtCore.QObject
and it defines the node’s parent.
boing.utils
— Common utilities¶The module boing.utils
contains generic utility classes and
functions.
boing.utils.
assertIsInstance
(obj, *valid)¶Raise TypeError if obj is not an instance of a class in valid.
boing.utils.
deepDump
(obj, fd=sys.stdout, maxdepth=None, indent=2, end="n", sort=True)¶Write to fd a textual representation of obj.
boing.utils.
Console
(inputdevice, outputdevice, banner="", locals=None, parent=None)¶Interactive Python console running along the Qt eventloop.
push
(line)¶Pass line to the Python interpreter.
Submodules
boing.utils.url
— Uniform Resource Locator¶The module boing.utils.url
mainly provides the class
URL
, which is used to represent a Uniform Resource Locator.
boing.utils.url.
URL
(string)¶An instance of the class URL
represents an Uniform
Resource Locator (URL). The attribute string of the class
constuctor defines the URL that the instance will represent; at the
instance initialization, string is parsed in order to detect the kind
of URL and to separate it into the specific components: schema,
site, path, query, fragment.
Usage example:
>>> from boing.utils.url import URL
>>> url = URL("ftp://paolo:pwd@localhost:8888/temp?key=value#frag")
>>> url.scheme
'ftp'
>>> url.site.user
'paolo'
>>> url.site.password
'pwd'
>>> url.site.host
'localhost'
>>> url.site.port
8888
>>> str(url.path)
'/temp'
>>> url.query['key']
'value'
>>> url.fragment
'frag'
Each instance owns the following read-only attributes:
kind
¶Kind of URL. It equals to one of the following:
URL.EMPTY
— empty URLURL.OPAQUE
— URL like <scheme>:<opaque>
URL.GENERIC
— URL like <scheme>://<site>/<path>?<query>#<fragment>
URL.NETPATH
— URL like //<site>/<path>?<query>#<fragment>
URL.ABSPATH
— URL like /<path>?<query>#<fragment>
URL.RELPATH
— URL like <path>?<query>#<fragment>
scheme
¶URL scheme defined by a str
.
fragment
¶URL fragment defined by a str
.
opaque
¶if the URL is of kind URL.OPAQUE
it defines the right part of the URL;
otherwise it is set by default to the empty string ""
.
The string representation of an URL
instance is normally
equal to the string passed at the instance initialization, but
there are few exceptions:
>>> str(URL("udp://:3333"))
'udp://:3333'
>>> str(URL("udp://:3333:0"))
'udp://:3333'
>>> str(URL("file:/tmp/log"))
'file:///tmp/log'
URL
instances are equal if their string representation is the same:
>>> URL("udp://:3333")==URL("udp://:3333")
True
>>> URL("udp://:3333:0")==URL("udp://:3333")
True
URL
instances can be compared to str
objects:
>>> URL("udp://:3333")=="udp://:3333"
True
and they can be concatenated as they were str
objects:
>>> url = URL("udp://:3333")
>>> "osc."+url
'osc.udp://:3333'
>>> url+"#frag"
'udp://:3333#frag'
Note that the result is a str
, not an URL
instance.
boing.utils.url.
URL_site
(string)¶Used to store the component site of an URL. Each instance owns the following attributes:
user
¶User defined by a string.
password
¶Password defined by a string. It is NOT encripted.
host
¶Site host defined by a string.
port
¶Port number defined by an integer. It defaults to 0
.
Usage example:
>>> url = URL("ftp://paolo:pwd@localhost:8888")
>>> url.site
URL_site('paolo:pwd@localhost:8888')
>>> print(url.site)
paolo:pwd@localhost:8888
>>> url.site.user
'paolo'
>>> url.site.password
'pwd'
>>> url.site.host
'localhost'
>>> url.site.port
8888
Instances can be compared to str
objects:
>>> url = URL("udp://localhost:3333")
>>> url.site=="localhost:3333"
True
and have Boolean value to True
if anyone of the component
attributes is defined:
>>> bool(URL("udp://localhost:3333").site)
True
>>> bool(URL("udp://").site)
False
Warning
Pay attention to the default case:
>>> bool(URL("udp://:0").site)
False
boing.utils.url.
URL_path
(string)¶Used to store the component path of an URL. Usage example:
>>> url = URL("file:///tmp/log")
>>> url.path
URL_path('/tmp/log')
>>> print(url.path)
/tmp/log
>>> url.path.isAbsolute()
True
isAbsolute
()¶Return wheter the path is absolute:
>>> URL("file:///tmp/log").path.isAbsolute()
True
>>> URL("/tmp/log").path.isAbsolute()
True
>>> URL("file").path.isAbsolute()
False
>>> URL("./file").path.isAbsolute()
False
Instances can be compared to str
objects:
>>> url = URL("file:///tmp/log")
>>> url.path=="/tmp/log"
True
and have Boolean value to True
if the URL path is not empty:
>>> bool(URL("file:///tmp/log").path)
True
>>> bool(URL("/").path)
True
>>> bool(URL("udp://:8888").path)
False
Warning
Pay attention to the default transformation:
>>> str(URL("file:/tmp/log"))
'file:///tmp/log'
boing.utils.url.
URL_query
(string)¶Used to store the component query of an URL. This class implements the
collections.MutableMapping
ABC. It is also able to encode the
URL’s query into a “percent-encoded” string.
Usage examples:
>>> url = URL("udp://:8888?name=Jérémie&connect")
>>> url
URL('udp://:8888?name=J%e9r%e9mie&connect')
>>> url.query
URL_query('name=J%e9r%e9mie&connect')
>>> url.query['name']
'Jérémie'
>>> dict(url.query)
{'name': 'Jérémie', 'connect': ''}
>>> URL("udp://:8888?name=Jérémie&connect")==URL("udp://:8888?name=J%e9r%e9mie&connect")
True
The easiest way to get help with the project is to join the mailing list boing@librelist.com.
The archive of the mailing list can be checked out at http://librelist.com/browser/boing/ .
The other good way is to open an issue on github.
v0.3.1, Sep, 18 2012 — Fixed and upgraded the installation guide.
boing.config
for storing global configuration variables.--no-gui
for running Boing without a display server..ui
files are automatically compiled when the package is installed.boing.VERSION
changed into boing.__version__
boing.utils.url
.v0.3.0, Sep, 10 2012 – First public release.
v0.2.0, Apr, 1 2012 – Architetecture wide modifications.
v0.1.0, Jan, 1 2012 – Pre-release.
Source: http://www.gnu.org/licenses/gpl-2.0.txt
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.
- Improve docs and unit test for modules
boing.utils.QPath
andboing.utils.fileutils
.- Add docs and unit test for class
boing.utils.url.URL
on MS Windows.
- Write more tutorials.
- Upgrade module
boing.core
documentation.
Bugs and unittest:
Add
boing.test.nodes.test_loader
cases for the data processing nodes.Improve class
QPath
: regular expression compilation, join method, add unittest. The command:QPath.filter(boing.nodes.encoding.TuioDecoder.getTemplate(), "diff.*.contacts.*.rel_pos")raises an error if
QPath._iterProp()
returns a real iterator.when
boing.create()
raises an exception, it shows the lower URI and not the original one. This may be misleading for users.The
player:
‘s playlist has some model trouble: when I drag and drop some files from a folder to the root level before the folder an Exception is raised. Sometimes files desappears.Handle when a source has been closed and when to start players (e.g. if TCP socked has been disconnected, TcpServer turned off).
Resolve the UDP socket reuse port issue on Windows.
Pipeline architecture:
- The class
Producer
should also automatically know whether being active or not, like the classWiseWorker
does. Check the ‘tag’ structure.- The class
Node
shouldn’t be a QObject?- Improve Graphers (Graphers should draw themselves).
- Add exclusive requests in order to optimize productivity.
Data model:
- json and pickle decoders should someway know what they produce.
- Check the
quickdict
constructor: if an hierarchical dictionary is passed to the constructor not all the hierarchy is transformed to a quickdict.Functionalities:
- Encoder and Decoders in module boing.nodes.encoding should inherit boing.nodes.Encoder and boing.node.Decoder.
- Find a way so that the boing.node.loader can create nodes from external source files, so that users can add custom nodes.
- Develop the transformation node, which transforms the data hierarchy (JSON-schema validator).
- Develop
evdev
anduinput
in&out bridges.- Enable remote node.
- Improve Contact Viz.
- Consider adding the module
libfilter.filtering.signal
toboing.filtering
.- Develop lib tIO cython bindings.
- When Qt4.8 will be available, add multicast support to UdpSocket.
Gesture Recognition:
- Prepare the directory with the gesture templates that the recognizer can use.
- Fix the recognition nodes.
- Support 1$ algorithm.
Docs:
- Check which Ubuntu packages are really necessary.
Todo
Describe how to configure the pipeline dinamically
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/boing.rst, line 94.)
Todo
Comment module boing.filtering
.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/boing.filtering.rst, line 29.)
Todo
Improve docs for the module boing.net.tcp
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/boing.net.tcp.rst, line 24.)
Todo
Improve docs for the module boing.net.udp
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/boing.net.udp.rst, line 24.)
Todo
Describe the data model.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/datamodel.rst, line 24.)
Todo
Describe an example of functional node.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/developer.rst, line 57.)
Todo
Speak about the default nodes and the node uris convention. Also add a link to the Nodes reference table.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 24.)
Todo
Describe data logging and replaying (both OSC and JSON formats).
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 46.)
Todo
Describe the recorder tool.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 52.)
Todo
Describe the Player tool.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 65.)
Todo
Describe the calibration node.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 81.)
Todo
Describe the filtering module.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/functionalities.rst, line 87.)
Todo
Logging utils tutorial
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/logging.rst, line 24.)
Todo
multi-touch utilities tutorial.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/multitouch.rst, line 24.)
Todo
Improve the OSC tutorial.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/osc.rst, line 24.)
Todo
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/pipeline.rst, line 406.)
Todo
Data redirection tutorial
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/redirection.rst, line 24.)
Todo
Script advanced options tutorial
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/scriptadvanced.rst, line 24.)
Todo
Improve the TUIO tutorial.
(The original entry is located in /home/docs/checkouts/readthedocs.org/user_builds/boing/checkouts/stable/doc/source/tuio.rst, line 24.)