Fix a couple of memory leaks - D-Bus signature strings, and decoded Unicode objects
[dbus-python-phuang.git] / doc / tutorial.txt.in
blobcbea47b9d8f4a6ee2e7e0a8c9f9de23b566e7235
1 .. @configure_input@
3 ====================
4 dbus-python tutorial
5 ====================
7 :Author: Simon McVittie, `Collabora Ltd.`_
8 :Date: 2006-01-16
9 :``dbus-python`` version: @VERSION@
11 .. _`Collabora Ltd.`: http://www.collabora.co.uk/
13 This tutorial requires Python 2.4 or up, and ``dbus-python`` 0.80rc4 or up.
15 .. contents::
17 .. --------------------------------------------------------------------
19 .. _Bus object:
20 .. _Bus objects:
22 Connecting to the Bus
23 =====================
25 Applications that use D-Bus typically connect to a *bus daemon*, which
26 forwards messages between the applications. To use D-Bus, you need to create a
27 ``Bus`` object representing the connection to the bus daemon.
29 There are generally two bus daemons you may be interested in. Each user
30 login session should have a *session bus*, which is local to that
31 session. It's used to communicate between desktop applications. Connect
32 to the session bus by creating a ``SessionBus`` object::
34     import dbus
36     session_bus = dbus.SessionBus()
38 The *system bus* is global and usually started during boot; it's used to
39 communicate with system services like udev_, NetworkManager_, and the
40 `Hardware Abstraction Layer daemon (hald)`_. To connect to the system
41 bus, create a ``SystemBus`` object::
43     import dbus
45     system_bus = dbus.SystemBus()
47 Of course, you can connect to both in the same application.
49 .. _udev:
50     http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html
51 .. _NetworkManager:
52     http://www.gnome.org/projects/NetworkManager/
53 .. _Hardware Abstraction Layer daemon (hald):
54     http://www.freedesktop.org/wiki/Software/hal
56 .. --------------------------------------------------------------------
58 Making method calls
59 ===================
61 D-Bus applications can export objects for other applications' use. To
62 start working with an object in another application, you need to know:
64 * The *bus name*. This identifies which application you want to
65   communicate with. You'll usually identify applications by a
66   *well-known name*, which is a dot-separated string starting with a
67   reversed domain name, such as ``org.freedesktop.NetworkManager``
68   or ``com.example.WordProcessor``.
70 * The *object path*. Applications can export many objects - for
71   instance, example.com's word processor might provide an object
72   representing the word processor application itself and an object for
73   each document window opened, or it might also provide an object for
74   each paragraph within a document.
75   
76   To identify which one you want to interact with, you use an object path,
77   a slash-separated string resembling a filename. For instance, example.com's
78   word processor might provide an object at ``/`` representing the word
79   processor itself, and objects at ``/documents/123`` and
80   ``/documents/345`` representing opened document windows.
82 As you'd expect, one of the main things you can do with remote objects
83 is to call their methods. As in Python, methods may have parameters,
84 and they may return one or more values.
86 .. _proxy object:
88 Proxy objects
89 -------------
91 To interact with a remote object, you use a *proxy object*. This is a
92 Python object which acts as a proxy or "stand-in" for the remote object -
93 when you call a method on a proxy object, this causes dbus-python to make
94 a method call on the remote object, passing back any return values from
95 the remote object's method as the return values of the proxy method call.
97 To obtain a proxy object, call the ``get_object`` method on the ``Bus``.
98 For example, NetworkManager_ has the well-known name
99 ``org.freedesktop.NetworkManager`` and exports an object whose object
100 path is ``/org/freedesktop/NetworkManager``, plus an object per network
101 interface at object paths like
102 ``/org/freedesktop/NetworkManager/Devices/eth0``. You can get a proxy
103 for the object representing eth0 like this::
105     >>> import dbus
106     >>> bus = dbus.SystemBus()
107     >>> bus.get_object('org.freedesktop.NetworkManager',
108     ...                '/org/freedesktop/NetworkManager/Devices/eth0')
109     <ProxyObject wrapping <dbus.Bus on SYSTEM at 0x3007e150>
110     org.freedesktop.NetworkManager
111     /org/freedesktop/NetworkManager/Devices/eth0 at 0x301f0ad0>
112     >>>
114 Interfaces and methods
115 ----------------------
117 D-Bus uses *interfaces* to provide a namespacing mechanism for methods.
118 An interface is a group of related methods and signals (more on signals
119 later), identified by a name which is a series of dot-separated components
120 starting with a reversed domain name. For instance, each NetworkManager_
121 object representing a network interface implements the interface
122 ``org.freedesktop.NetworkManager.Devices``, which has methods like
123 ``getProperties``.
125 To call a method, call the method of the same name on the proxy object,
126 passing in the interface name via the ``dbus_interface`` keyword argument::
128     >>> import dbus
129     >>> bus = dbus.SystemBus()
130     >>> eth0 = bus.get_object('org.freedesktop.NetworkManager',
131     ...                       '/org/freedesktop/NetworkManager/Devices/eth0')
132     >>> eth0.getProperties(dbus_interface='org.freedesktop.NetworkManager.Devices')
133     (dbus.ObjectPath('/org/freedesktop/NetworkManager/Devices/eth0'), [...])
134     >>>
136 (I've truncated the list of properties here.)
138 .. _dbus.Interface:
140 As a short cut, if you're going to be calling many methods with the same
141 interface, you can construct a ``dbus.Interface`` object and call
142 methods on that, without needing to specify the interface again::
144     >>> import dbus
145     >>> bus = dbus.SystemBus()
146     >>> eth0 = bus.get_object('org.freedesktop.NetworkManager',
147     ...                       '/org/freedesktop/NetworkManager/Devices/eth0')
148     >>> eth0_dev_iface = dbus.Interface(eth0,
149     ...     dbus_interface='org.freedesktop.NetworkManager.Devices')
150     >>> eth0_dev_iface.getProperties()
151     (dbus.ObjectPath('/org/freedesktop/NetworkManager/Devices/eth0'), [...])
152     >>>
154 See also
155 ~~~~~~~~
157 See the example in ``examples/example-client.py``. Before running it,
158 you'll need to run ``examples/example-service.py`` in the background or
159 in another shell.
161 Data types
162 ----------
164 Unlike Python, D-Bus is statically typed - each method has a certain
165 *signature* representing the types of its arguments, and will not accept
166 arguments of other types.
168 D-Bus has an introspection mechanism, which ``dbus-python`` tries to use
169 to discover the correct argument types. If this succeeds, Python types
170 are converted into the right D-Bus data types automatically, if possible;
171 ``TypeError`` is raised if the type is inappropriate.
173 If the introspection mechanism fails (or the argument's type is
174 variant - see below), you have to provide arguments of
175 the correct type. ``dbus-python`` provides Python types corresponding to
176 the D-Bus data types, and a few native Python types are also converted to
177 D-Bus data types automatically. If you use a type which isn't among these,
178 a ``TypeError`` will be raised telling you that ``dbus-python`` was
179 unable to guess the D-Bus signature.
181 Basic types
182 ~~~~~~~~~~~
184 The following basic data types are supported.
186 ==========================  =============================  =====
187 Python type                 converted to D-Bus type        notes
188 ==========================  =============================  =====
189 D-Bus `proxy object`_       ObjectPath (signature 'o')     `(+)`_
190 `dbus.Interface`_           ObjectPath (signature 'o')     `(+)`_
191 `dbus.service.Object`_      ObjectPath (signature 'o')     `(+)`_
192 ``dbus.Boolean``            Boolean (signature 'b')        a subclass of ``int``
193 ``dbus.Byte``               byte (signature 'y')           a subclass of ``int``
194 ``dbus.Int16``              16-bit signed integer ('n')    a subclass of ``int``
195 ``dbus.Int32``              32-bit signed integer ('i')    a subclass of ``int``
196 ``dbus.Int64``              64-bit signed integer ('x')    `(*)`_
197 ``dbus.UInt16``             16-bit unsigned integer ('q')  a subclass of ``int``
198 ``dbus.UInt32``             32-bit unsigned integer ('u')  `(*)_`
199 ``dbus.UInt64``             64-bit unsigned integer ('t')  `(*)_`
200 ``dbus.Double``             double-precision float ('d')   a subclass of ``float``
201 ``dbus.ObjectPath``         object path ('o')              a subclass of ``str``
202 ``dbus.Signature``          signature ('g')                a subclass of ``str``
203 ``dbus.String``             string ('s')                   a subclass of 
204                                                            ``unicode``
205 ``dbus.UTF8String``         string ('s')                   a subclass of ``str``
206 ``bool``                    Boolean ('b')
207 ``int`` or subclass         32-bit signed integer ('i')
208 ``long`` or subclass        64-bit signed integer ('x')
209 ``float`` or subclass       double-precision float ('d')
210 ``str`` or subclass         string ('s')                   must be valid UTF-8
211 ``unicode`` or subclass     string ('s')
212 ==========================  =============================  =====
214 .. _(*):
216 Types marked (*) may be a subclass of either ``int`` or ``long``, depending
217 on platform.
219 .. _(+):
221 (+): D-Bus proxy objects, exported D-Bus service objects and anything
222 else with the special attribute ``__dbus_object_path__``, which
223 must be a string, are converted to their object-path. This might be
224 useful if you're writing an object-oriented API using dbus-python.
226 Basic type conversions
227 ~~~~~~~~~~~~~~~~~~~~~~
229 If introspection succeeded, ``dbus-python`` will also accept:
231 * for Boolean parameters, any object (converted as if via ``int(bool(...))``)
232 * for byte parameters, a single-character string (converted as if via ``ord()``)
233 * for byte and integer parameters, any integer (must be in the correct range)
234 * for object-path and signature parameters, any ``str`` or ``unicode``
235   subclass (the value must follow the appropriate syntax)
237 Container types
238 ~~~~~~~~~~~~~~~
240 D-Bus supports four container types: array (a variable-length sequence of the
241 same type), struct (a fixed-length sequence whose members may have
242 different types), dictionary (a mapping from values of the same basic type to
243 values of the same type), and variant (a container which may hold any
244 D-Bus type, including another variant).
246 Arrays are represented by Python lists, or by ``dbus.Array``, a subclass
247 of ``list``. When sending an array, if an introspected signature is
248 available, that will be used; otherwise, if the ``signature`` keyword
249 parameter was passed to the ``Array`` constructor, that will be used to
250 determine the contents' signature; otherwise, ``dbus-python`` will guess
251 from the array's first item.
253 The signature of an array is 'ax' where 'x' represents the signature of
254 one item. For instance, you could also have 'as' (array of strings) or
255 'a(ii)' (array of structs each containing two 32-bit integers).
257 There's also a type ``dbus.ByteArray`` which is a subclass of ``str``,
258 used as a more efficient representation of a D-Bus array of bytes
259 (signature 'ay').
261 Structs are represented by Python tuples, or by ``dbus.Struct``, a
262 subclass of ``tuple``. When sending a struct, if an introspected signature is
263 available, that will be used; otherwise, if the ``signature`` keyword
264 parameter was passed to the ``Array`` constructor, that will be used to
265 determine the contents' signature; otherwise, ``dbus-python`` will guess
266 from the array's first item.
268 The signature of a struct consists of the signatures of the contents,
269 in parentheses - for instance '(is)' is the signature of a struct
270 containing a 32-bit integer and a string.
272 Dictionaries are represented by Python dictionaries, or by
273 ``dbus.Dictionary``, a subclass of ``dict``. When sending a dictionary,
274 if an introspected signature is available, that will be used; otherwise,
275 if the ``signature`` keyword parameter was passed to the ``Dictionary``
276 constructor, that will be used to determine the contents' key and value
277 signatures; otherwise, ``dbus-python`` will guess from an arbitrary item
278 of the ``dict``.
280 The signature of a dictionary is 'a{xy}' where 'x' represents the
281 signature of the keys (which may not be a container type) and 'y'
282 represents the signature of the values. For instance,
283 'a{s(ii)}' is a dictionary where the keys are strings and the values are
284 structs containing two 32-bit integers.
286 Variants are represented by setting the ``variant_level`` keyword
287 argument in the constructor of any D-Bus data type to a value greater
288 than 0 (``variant_level`` 1 means a variant containing some other data type,
289 ``variant_level`` 2 means a variant containing a variant containing some
290 other data type, and so on). If a non-variant is passed as an argument
291 but introspection indicates that a variant is expected, it'll
292 automatically be wrapped in a variant.
294 The signature of a variant is 'v'.
296 .. _byte_arrays and utf8_strings:
298 Return values, and the ``byte_arrays`` and ``utf8_strings`` options
299 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
301 If a D-Bus method returns no value, the Python proxy method will return
302 ``None``.
304 If a D-Bus method returns one value, the Python proxy method will return
305 that value as one of the ``dbus.`` types - by default, strings are
306 returned as ``dbus.String`` (a subclass of Unicode) and byte arrays are
307 returned as a ``dbus.Array`` of ``dbus.Byte``.
309 If a D-Bus method returns multiple values, the Python proxy method
310 will return a tuple containing those values.
312 If you want strings returned as ``dbus.UTF8String`` (a subclass of
313 ``str``) pass the keyword parameter ``utf8_strings=True`` to the proxy
314 method.
316 If you want byte arrays returned as ``dbus.ByteArray`` (also a
317 subclass of ``str`` - in practice, this is often what you want) pass
318 the keyword parameter ``byte_arrays=True`` to the proxy method.
320 .. --------------------------------------------------------------------
322 Making asynchronous method calls
323 ================================
325 Asynchronous (non-blocking) method calls allow multiple method calls to
326 be in progress simultaneously, and allow your application to do other
327 work while it's waiting for the results. To make asynchronous calls,
328 you first need an event loop or "main loop".
330 Setting up an event loop
331 ------------------------
333 Currently, the only main loop supported by ``dbus-python`` is GLib.
335 ``dbus-python`` has a global default main loop, which is the easiest way
336 to use this functionality. To arrange for the GLib main loop to be the
337 default, use::
339     from dbus.mainloop.glib import DBusGMainLoop
341     DBusGMainLoop(set_as_default=True)
343 You must do this before `connecting to the bus`_.
345 Actually starting the main loop is as usual for ``pygobject``::
347     import gobject
349     loop = gobject.MainLoop()
350     loop.run()
352 While ``loop.run()`` is executing, GLib will run your callbacks when
353 appropriate. To stop, call ``loop.quit()``.
355 You can also set a main loop on a per-connection basis, by passing a
356 main loop to the Bus constructor::
358     import dbus
359     from dbus.mainloop.glib import DBusGMainLoop
361     dbus_loop = DBusGMainLoop()
363     bus = dbus.SessionBus(mainloop=dbus_loop)
365 This isn't very useful until we support more than one main loop, though.
367 Backwards compatibility: ``dbus.glib``
368 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
370 In versions of ``dbus-python`` prior to 0.80, the way to set GLib as the
371 default main loop was::
373     import dbus.glib
375 Executing that import statement would automatically load the GLib main
376 loop and make this the default. This is now deprecated, since it's
377 highly non-obvious, but may be useful if you want to write or understand
378 backwards-compatible code.
380 The Qt main loop
381 ~~~~~~~~~~~~~~~~
383 FIXME: describe how to use the Qt event loop too (requires recent pyqt)
385 Making asynchronous calls
386 -------------------------
388 To make a call asynchronous, pass two callables as keyword arguments
389 ``reply_handler`` and ``error_handler`` to the proxy method. The proxy
390 method will immediately return `None`. At some later time, when the event
391 loop is running, one of these will happen: either
393 * the ``reply_handler`` will be called with the method's return values
394   as arguments; or
396 * the ``error_handler`` will be called with one argument, an instance of
397   ``DBusException`` representing a remote exception.
399 See also
400 ~~~~~~~~
402 ``examples/example-async-client.py`` makes asynchronous method calls to
403 the service provided by ``examples/example-service.py`` which return
404 either a value or an exception. As for ``examples/example-client.py``,
405 you need to run ``examples/example-service.py`` in the background or
406 in another shell first.
408 .. --------------------------------------------------------------------
410 Receiving signals
411 =================
413 To receive signals, the Bus needs to be connected to an event loop - see
414 section `Setting up an event loop`_. Signals will only be received while
415 the event loop is running.
417 Receiving signals from a proxy object
418 -------------------------------------
420 `Proxy objects`_ have a special method ``connect_to_signal`` which
421 arranges for a callback to be called when a signal is received
422 from the corresponding remote object. The parameters are:
424 * the name of the signal
426 * a callable (the handler function) which will be called by the event loop
427   when the signal is received - its parameters will be the arguments of
428   the signal
430 * the keyword argument ``dbus_interface`` qualifies the name with its
431   interface
433 `dbus.Interface` objects have a similar ``connect_to_signal`` method,
434 but in this case you don't need the ``dbus_interface`` keyword argument
435 since the interface to use is already known.
437 ``connect_to_signal`` has keyword arguments ``utf8_strings`` and
438 ``byte_arrays`` which influence the types used when calling the
439 handler function, in the same way as the `byte_arrays and utf8_strings`_
440 options on proxy methods.
442 Example
443 ~~~~~~~
445 ``examples/example-signal-recipient.py`` receives signals. Before running it,
446 you'll need to run ``examples/example-signal-emitter.py`` in the background or
447 in another shell. As well as ``connect_to_signal`` it demonstrates more
448 general signal matching, described next.
450 Getting more information from a signal
451 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
453 You can also arrange for more information to be passed to the handler
454 function. If you pass the keyword arguments ``sender_keyword``,
455 ``destination_keyword``, ``interface_keyword``, ``member_keyword`` or
456 ``path_keyword`` to the ``connect_to_signal`` method, the appropriate
457 part of the signal message will be passed to the handler function as a
458 keyword argument: for instance if you use ::
460     def handler(sender=None):
461         print "got signal from %r" % sender
463     iface.connect_to_signal("Hello", handler, sender_keyword='sender')
465 and a signal ``Hello`` with no arguments is received from
466 ``com.example.Foo``, the ``handler`` function will be called with
467 ``sender='com.example.Foo'``.
469 String argument matching
470 ~~~~~~~~~~~~~~~~~~~~~~~~
472 If there are keyword parameters for the form ``arg``\ *n* where n is a
473 small non-negative number, their values must be ``unicode`` objects
474 or UTF-8 strings. The handler will only be called if that argument
475 of the signal (numbered from zero) is a D-Bus string (in particular,
476 not an object-path or a signature) with that value.
478 .. *this comment is to stop the above breaking vim syntax highlighting*
480 General signal matching
481 -----------------------
483 To match signals in a more general way, you can use the
484 ``add_signal_receiver`` method on `Bus objects`_. This behaves rather
485 like ``connect_to_signal``, but has the following parameters:
487 * the handler function ``handler_function``, a callable: the same as for
488   ``connect_to_signal``
489 * the signal name, ``signal_name``: here None (the default) matches all names
490 * the D-Bus interface, ``dbus_interface``: again None is the default,
491   and matches all interfaces
492 * a sender bus name (well-known or unique), ``named_service``: None is again
493   the default, and matches all senders
494 * a sender object path, ``path``: once again None is the default and
495   matches all object paths
497 The same extra keyword arguments as for ``connect_to_signal`` are also
498 available.
500 See also
501 ~~~~~~~~
503 As before, ``examples/signal-recipient.py`` receives signals - it demonstrates
504 general signal matching as well as ``connect_to_signal``. Before running it,
505 you'll need to run ``examples/signal-emitter.py`` in the background or
506 in another shell.
508 .. _BusName:
510 .. --------------------------------------------------------------------
512 Claiming a bus name
513 ===================
515 FIXME describe `BusName`_ - perhaps fix its API first?
517 The unique-instance idiom
518 -------------------------
520 FIXME provide exemplary code, put it in examples
522 .. _exported object:
523 .. _exported objects:
525 .. --------------------------------------------------------------------
527 Exporting objects
528 =================
530 Objects made available to other applications over D-Bus are said to be
531 *exported*. All subclasses of ``dbus.service.Object`` are automatically
532 exported.
534 To export objects, the Bus needs to be connected to an event loop - see
535 section `Setting up an event loop`_. Exported methods will only be called,
536 and queued signals will only be sent, while the event loop is running.
538 .. _dbus.service.Object:
540 Inheriting from ``dbus.service.Object``
541 ---------------------------------------
543 To export an object onto the Bus, just subclass
544 ``dbus.service.Object``. Object expects either a `BusName`_ or a `Bus
545 object`_, and an object-path, to be passed to its constructor: arrange
546 for this information to be available. For example::
548     class Example(dbus.service.Object):
549         def __init__(self, object_path):
550             dbus.service.Object.__init__(self, dbus.SessionBus(), path)
552 This object will automatically support introspection, but won't do
553 anything particularly interesting. To fix that, you'll need to export some
554 methods and signals too.
556 FIXME also mention dbus.gobject.ExportedGObject once I've written it
558 Exporting methods with ``dbus.service.method``
559 ----------------------------------------------
561 To export a method, use the decorator ``dbus.service.method``. For
562 example::
564     class Example(dbus.service.Object):
565         def __init__(self, object_path):
566             dbus.service.Object.__init__(self, dbus.SessionBus(), path)
568         @dbus.service.method(interface='com.example.Sample',
569                              in_signature='v', out_signature='s')
570         def StringifyVariant(self, variant):
571             return str(variant)
573 The ``in_signature`` and ``out_signature`` are D-Bus signature strings
574 as described in `Data Types`_.
576 As well as the keywords shown, you can pass ``utf8_strings`` and
577 ``byte_arrays`` keyword arguments, which influence the types which will
578 be passed to the decorated method when it's called via D-Bus, in the
579 same way that the `byte_arrays and utf8_strings`_ options affect the
580 return value of a proxy method.
582 You can find a simple example in ``examples/example-service.py``, which
583 we used earlier to demonstrate ``examples/example-client.py``.
585 Finding out the caller's bus name
586 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
588 The ``method`` decorator accepts a ``sender_keyword`` keyword argument.
589 If you set that to a string, the unique bus name of the sender will be
590 passed to the decorated method as a keyword argument of that name::
592     class Example(dbus.service.Object):
593         def __init__(self, object_path):
594             dbus.service.Object.__init__(self, dbus.SessionBus(), path)
596         @dbus.service.method(interface='com.example.Sample',
597                              in_signature='', out_signature='s',
598                              sender_keyword='sender')
599         def SayHello(self, sender=None):
600             return 'Hello, %s!' % sender
601             # -> something like 'Hello, :1.1!'
603 Asynchronous method implementations
604 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
606 FIXME and also add an example, perhaps examples/example-async-service.py
608 Emitting signals with ``dbus.service.signal``
609 ---------------------------------------------
611 To export a signal, use the decorator ``dbus.service.signal``; to emit
612 that signal, call the decorated method. The decorated method can also
613 contain code which will be run when called, as usual. For example::
615     class Example(dbus.service.Object):
616         def __init__(self, object_path):
617             dbus.service.Object.__init__(self, dbus.SessionBus(), path)
619         @dbus.service.signal(interface='com.example.Sample',
620                              signature='us')
621         def NumberOfBottlesChanged(self, number, contents):
622             print "%d bottles of %s on the wall" % (number, contents)
624     e = Example('/bottle-counter')
625     e.NumberOfBottlesChanged(100, 'beer')
626     # -> emits com.example.Sample.NumberOfBottlesChanged(100, 'beer')
627     #    and prints "100 bottles of beer on the wall"
629 The signal will be queued for sending when the decorated method returns -
630 you can prevent the signal from being sent by raising an exception
631 from the decorated method (for instance, if the parameters are
632 inappropriate). The signal will only actually be sent when the event loop
633 next runs.
635 Example
636 ~~~~~~~
638 ``examples/example-signal-emitter.py`` emits some signals on demand when
639 one of its methods is called. (In reality, you'd emit a signal when some
640 sort of internal state changed, which may or may not be triggered by a
641 D-Bus method call.)
643 .. --------------------------------------------------------------------
645 License for this document
646 =========================
648 Copyright 2006-2007 `Collabora Ltd.`_
650 Licensed under the Academic Free License version 2.1
652 This document is free software; you can redistribute it and/or modify
653 it under the terms of the GNU General Public License as published by
654 the Free Software Foundation; either version 2 of the License, or
655 (at your option) any later version.
657 This document is distributed in the hope that it will be useful,
658 but WITHOUT ANY WARRANTY; without even the implied warranty of
659 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
660 GNU General Public License for more details.
662 You should have received a copy of the GNU General Public License
663 along with this document; if not, write to the Free Software
664 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
667   vim:set ft=rst sw=4 sts=4 et tw=72: