summaryrefslogtreecommitdiffstats
path: root/emacs.d
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2009-11-19 01:44:52 +0100
committerAlexander Sulfrian <alexander@sulfrian.net>2009-11-19 01:44:52 +0100
commit07963cfc7b5bd985bf01ef22c90970501104352d (patch)
tree8166a4c5ff56dfb5a2c8860cd34cb2c04d601fd3 /emacs.d
parent91d3e89c924fb8a932599ccfcf18bc364878ac17 (diff)
downloaddotfiles-07963cfc7b5bd985bf01ef22c90970501104352d.tar.gz
dotfiles-07963cfc7b5bd985bf01ef22c90970501104352d.tar.xz
dotfiles-07963cfc7b5bd985bf01ef22c90970501104352d.zip
added rudel (obby and other colab framework for emacs)
Diffstat (limited to 'emacs.d')
-rw-r--r--emacs.d/lisp/rudel/.bzrignore2
-rw-r--r--emacs.d/lisp/rudel/.svn/all-wcprops173
-rw-r--r--emacs.d/lisp/rudel/.svn/dir-prop-base5
-rw-r--r--emacs.d/lisp/rudel/.svn/entries1001
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/.bzrignore.svn-base2
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/ChangeLog.svn-base2403
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/INSTALL.svn-base58
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/Project.ede.svn-base24
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/README.svn-base88
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/TODO.svn-base436
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-backend.el.svn-base305
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-chat.el.svn-base103
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-compat.el.svn-base158
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-compile.el.svn-base46
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-debug.el.svn-base215
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-errors.el.svn-base66
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-hooks.el.svn-base252
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-icons.el.svn-base90
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-interactive.el.svn-base181
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-loaddefs.el.svn-base23
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-mode.el.svn-base621
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-operations.el.svn-base133
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-operators.el.svn-base172
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-overlay.el.svn-base275
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-protocol.el.svn-base83
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-session-initiation.el.svn-base352
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-speedbar.el.svn-base214
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-state-machine.el.svn-base331
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-tls.el.svn-base201
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-transport.el.svn-base72
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel-util.el.svn-base261
-rw-r--r--emacs.d/lisp/rudel/.svn/text-base/rudel.el.svn-base1012
-rw-r--r--emacs.d/lisp/rudel/ChangeLog2403
-rw-r--r--emacs.d/lisp/rudel/INSTALL58
-rw-r--r--emacs.d/lisp/rudel/Project.ede24
-rw-r--r--emacs.d/lisp/rudel/README88
-rw-r--r--emacs.d/lisp/rudel/TODO436
-rw-r--r--emacs.d/lisp/rudel/doc/.svn/all-wcprops23
-rw-r--r--emacs.d/lisp/rudel/doc/.svn/entries130
-rw-r--r--emacs.d/lisp/rudel/doc/.svn/text-base/Project.ede.svn-base20
-rw-r--r--emacs.d/lisp/rudel/doc/.svn/text-base/card.pdf.svn-basebin0 -> 68211 bytes
-rw-r--r--emacs.d/lisp/rudel/doc/.svn/text-base/card.tex.svn-base329
-rw-r--r--emacs.d/lisp/rudel/doc/Project.ede20
-rw-r--r--emacs.d/lisp/rudel/doc/card.pdfbin0 -> 68211 bytes
-rw-r--r--emacs.d/lisp/rudel/doc/card.tex329
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/all-wcprops41
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/entries232
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/connected.svg.svn-base2479
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/disconnected.svg.svn-base2600
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/document.svg.svn-base608
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/encrypted.svg.svn-base902
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/person.svg.svn-base388
-rw-r--r--emacs.d/lisp/rudel/icons/.svn/text-base/plaintext.svg.svn-base474
-rw-r--r--emacs.d/lisp/rudel/icons/connected.svg2479
-rw-r--r--emacs.d/lisp/rudel/icons/disconnected.svg2600
-rw-r--r--emacs.d/lisp/rudel/icons/document.svg608
-rw-r--r--emacs.d/lisp/rudel/icons/encrypted.svg902
-rw-r--r--emacs.d/lisp/rudel/icons/person.svg388
-rw-r--r--emacs.d/lisp/rudel/icons/plaintext.svg474
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/all-wcprops47
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/entries266
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/Project.ede.svn-base14
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-compound.el.svn-base89
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-delete.el.svn-base176
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-insert.el.svn-base165
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-nop.el.svn-base59
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-operation.el.svn-base61
-rw-r--r--emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter.el.svn-base135
-rw-r--r--emacs.d/lisp/rudel/jupiter/Project.ede14
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter-compound.el89
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter-delete.el176
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter-insert.el165
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter-nop.el59
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter-operation.el61
-rw-r--r--emacs.d/lisp/rudel/jupiter/jupiter.el135
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/all-wcprops53
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/entries300
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/Project.ede.svn-base14
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-client.el.svn-base973
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-debug.el.svn-base122
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-errors.el.svn-base65
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-server.el.svn-base798
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-state.el.svn-base169
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-util.el.svn-base314
-rw-r--r--emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby.el.svn-base488
-rw-r--r--emacs.d/lisp/rudel/obby/Project.ede14
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-client.el973
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-debug.el122
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-errors.el65
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-server.el798
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-state.el169
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby-util.el314
-rw-r--r--emacs.d/lisp/rudel/obby/rudel-obby.el488
-rw-r--r--emacs.d/lisp/rudel/rudel-backend.el305
-rw-r--r--emacs.d/lisp/rudel/rudel-chat.el103
-rw-r--r--emacs.d/lisp/rudel/rudel-compat.el158
-rw-r--r--emacs.d/lisp/rudel/rudel-compile.el46
-rw-r--r--emacs.d/lisp/rudel/rudel-debug.el215
-rw-r--r--emacs.d/lisp/rudel/rudel-errors.el66
-rw-r--r--emacs.d/lisp/rudel/rudel-hooks.el252
-rw-r--r--emacs.d/lisp/rudel/rudel-icons.el90
-rw-r--r--emacs.d/lisp/rudel/rudel-interactive.el181
-rw-r--r--emacs.d/lisp/rudel/rudel-loaddefs.el23
-rw-r--r--emacs.d/lisp/rudel/rudel-mode.el621
-rw-r--r--emacs.d/lisp/rudel/rudel-operations.el133
-rw-r--r--emacs.d/lisp/rudel/rudel-operators.el172
-rw-r--r--emacs.d/lisp/rudel/rudel-overlay.el275
-rw-r--r--emacs.d/lisp/rudel/rudel-protocol.el83
-rw-r--r--emacs.d/lisp/rudel/rudel-session-initiation.el352
-rw-r--r--emacs.d/lisp/rudel/rudel-speedbar.el214
-rw-r--r--emacs.d/lisp/rudel/rudel-state-machine.el331
-rw-r--r--emacs.d/lisp/rudel/rudel-tls.el201
-rw-r--r--emacs.d/lisp/rudel/rudel-transport.el72
-rw-r--r--emacs.d/lisp/rudel/rudel-util.el261
-rw-r--r--emacs.d/lisp/rudel/rudel.el1012
-rw-r--r--emacs.d/lisp/rudel/telepathy/.svn/all-wcprops11
-rw-r--r--emacs.d/lisp/rudel/telepathy/.svn/entries62
-rw-r--r--emacs.d/lisp/rudel/telepathy/.svn/text-base/rudel-telepathy.el.svn-base76
-rw-r--r--emacs.d/lisp/rudel/telepathy/rudel-telepathy.el76
-rw-r--r--emacs.d/lisp/rudel/wave/.svn/all-wcprops17
-rw-r--r--emacs.d/lisp/rudel/wave/.svn/entries96
-rw-r--r--emacs.d/lisp/rudel/wave/.svn/text-base/Project.ede.svn-base14
-rw-r--r--emacs.d/lisp/rudel/wave/.svn/text-base/rudel-wave.el.svn-base77
-rw-r--r--emacs.d/lisp/rudel/wave/Project.ede14
-rw-r--r--emacs.d/lisp/rudel/wave/rudel-wave.el77
-rw-r--r--emacs.d/lisp/rudel/zeroconf/.svn/all-wcprops17
-rw-r--r--emacs.d/lisp/rudel/zeroconf/.svn/entries96
-rw-r--r--emacs.d/lisp/rudel/zeroconf/.svn/text-base/Project.ede.svn-base14
-rw-r--r--emacs.d/lisp/rudel/zeroconf/.svn/text-base/rudel-zeroconf.el.svn-base253
-rw-r--r--emacs.d/lisp/rudel/zeroconf/Project.ede14
-rw-r--r--emacs.d/lisp/rudel/zeroconf/rudel-zeroconf.el253
131 files changed, 42676 insertions, 0 deletions
diff --git a/emacs.d/lisp/rudel/.bzrignore b/emacs.d/lisp/rudel/.bzrignore
new file mode 100644
index 0000000..5f6312e
--- /dev/null
+++ b/emacs.d/lisp/rudel/.bzrignore
@@ -0,0 +1,2 @@
+*.elc
+Makefile
diff --git a/emacs.d/lisp/rudel/.svn/all-wcprops b/emacs.d/lisp/rudel/.svn/all-wcprops
new file mode 100644
index 0000000..5ad96b9
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/all-wcprops
@@ -0,0 +1,173 @@
+K 25
+svn:wc:ra_dav:version-url
+V 33
+/svnroot/rudel/!svn/ver/480/trunk
+END
+.bzrignore
+K 25
+svn:wc:ra_dav:version-url
+V 44
+/svnroot/rudel/!svn/ver/353/trunk/.bzrignore
+END
+rudel-icons.el
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/rudel/!svn/ver/271/trunk/rudel-icons.el
+END
+rudel-errors.el
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svnroot/rudel/!svn/ver/261/trunk/rudel-errors.el
+END
+rudel-interactive.el
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svnroot/rudel/!svn/ver/322/trunk/rudel-interactive.el
+END
+rudel-util.el
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svnroot/rudel/!svn/ver/306/trunk/rudel-util.el
+END
+rudel-operators.el
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/181/trunk/rudel-operators.el
+END
+rudel-chat.el
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svnroot/rudel/!svn/ver/333/trunk/rudel-chat.el
+END
+ChangeLog
+K 25
+svn:wc:ra_dav:version-url
+V 43
+/svnroot/rudel/!svn/ver/478/trunk/ChangeLog
+END
+rudel-overlay.el
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/465/trunk/rudel-overlay.el
+END
+rudel-loaddefs.el
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svnroot/rudel/!svn/ver/464/trunk/rudel-loaddefs.el
+END
+rudel-state-machine.el
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svnroot/rudel/!svn/ver/397/trunk/rudel-state-machine.el
+END
+rudel-hooks.el
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/rudel/!svn/ver/307/trunk/rudel-hooks.el
+END
+rudel-operations.el
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svnroot/rudel/!svn/ver/181/trunk/rudel-operations.el
+END
+rudel-compat.el
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svnroot/rudel/!svn/ver/468/trunk/rudel-compat.el
+END
+rudel-mode.el
+K 25
+svn:wc:ra_dav:version-url
+V 47
+/svnroot/rudel/!svn/ver/469/trunk/rudel-mode.el
+END
+README
+K 25
+svn:wc:ra_dav:version-url
+V 40
+/svnroot/rudel/!svn/ver/397/trunk/README
+END
+rudel-speedbar.el
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svnroot/rudel/!svn/ver/235/trunk/rudel-speedbar.el
+END
+rudel-debug.el
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/rudel/!svn/ver/331/trunk/rudel-debug.el
+END
+rudel-backend.el
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/330/trunk/rudel-backend.el
+END
+rudel-compile.el
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/347/trunk/rudel-compile.el
+END
+rudel-session-initiation.el
+K 25
+svn:wc:ra_dav:version-url
+V 61
+/svnroot/rudel/!svn/ver/354/trunk/rudel-session-initiation.el
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 45
+/svnroot/rudel/!svn/ver/471/trunk/Project.ede
+END
+rudel-transport.el
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/316/trunk/rudel-transport.el
+END
+TODO
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svnroot/rudel/!svn/ver/480/trunk/TODO
+END
+INSTALL
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svnroot/rudel/!svn/ver/397/trunk/INSTALL
+END
+rudel-protocol.el
+K 25
+svn:wc:ra_dav:version-url
+V 51
+/svnroot/rudel/!svn/ver/245/trunk/rudel-protocol.el
+END
+rudel-tls.el
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svnroot/rudel/!svn/ver/326/trunk/rudel-tls.el
+END
+rudel.el
+K 25
+svn:wc:ra_dav:version-url
+V 42
+/svnroot/rudel/!svn/ver/471/trunk/rudel.el
+END
diff --git a/emacs.d/lisp/rudel/.svn/dir-prop-base b/emacs.d/lisp/rudel/.svn/dir-prop-base
new file mode 100644
index 0000000..8f9583a
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/dir-prop-base
@@ -0,0 +1,5 @@
+K 13
+bzr:pointless
+V 1
+2
+END
diff --git a/emacs.d/lisp/rudel/.svn/entries b/emacs.d/lisp/rudel/.svn/entries
new file mode 100644
index 0000000..df63eca
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/entries
@@ -0,0 +1,1001 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-11-01T06:23:01.081193Z
+480
+scymtym
+has-props
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+zeroconf
+dir
+
+rudel-util.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+0cca36ebc59e3a59eb8209c4ad358c07
+2009-10-03T01:30:23.499430Z
+306
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7858
+
+rudel-interactive.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+b407a3920ab5c077cf0746220e0de31d
+2009-10-03T01:57:16.152033Z
+322
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6149
+
+rudel-overlay.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+a3ba9b413bfefcea2631dd27464acfb1
+2009-10-16T01:47:25.421704Z
+465
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9178
+
+obby
+dir
+
+rudel-operations.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+a3b2732504aee4fbddf77e8f5cb5d3f5
+2009-10-03T00:38:22.402651Z
+181
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3546
+
+rudel-hooks.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+fd6ed67d83a6678cac9fa25e414de1d8
+2009-10-03T01:30:48.800693Z
+307
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7540
+
+rudel-debug.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+8f020be45bb3787c27888ec5eda99c1f
+2009-10-03T01:59:11.181331Z
+331
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5778
+
+rudel-compile.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+e9fdc6a7e7a557cef318ff5b4406b8c1
+2009-10-03T02:04:48.037280Z
+347
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1286
+
+wave
+dir
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+c2d7e6f2f3310e6275555ae30c68556b
+2009-10-16T01:48:38.325631Z
+471
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1007
+
+doc
+dir
+
+INSTALL
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+6d6fa2de5c8eab6c413fefc4a584de6e
+2009-10-10T00:39:13.745463Z
+397
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1977
+
+rudel-protocol.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+30def601287f12146ec67c4f22dfedb2
+2009-10-03T00:56:18.517642Z
+245
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2474
+
+rudel-tls.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+aaacd0f1a0ee9432b08c0a6b7011be6d
+2009-10-03T01:57:56.380090Z
+326
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6653
+
+.bzrignore
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+8869a5d05314da0eef07cc732c683b4c
+2009-10-03T02:08:21.840187Z
+353
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15
+
+jupiter
+dir
+
+rudel-icons.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+69c1f83b9fb9daeed59f82029c6bb2f5
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2216
+
+rudel-errors.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+b08feb690df0dad3641e67ab887edec0
+2009-10-03T01:07:06.053827Z
+261
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1555
+
+rudel-operators.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+d14817f262478370aa6407859a793f38
+2009-10-03T00:38:22.402651Z
+181
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+5620
+
+ChangeLog
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+f373fa66be88d4b25681887e2d21c4f5
+2009-11-01T06:22:31.276953Z
+478
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+99450
+
+rudel-chat.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+b95fa6378d432f42de7f422be624e3f8
+2009-10-03T01:59:22.171161Z
+333
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2726
+
+rudel-loaddefs.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+7f4b7008a58c307af7dc94f7a57ce509
+2009-10-16T01:47:11.584789Z
+464
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+836
+
+rudel-state-machine.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+29237a64e50d3fe8585483cd3639c75d
+2009-10-10T00:39:13.745463Z
+397
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10305
+
+rudel-compat.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+63bc6b3180525b022f9ddb9ea13ec7dc
+2009-10-16T01:48:03.160288Z
+468
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+6110
+
+rudel-mode.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+dc7a115e60aeddc080cb2e680f2824ca
+2009-10-16T01:48:14.377417Z
+469
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+20825
+
+rudel-speedbar.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+c899ca06cea2a20f3e760ae3a2f622b3
+2009-10-03T00:51:24.682586Z
+235
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7471
+
+README
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+d2ec3a641007417c8ee8bca69ab5f858
+2009-10-10T00:39:13.745463Z
+397
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3235
+
+rudel-backend.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+2ca1c3acc2d0ae469d1b014be4b0674e
+2009-10-03T01:58:59.186010Z
+330
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9610
+
+telepathy
+dir
+
+rudel-session-initiation.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+681ca33c2c1c328b551a9027ac4aab69
+2009-10-03T02:08:38.551425Z
+354
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+10953
+
+rudel-transport.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+e22f3b1d0e1e1d73ddf96e5e4c47b5a1
+2009-10-03T01:55:52.956859Z
+316
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1894
+
+TODO
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+6579915878eaff18f620e6cd0174c9df
+2009-11-01T06:23:01.081193Z
+480
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+12907
+
+rudel.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+e043c1ef7127a53a4a1292dafde28e4e
+2009-10-16T01:48:38.325631Z
+471
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+30406
+
+icons
+dir
+
diff --git a/emacs.d/lisp/rudel/.svn/text-base/.bzrignore.svn-base b/emacs.d/lisp/rudel/.svn/text-base/.bzrignore.svn-base
new file mode 100644
index 0000000..5f6312e
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/.bzrignore.svn-base
@@ -0,0 +1,2 @@
+*.elc
+Makefile
diff --git a/emacs.d/lisp/rudel/.svn/text-base/ChangeLog.svn-base b/emacs.d/lisp/rudel/.svn/text-base/ChangeLog.svn-base
new file mode 100644
index 0000000..03c4fab
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/ChangeLog.svn-base
@@ -0,0 +1,2403 @@
+2009-10-22 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * TODO (Future): added BEEP and SubEthaEdit tasks
+
+2009-10-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-version): bumped to 0.3
+ * Project.ede (project rudel): bumped version to 0.3
+
+ * TODO: whitespace fixes
+ (Milestone rudel-0.4): new; focus on telepathy transport
+ (Milestone rudel-0.3): added infinote, document trees
+
+2009-10-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * TODO: new file; TODO items for future development and releases
+
+2009-10-12 Phil Hagelberg <phil@enigma>
+
+ * rudel-mode.el
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line):
+ Replace reference to mode-line indicator that was not present in
+ Emacs 22.
+
+ * rudel-compat.el: add rudel-get-coding-system wrapper function.
+ * rudel-obby-util.el (with-parsed-args): Replace call to
+ Emacs23-specific coding-system-from-name function with
+ rudel-get-coding-system.
+
+ rudel-compat.el: Add string-match-p if not present. (< Emacs 23)
+
+ * rudel-mode.el, rudel-overlay.el: Move use of :safe flag from
+ defcustom to a separate put. Required for Emacs 22 compatibility.
+
+ * rudel-loaddefs.el: Only require rudel-zeroconf if zeroconf is
+ available.
+
+2009-10-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ fixed error message
+
+2009-10-08 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter.el (header): downcased keywords
+ (object-print): new method; add revisions and log length to string
+ * jupiter/jupiter-nop.el (header): downcased keywords; cosmetic
+ representation changes to "commentary" section
+ * jupiter/jupiter-insert.el (header): downcased keywords; cosmetic
+ changes to "commentary" section
+ (object-print): new method; add start, end, length and data to
+ string representation
+ * jupiter/jupiter-delete.el (header): downcased keywords; cosmetic
+ changes to "commentary" section
+ (jupiter-transform): cosmetic changes
+ (object-print): new method; add position and length to string
+ representation
+ * jupiter/jupiter-compound.el (header): downcased keywords;
+ cosmetic changes to "commentary" section
+ (object-print): new method; add number of children to string
+ representation
+
+2009-10-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * doc/card.tex (Session Initiation): mention configured sessions;
+ explain Zeroconf-advertised session in more detail
+
+2009-10-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * doc/card.tex (Joining a Session ...): added global and user
+ passwords
+
+ * rudel.el (rudel-version): use list representation instead of
+ float
+ (rudel-allocate-buffer-function): added documentation string
+
+ * INSTALL (COMPILING): fixed typo
+
+2009-10-06 Phil Hagelberg <phil@enigma>
+
+ * README (JOINING): Mention `rudel-configured-sessions'
+ customization.
+
+ * README (INTRODUCTION): emphasize obby backend being the only
+ supported one so far
+ (JOINING): update example session with passwords.
+
+ * rudel-loaddefs.el: Add autoloads for rudel-host-session and
+ rudel-speedbar
+
+2009-10-05 Phil Hagelberg <phil@enigma>
+
+ * README: Mention Eshell issue and license.
+
+2009-10-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el (make-pulsing-progress-reporter): removed;
+ `make-progress-reporter' is sufficient
+ (progress-reporter-pulse): store index in the car of the reporter;
+ set last update time of the reporter
+ * obby/rudel-obby.el (rudel-connect): use `make-progress-reporter'
+ instead of `make-pulsing-progress-reporter'
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-subscribe-to): cosmetic changes in
+ status messages
+
+ * ChangeLog: updated
+
+2009-10-02 Phil Hagelberg <phil@enigma>
+
+ * INSTALL: Mention CEDET's inclusion in Emacs
+
+ * rudel-state-machine.el (rudel-state-wait): update progress
+ reporter usage to match rudel-compat.el
+
+ * rudel-compat.el: Use updated progress reporters
+ (progress-reporter-update): may be used by pulsing reporters too
+ (make-progress-reporter): nil max value returns pulsing reporter
+ (progress-reporter-force-update): may be used by pulsing reporters
+ too
+ (progress-reporter-pulsing-p): added
+ (progress-reporter-pulse): removed message change option
+
+2009-10-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (rudel-state-wait): accept callback
+ function instead of message; adjusted documentation string
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): when
+ calling `rudel-state-wait', provide a callback; the callback
+ controls a progress reporter
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-subscribe-to): when calling
+ `rudel-state-wait', provide a callback; the callback controls a
+ progress reporter
+
+ * rudel-compat.el (progress-reporter-pulse): store index as float
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_create):
+ cosmetic changes of printed messages
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ cosmetic changes of printed messages
+
+ * rudel.el (rudel-session::rudel-remove-document): when necessary,
+ detach document first; added documentation string
+ (rudel-document::rudel-attached-p): new method; return non-nil
+ when document is attached to a buffer
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part):
+ promoted warning severity to :warning
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ fixed lookup of document; added warning message in case it is not
+ found
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/rename):
+ promoted warning severity to :warning
+ (rudel-obby-connection::rudel-unpublish): new method; ask server
+ to remove a document
+
+2009-10-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (rudel-state-wait): fixed progress range
+ [0, 100] -> [0, 1]; fixed reference to reporter object
+ * obby/rudel-obby.el (rudel-obby-send): removed remnants of calls
+ to `working-*' functions; call `progress-reporter-pulse' just
+ before `progress-reporter-done'
+
+2009-09-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el: only define pulsing progress reporter when
+ Emacs does not have one itself
+ (header): downcased keywords
+ (make-pulsing-progress-reporter): renamed
+ `make-progress-reporter-pulse' ->
+ `make-pulsing-progress-reporter'; cosmetic changes; explanatory
+ comment
+ (progress-reporter-pulse): added documentation string
+ Suggested by Phil Hagelberg
+
+ * rudel-compat.el (progress-pulse-values): new variable; indicator
+ strings used by pulsing progress reporter
+ (make-progress-reporter-pulse): new function; creates pulsing
+ progress reporter
+ (progress-reporter-pulse): new function; updates pulsing progress
+ reporter
+ Suggested by Phil Hagelberg
+
+2009-09-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-server-state-before-join::rudel-obby/net6_client_login):
+ accept two additional arguments: global-password and user-password
+
+ * rudel-session-initiation.el (rudel-configured-sessions):
+ improved documentation string
+
+2009-09-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): wording
+ (INSTALLING): mention other things that cause rudel to be
+ autoloaded; minor cosmetic changes
+ (COMPILING): fixed filename compile.el -> rudel-compile.el
+
+ * rudel-compile.el (header): added copyright and meta data
+ (code): let-bind rudel-dir; call `byte-recompile-directory' just
+ once since it operates recursively
+
+2009-09-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el (header): better documentation
+ (require rudel-state-machine): now required for state machine
+ style handling of client connections
+ (require rudel-obby-state): now required; provides base class for
+ states
+ (rudel-obby-server-state-new): new class; client connection state
+ new
+ (rudel-obby-server-state-encryption-negotiate): new class; client connection state
+ for negotiating encryption
+ (rudel-obby-server-state-before-join): new class; client connection state
+ for waiting for login request
+ (rudel-obby-server-state-new): new class; client connection state
+ entered after session setup and joining is complete
+ (rudel-obby-server-connection-states): new variable; list of
+ states and their symbolic names
+ (rudel-obby-client): now derived from rudel-state-machine
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info):
+ check for :global-password and :user-password correctly; do not
+ put them into the list when they are ""
+ (rudel-obby-backend::rudel-connect): comment
+
+ * rudel-session-initiation.el
+ (rudel-configured-sessions-backend::rudel-discover): let
+ `rudel-session-initiation-adjust-info' do the heavy lifting
+ (rudel-session-initiation-adjust-info): new function; adjust
+ arguments that need adjusting in a session information property
+ list
+
+ * rudel-session-initiation.el (rudel-configured-sessions): more
+ precise specification of the customization type
+
+2009-09-27 Phil Hagelberg <technomancy@gmail.com>
+
+ * compile.el: renamed compile.el -> rudel-compile.el
+
+ * INSTALL: Mention new install process using compile.el and
+ rudel-loaddefs.el.
+
+ * rudel-loaddefs.el: Autoload rudel as one unit instead of
+ piece-by-piece. Remove eieio dependency from autoloads.
+
+ * compile.el: Perform compilation from Elisp
+
+ * Makefile: Remove error-prone CEDET-autogenerated build scripts.
+
+2009-09-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-session-initiation.el
+ (rudel-configured-sessions-backend::rudel-discover): fixed a bug
+ that dropped the last option in each configured session
+
+ * rudel-session-initiation.el (rudel-configured-sessions): new
+ customization option; contains a list of session information lists
+ (rudel-ask-protocol-backend::initialize-instance): maybe call next
+ method
+ (rudel-configured-sessions-version): new constant; version of the
+ configured-sessions backend
+ (rudel-configured-sessions-backend): new class;
+ configured-sessions backend
+ (rudel-configured-sessions-backend::initialize-instance): new
+ method; set version slot
+ (rudel-configured-sessions-backend::rudel-discover): new method;
+ "discover" configured sessions
+ (autoload rudel-add-backend): register
+ rudel-configured-sessions-backend as a protocol backend
+
+ * rudel-chat.el (rudel-chat-buffer-name): new constant; name chat
+ log buffer
+ (rudel-chat-handle-buffer): raise buffer when logging a chat
+ message
+
+ * rudel-debug.el (header): fixed meta-data and license
+ (rudel-debug-sent-data-face): added documentation string
+ (rudel-debug-received-data-face): added documentation string
+ (rudel-debug-received-processed-data-face): added documentation
+ string
+ (rudel-debug-state-face): added documentation string
+ (rudel-debug-special-face): added documentation string
+ (rudel-suspend-session-socket): added documentation string
+ (rudel-resume-session-socket): added documentation string
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): use
+ `display-warning' instead of `warn'
+ * obby/rudel-obby-state.el (rudel-obby-state::rudel-accept): use
+ `display-warning' instead of `warn'
+ (rudel-obby-document-handler::rudel-obby/obby_document): use
+ `display-warning' instead of `warn'
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part): use
+ `display-warning' instead of `warn'
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/record):
+ use `display-warning' instead of `warn'
+ * rudel-backend.el (rudel-backend-factory::rudel-load-backends):
+ use `display-warning' instead of `warn'
+
+ * obby/rudel-obby-client.el (require rudel-chat): used when
+ handling chat messages
+ (rudel-obby-client-state-idle::rudel-obby/obby_message): new
+ method; handles obby 'message' messages by dispatching to
+ `rudel-chat-dispatch-message'
+ * rudel-chat.el (whole file): new file; handling of incoming chat
+ messages
+ * Project.ede (target rudel): added rudel-chat.el
+ * Makefile (target rudel_LISP): added rudel-chat.el
+
+2009-09-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-state.el (rudel-obby-server-connection-state):
+ new class; base class for server connection states
+ (rudel-obby-server-connection-state::rudel-broadcast): new method;
+ broadcast message to a set of receivers
+
+2009-09-25 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): new
+ error state they-finalized; handle join-failed error specially
+ * obby/rudel-obby-client.el (rudel-obby-client-state-join-failed):
+ improved comments
+ (rudel-obby-client-state-they-finalized): new state class; used to
+ indicate that the connection was closed by the peer
+ (rudel-obby-client-connection-states): added they-finalized
+ (rudel-obby-connection::rudel-close): switch state machine to
+ they-finalized
+ (rudel-obby-connection::rudel-subscribe-to): new error state
+ they-finalized
+
+ * rudel.el (rudel-client-session::connection): allow nil value
+ (rudel-client-session::rudel-end): only try to disconnect the
+ connection if it is non-nil; ignore errors during disconnect
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-encryption-start::rudel-obby/net6_encryption_begin):
+ do not require rudel-tls; do not try to start TLS encryption if
+ the connection does not support it
+ * rudel-tls.el (rudel-tls-make-process): mark process as
+ supporting TLS encryption
+
+ * obby/rudel-obby-state.el (rudel-obby/net6_ping): return nil to
+ prevent erratic behavior of the state machine
+
+ * rudel-interactive.el (rudel-allocate-buffer-clear-existing):
+ added missing whitespace in prompt string
+
+2009-09-24 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-tls.el (rudel-tls-start-tls): changed displayed message
+ (rudel-tls-wait-init): ignore all lines until "- Simple Client
+ Mode.*" is received; then switch back old filter
+ (rudel-tls-wait-handshake): ignore all lines until "-
+ Compression.*" is received; then switch to established filter
+ (rudel-tls-established): do not ignore any lines other than
+ "- Peer has closed the GNUTLS connection"
+
+ * obby/rudel-obby.el (rudel-ask-connect-info): ask for global and
+ user passwords
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-enter): transmit global
+ and user passwords when available
+
+ * obby/rudel-obby-errors.el
+ (rudel-obby-error-wrong-global-password): fixed error code
+ (rudel-obby-error-wrong-user-password): fixed error code
+ (rudel-obby-error-protocol-version-mismatch): fixed error code
+ (rudel-obby-error-not-encrypted): fixed error code
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-obby/net6_login_failed):
+ recognize wrong global/user password error codes
+
+ * obby/rudel-obby-debug.el (whole file): new file; debugging
+ functions for the obby backend
+ * rudel-debug.el (whole file): new file; debugging functions
+
+ * obby/rudel-obby-errors.el
+ (rudel-obby-error-wrong-global-password): new constant; error code
+ for wrong global password
+ (rudel-obby-error-wrong-user-password): new constant; error code
+ for wrong user password
+ (rudel-obby-error-protocol-version-mismatch): new constant; error
+ code for protocol version mismatch
+ (rudel-obby-error-not-encrypted): new constant; error code for not
+ encrypted
+
+ * Project.ede (target rudel): added rudel-transport.el
+ * Makefile (target rudel_LISP): added rudel-transport.el
+ * rudel-transport.el (whole file): new file; interface for
+ transport backends
+
+2009-09-20 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-remote-operation): added byte -> char
+ conversion before the operation is applied to the server-side
+ document; updated comments
+
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-broadcast):
+ cosmetic changes
+ (rudel-obby-client::rudel-obby/net6_client_login): cosmetic
+ changes; improved comments
+ (rudel-obby-client::rudel-obby/obby_document): changed
+ documentation string; cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/record): added a
+ comment
+ (rudel-obby-client::rudel-remote-operation): improved comments
+
+ * obby/rudel-obby-server.el (header): added header comment
+ (rudel-obby-client::rudel-obby/obby_document_create): changed
+ documentation comment
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): changed
+ documentation comment; cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe):
+ cosmetic changes
+ (rudel-obby-server::initialize-instance): do not run :after; call
+ next method
+ (rudel-obby-server::rudel-broadcast): signal wrong-type-argument
+ instead of just error; cosmetic changes
+ (rudel-obby-server::rudel-check-username-and-color): changed
+ comments
+ (rudel-obby-server::object-print): new method; generate string
+ representation with number of clients
+
+2009-09-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ construct the operation and use `rudel-remote-operation'
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ construct the operation and use `rudel-remote-operation'
+ (rudel-obby-client::rudel-remote-operation): new method; transform
+ and apply an operation object to the server-side document; send
+ operation to all other clients
+ (rudel-obby-server::rudel-broadcast): cosmetic changes
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/del): swapped
+ local and remote revisions in the operation name to be consistent
+ with record/ins; does not affect behavior
+
+2009-09-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions--update-from-document):
+ force mode line update
+ (rudel-header-subscriptions--update-from-buffer): force mode line
+ update
+ (rudel-header-subscriptions-minor-mode): force mode line update
+
+ * rudel-mode.el
+ (rudel-mode-line-publish-state-unpublished-string): new
+ customization option; string used to indicate that a buffer is not
+ published
+ (rudel-mode-line-publish-state-published-string): new
+ customization option; string used to indicate that a buffer is
+ published
+ (rudel-mode-line-publish-state--update-string): use
+ `rudel-mode-line-publish-state-unpublished-string' and
+ `rudel-mode-line-publish-state-unpublished-string'
+
+ * rudel.el (rudel-session::end-hook): new slot; stores handlers of
+ the end hook
+ (rudel-session::rudel-end): run end hook
+ (rudel-session::rudel-join-session): install handler on session
+ end hook to set `rudel-current-session' to nil
+ (rudel-session::rudel-end-session): no need to run
+ rudel-session-end-hook or reset `rudel-current-session'
+ * rudel-hooks.el (rudel-hooks--session-start): add handler for the
+ end hook of the session
+ (rudel-hooks--session-end): remove the handler from end hook of
+ the session; run the rudel-session-end hook
+ (rudel-hooks--install-handlers): do install handler for
+ rudel-session-end hook; this is now done by installing the in the
+ session object
+ (rudel-hooks--uninstall-handlers): no need to remove
+ rudel-session-end hook
+
+ * rudel-util.el (rudel-socket-owner::rudel-state-change): cover
+ more states
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ implemented, was stub; untested though
+
+2009-09-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_join): check
+ whether we have a user object for the specified user id; modify
+ the existing object if there is one
+
+2009-09-09 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * zeroconf/Makefile (whole file): regenerated
+ * wave/Makefile (whole file): regenerated
+ * Makefile (target all): build target doc
+ (target doc): new target; build documentation
+ (target tags): build target tags in doc directory
+ (target dist): build target dist in doc directory
+
+2009-09-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * telepathy/rudel-telepathy.el (header): fixes
+ (require rudel-backend): required, since we define a backend
+ (require rudel-transport): it is a transport backend
+ (class rudel-telepathy-backend): derived from
+ rudel-transport-backend
+ (rudel-telepathy-backend::initialize-instance): new method; set
+ version slot
+ (autoloading): upgraded to new backend registration style
+
+ * INSTALL (REQUIREMENTS): mention Avahi
+
+2009-09-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (require rudel-util): required for `rudel-hook-object'
+
+ * rudel-util.el (property svn:executable): removed property
+ * rudel-overlay.el (property svn:executable): removed property
+
+ * doc/Project.ede (whole file): new file; project file for the
+ documentation directory
+ * doc/Makefile (whole file): new file; generated Makefile for the
+ documentation directory
+ * doc/card.tex (whole file): new file; reference card for Rudel;
+ source
+ * doc/card.pdf (whole file): new file; reference card for Rudel;
+ PDF
+
+2009-09-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-document): added comment
+ (rudel-allocate-buffer-clear-existing): handle the case in which
+ case a buffer with the desired name exists and is attached to a
+ different document; added some comments
+
+ * rudel-mode.el (header): list all provided modes; bump version
+ (require rudel-hooks): required for global hooks
+ (rudel-mode-line-publish-state-string): new variable; buffer
+ local, holds publish state string for buffer
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line): new
+ function; add publish state indicator to mode line
+ (rudel-mode-line-publish-state--remove-indicator-from-mode-line):
+ new function; remove publish state indicator from mode line
+ (rudel-mode-line-publish-state--update-string): new function;
+ update publish state indicator according to buffer state
+ (rudel-mode-line-publish-state--document-attach): new function;
+ handle document attaching to buffer
+ (rudel-mode-line-publish-state--document-detach): new function;
+ handle document detaching from buffer
+ (rudel-mode-line-publish-state-minor-mode): new minor mode;
+ displays publish state of buffer in mode line
+ (global-rudel-mode-line-publish-state-mode): new minor mode;
+ globalization of `rudel-mode-line-publish-state-minor-mode'
+ (rudel-minor-keymap): menu entries for buffer local and global
+ mode line publish state mode
+
+ * rudel.el (require rudel-hooks): required or hook variables
+ (rudel-session-start-hook): moved to rudel-hooks.el
+ (rudel-session-end-hook): moved to rudel-hooks.el
+ * rudel-hooks.el (whole file): new file; contains hook variables
+ and mapping from object hooks to global hooks
+ * Project.ede (target rudel): added file rudel-hooks.el
+ * Makefile (target rudel_LISP): added file rudel-hooks.el
+
+2009-09-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions-minor-mode): improved
+ documentation string
+
+2009-08-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * zeroconf/Makefile (whole file): new file; generated Makefile for
+ the zeroconf subproject
+
+ * wave/rudel-wave.el (whole file): new file; main class of the
+ wave backend
+ * wave/Project.ede (whole file): new file; project file for the
+ wave subproject
+ * wave/Makefile (whole file): new file; generated Makefile for the
+ wave subproject
+ * Project.ede (target autoloads): added wave directory
+ * Makefile (LOADDIRS): added wave and zeroconf directories
+ (VERSION): bumped to 0.2
+ (target all): added wave and zeroconf
+ (tags): descend into zeroconf and wave directories
+ (dist): descend into zeroconf and wave directories
+
+2009-08-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-change-color): run the change hook of the self
+ user
+
+ * rudel-overlay.el (rudel-overlay-set-face-attributes): check the
+ face actually exists
+
+2009-08-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions-use-images): new
+ variable; controls whether images are used when formatting user
+ names
+ (rudel-header-subscriptions-separator): new variable; separator
+ used when formatting user names
+ (rudel-header-subscriptions--make-format): new function; make a
+ format object for header line
+ (rudel-header-subscriptions--update-from-document): new function;
+ update header line from document
+ (rudel-header-subscriptions--update-from-buffer): new function;
+ update header line from buffer
+ (rudel-header-subscriptions--options-changed): new function;
+ update header line in all buffers that have
+ rudel-header-subscriptions-minor-mode enabled after customization
+ option change
+ (rudel-header-subscriptions--user-change): new function; update
+ header line after a user object change
+ (rudel-header-subscriptions--add-user): new function; watch newly
+ subscribed user and update header line
+ (rudel-header-subscriptions--remove-user): new function; stop
+ watching user and update header line
+ (minor mode rudel-header-subscriptions-minor-mode): new minor
+ mode; display subscribed users in buffer's header line
+ (rudel-header-subscriptions--attach): new function; enable header
+ subscription minor mode when attaching
+ (rudel-header-subscriptions--detach): new function; disable header
+ subscription minor mode when detaching
+ (rudel-header-subscriptions--add-document): new function; monitor
+ attaching/detaching of new document
+ (rudel-header-subscriptions--remove-document): new function; stop
+ monitoring attaching/detaching of new document
+ (rudel-header-subscriptions--session-start): new function; watch
+ documents being added/removed to/from the session
+ (rudel-header-subscriptions--session-end): new function; stop
+ watching documents being added/removed to/from the session
+ (minor mode global-rudel-header-subscriptions-mode): global minor
+ mode that controls `rudel-header-subscriptions-minor-mode' in
+ buffers
+ (advice global-rudel-header-subscriptions-mode): controls
+ adding/removing watches for added/removed documents when the
+ global mode is enabled/disabled
+ (rudel-minor-keymap): Added entries for
+ `rudel-header-subscriptions-minor-mode' and
+ `global-rudel-header-subscriptions-mode'
+
+2009-08-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * . (property svn:ignore): added patterns
+ * jupiter (property svn:ignore): added patterns
+ * obby (property svn:ignore): added patterns
+
+ * rudel.el (rudel-session::add-user-hook): new slot; add user hook
+ function list
+ (rudel-session::remove-user-hook): new slot; remove user hook
+ function list
+ (rudel-session::add-document-hook): updated documentation string
+ (rudel-session::remove-document-hook): updated documentation
+ string
+ (rudel-session::rudel-add-user): run add user hook
+ (rudel-session::rudel-remove-user): run remove user hook
+
+ * rudel.el (rudel-session-start-hook): new variable; session start
+ hook function list
+ (rudel-session-end-hook): new variable; session end hook function
+ list
+ (rudel-join-session): run session start hook
+ (rudel-end-session): run session end hook
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document_create): call
+ `generate-new-buffer-name' on complete buffer name; not just name
+ part
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): send
+ number of bytes instead of number of characters
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-document-synching::remaining-bytes):
+ fixed initarg num-bytes -> remaining-bytes
+
+ * rudel.el (rudel-session::add-document-hook): new slot; run when
+ a document gets added to the session
+ (rudel-session::remove-document-hook): new slot; run when a
+ document gets removed from the session
+ (rudel-session::rudel-add-document): run add document hook
+ (rudel-session::rudel-remove-document): run remove document hook
+ (rudel-document::unsubscribe-hook): fixed initarg subscribe-hook
+ -> unsubscribe-hook
+
+2009-08-25 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * www/index.html (Download): link to http://bazaar-vcs.org;
+ improved wording
+
+ * www/index.html (Download): changed link to source; add browse
+ source link for bzr
+
+ * INSTALL (REQUIREMENTS): precise CEDET release version
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_user_colour): run change hook
+ after setting slot
+ (rudel-obby-server::rudel-remove-client): run change hook after
+ setting slot
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part): run
+ change hook after setting slots
+ (rudel-obby-client-state-idle::rudel-obby/obby_user_colour): run
+ change hook after setting slot
+ * rudel.el (class rudel-user): derive from `rudel-hook-object'
+ (rudel-user::change-hook): new slot; stores change hook functions
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_user_colour): cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): use
+ `rudel-add-user'
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): use
+ `rudel-remove-user'
+ (rudel-obby-server::rudel-check-username-and-color): whitespace
+ fixes
+
+2009-08-23 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::attach-hook): new slot; attach hook
+ function list
+ (rudel-document::detach-hook): new slot; detach hook function list
+ (rudel-document::rudel-attach-to-buffer): run hook `attach-hook'
+ (rudel-document::rudel-detach-from-buffer): run hook `detach-hook'
+ (rudel-document::rudel-add-user): improved documentation string
+ (rudel-document::rudel-remove-user): improved documentation string
+
+ * obby/rudel-obby.el
+ (rudel-obby-user::eieio-speedbar-object-buttonname): fixed typo
+
+2009-08-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/subscribe):
+ call `rudel-add-user'
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/unsubscribe):
+ call `rudel-remove-user'
+ * rudel.el (class rudel-document): mixin rudel-hook-object
+ (rudel-document::subscribe-hook): new slot; subscribe-hook
+ function list
+ (rudel-document::unsubscribe-hook): new slot; unsubscribe-hook
+ function list
+ (rudel-document::rudel-add-user): new method; add user to list of
+ subscribed users and run subscribe-hook
+ (rudel-document::rudel-remove-user): new method; remove user from
+ list of subscribed users and run unsubscribe-hook
+
+ * obby/rudel-obby.el (header): cosmetic changes
+ (include rudel-icons): `rudel-display-string' uses icons
+ (rudel-obby-user::eieio-speedbar-object-buttonname): use
+ `rudel-display-string'
+ (rudel-obby-user::rudel-display-string): new method; textual
+ representation of user object
+ (rudel-obby-parse-message): cosmetic changes
+ * rudel.el (include rudel-icons): `rudel-display-string' uses
+ icons
+ (rudel-user::rudel-display-string): new method; textual
+ representation of user object
+
+ * rudel-util.el (rudel-hook-object): new class; abstract mixin for
+ classes that offer hooks
+ (rudel-hook-object::object-add-hook): new method; add function to
+ hook list
+ (rudel-hook-object::object-remove-hook): new method; remove
+ function from hook list
+ (rudel-hook-object::object-run-hook-with-args): new method; run
+ hook functions
+
+2009-08-20 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * icons/plaintext.svg (new file): plaintext icon
+ * icons/person.svg (new file): person icon
+ * icons/encrypted.svg (new file): encrypted icon
+ * icons/document.svg (new file): document icon
+ * icons/disconnected.svg (new file): disconnected icon
+ * icons/connected.svg (new file): connected icon
+ * rudel-icons.el (new file): loading icons
+ * Project.ede (target rudel): added rudel-icons.el
+
+2009-08-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-join-session): renamed local variable backend to
+ session-initiation-backend
+
+2009-08-17 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-state.el (rudel-obby-state::rudel-accept): fixed
+ format of warning message
+
+ * rudel-state-machine.el (require working): needed by
+ `rudel-state-wait'
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_user_colour): set
+ face attributes
+ * rudel.el (rudel-change-color): set face attributes
+ * rudel-overlay.el (rudel-overlay-make-face): use
+ `rudel-overlay-set-face-attributes'
+ (rudel-overlay-set-face-attributes): new function; set face
+ attributes
+
+ * rudel-overlay.el (rudel-overlay-author-set-properties): call
+ `rudel-overlay-make-face-symbol'
+ (rudel-overlay-make-face-symbol): new function; return face symbol
+
+2009-08-16 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-overlay.el (rudel-overlay-author-display): option that
+ controls display of author overlays
+ (rudel-make-author-overlay): call
+ `rudel-overlay-author-set-properties' to set the overlay
+ properties
+ (rudel-overlay-author-set-properties): new function; set overlay
+ properties; respects rudel-overlay-author-display
+ (rudel-overlay-author-update): new function; update overlay
+ properties based on associated user object
+ (rudel-overlay-options-changed): new function; call
+ `rudel-overlay-author-update' on all Rudel overlays in all buffers
+ * rudel-mode.el (header): cosmetic changes
+ (rudel-minor-menu): added menu entry to toggle display of author
+ overlays
+
+ * rudel-overlay.el (rudel-make-author-overlay): use `intern'
+ instead of `make-symbol' when allocating the face name; this way,
+ faces can actually be created lazily
+ (rudel-overlay-make-face): call `make-face' for the new face
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-document-synching::object-print): fixed
+ slot name remaining-bytes
+
+ * rudel.el (rudel-host-session): the backend object is the cdr of
+ the result of `rudel-backend-choose'
+
+2009-08-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * telepathy/rudel-telepathy.el (header): added file comment
+ * obby/rudel-obby-state.el (header): fixed email address
+ (whole file): whitespace fixes
+ * jupiter/jupiter.el (header): cosmetic changes
+ (whole file): whitespace fixes
+ * rudel-util.el (header): cosmetic changes
+ * rudel-mode.el (header): cosmetic changes
+ * rudel-errors.el (header): fixed type
+ (whole file): whitespace fixes
+
+ * obby/rudel-obby.el (rudel-ask-connect-info): added optional
+ argument info; do not ask for things that are already specified in
+ info
+ (autoload): register obby service with the Zeroconf backend
+ * zeroconf/rudel-zeroconf.el (new file): Zeroconf session
+ initiation for Rudel
+ * zeroconf/Project.ede (new file): subproject zeroconf
+ * rudel.el (rudel-join-session): call `rudel-ask-info' to augment
+ connect info
+ * Project.ede (target autoloads): added directory zeroconf
+ * INSTALL (INSTALLING): mention zeroconf subdirectory
+ (COMPILING): mention zeroconf target
+
+ * rudel-backend.el (rudel-backend-factory::rudel-get-backend):
+ return backend as a cons
+ (rudel-backend-get): new function; convenience function for
+ getting backends
+
+ * obby/rudel-obby.el (header): extended commentary and history
+ (rudel-obby-version): bumped to 0.2
+ (rudel-obby-backend::initialize-instance): set :version slot in
+ constructor instead of using obsolete lambda expression in
+ initform
+
+2009-08-14 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * Project.ede (project rudel): bumped version to 0.2; added
+ mailing list and path to web files
+
+ * rudel-backend.el (rudel-backend-factory): do not initialize
+ backends with lambda expression
+ (rudel-backend-factory::initialize-instance): new method;
+ initialize backends
+ (rudel-backend-cons-p): use `object-p' instead of `eieio-object-p'
+ (rudel-backend-dump): changed format slightly
+
+2009-08-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (include rudel-session-initiation): required for
+ `rudel-join-session'
+ (rudel-join-session): mostly rewritten; moved user interaction to
+ `interactive' form
+ * rudel-session-initiation.el (new file): session initiation
+ backend interface and high-level programming interface
+ * Project.ede (target rudel): added rudel-session-initiation.el
+ * Makefile (rudel_LISP): added rudel-session-initiation.el
+
+ * rudel-interactive.el (rudel-read-session): discriminate sessions
+ vs. session generating objects using `rudel-backend-cons-p'
+
+ * rudel-backend.el (rudel-backend-cons-p): new function; checks
+ whether a cons consists of a backend name and object
+
+2009-08-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-session): new function; read
+ session by name and return it
+
+ * rudel-interactive.el (rudel-read-backend): argument backends is
+ no longer optional; always return a cons of backend name and
+ object; updated documentation string
+ (whole file): whitespace fixes
+ * rudel-backend.el (rudel-backend-choose): always return a cons of
+ backend name and object; updated documentation string
+
+2009-08-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (file header): added project URL
+ (whole file): improved some comments
+
+2009-08-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (include eieio-base): needed for eieio-named
+
+2009-08-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (header section commentary): updated
+ (rudel-state-machine::initialize-instance): use
+ `rudel--switch-to-return-value' to allow immediate switch to
+ another state
+ (rudel-state-machine::rudel-switch): use
+ `rudel--switch-to-return-value' to switch to successor state
+ (rudel-state-machine::rudel--switch-to-return-value): new function
+ switch to successor state for different kinds of specifications of
+ the successor state
+
+2009-08-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (require rudel-backend): now necessary
+ (require rudel-protocol): now necessary
+ (class rudel-obby-backend): now derived from `rudel-backend';
+ autoloaded
+ (autoloading): use `rudel-add-backend'
+ * rudel.el (require rudel-backend): backends have their own file
+ (class rudel-backend): moved to rudel-backend.el
+ (rudel-load-backends): moved to rudel-backend.el
+ (rudel-suitable-backends): moved to rudel-backend.el
+ (rudel-choose-backend): moved to rudel-backend.el
+ (rudel-join-session): use `rudel-backend-choose'
+ (rudel-host-session): use `rudel-backend-choose'
+
+ * rudel-protocol.el (new file): interface for Rudel protocol
+ backends
+ * Project.ede (target rudel): added rudel-protocol.el
+ * Makefile (rudel_LISP): added rudel-protocol.el
+
+ * rudel-backend.el (rudel-backend-factory::rudel-get-backend):
+ improved documentation string
+ (rudel-backend-factory::rudel-suitable-backends): improved
+ documentation string
+ (rudel-backend-suitable-backends): improved documentation string
+ (rudel-backend-choose): When only one backend matches, do not
+ check interactivity using `interactive-p', that does not work;
+ call `sit-for' correctly
+
+2009-08-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/Makefile (whole file): regenerated; reflects CEDET
+ changes
+ * rudel-backend.el (new file): generic backend management, query
+ and loading functions
+ * Project.ede (target rudel): added rudel-backend.el to sources
+ * Makefile (rudel_LISP): added rudel-backend.el
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): use slot
+ :object-name instead of calling object-name-string
+ (rudel-obby-server::rudel-add-context): use slot :object-name
+ instead of calling object-name-string
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/rename):
+ use slot :object-name instead of calling object-name-string
+ (rudel-obby-connection::rudel-add-context): use slot :object-name
+ instead of calling object-name-string
+ (rudel-obby-connection::rudel-publish): use slot :object-name
+ instead of calling object-name-string
+ * rudel.el (class rudel-user): added base class eieio-named for
+ virtual slot :object-name; made abstract
+ (class rudel-document): added base class eieio-named for virtual
+ slot :object-name
+ * rudel-overlay.el (rudel-make-author-overlay): use slot
+ :object-name instead of calling object-name-string
+
+ * rudel-state-machine.el
+ (rudel-state-machine::initialize-instance): use &rest slots
+ instead of just slots
+
+2009-07-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::rudel-detach-from-buffer): call
+ `rudel-overlays-remove-all'; remove `rudel-unpublish-buffer' hook
+ early
+ * rudel-overlay.el (rudel-overlays-remove-all): new function;
+ remove all overlays from the current buffer
+ (whole file): cosmetic changes; typo fixes; whitespace fixes
+
+ * obby/rudel-obby.el (rudel-obby-document::rudel-unique-name):
+ Check `next-method-p' before calling the next method
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::initialize-instance): Check
+ `next-method-p' before calling the next method
+ (rudel-obby-connection::rudel-register-state): Check
+ `next-method-p' before calling the next method
+ (rudel-obby-connection::rudel-disconnect): Check
+ `next-method-p' before calling the next method
+ * rudel.el (rudel-client-session::rudel-end): Check
+ `next-method-p' before calling the next method
+
+2009-07-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): only
+ start the network process after everything is ready; wait for the
+ connection state machine to reach a success or error state
+ (rudel-obby-backend::rudel-host): cosmetic changes
+ (class rudel-obby-user): cosmetic changes
+ * rudel.el (rudel-join-session): reversed order of creation for
+ session and connection; do not catch errors to give error messages
+ a chance
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ cosmetic changes
+ (whole file): whitespace fixes
+
+ * rudel.el (rudel-session::rudel-find-user): added documentation
+ string; cosmetic changes
+ (rudel-session::rudel-find-document): added documentation string;
+ cosmetic changes
+ (whole file): whitespace fixes
+
+2009-07-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-speedbar.el (eieio-speedbar-object-buttonname): use
+ `rudel-unique-name' instead of `object-name-string'
+
+ * obby/rudel-obby-state.el (rudel-enter): return nil
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-enter): return nil
+ (rudel-obby-client-state-join-failed::rudel-enter): return nil
+ (rudel-obby-client-state-session-synching::rudel-enter): return
+ nil
+ (rudel-obby-client-state-session-synching::object-print): new
+ method; add number of remaining items to string representation
+ (rudel-obby-client-state-subscribing::rudel-enter): nil
+ (rudel-obby-client-state-document-synching::rudel-enter): nil
+ (rudel-obby-client-state-document-synching::object-print): new
+ method; add number of remaining bytes to string representation
+
+2009-07-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (with-parsed-arguments): added debug
+ declaration
+ (whole file): whitespace fixes
+ * rudel-util.el (rudel-assemble-line-fragments): added debug
+ declaration
+ (rudel-loop-lines): added debug declaration
+ (rudel-loop-chunks): fixed documentation string; added debug
+ declaration
+
+ * rudel-state-machine.el (rudel-no-start-state): new error symbol
+ (rudel-state-machine::initialize-instance): try hard to find a
+ suitable start sate; call `rudel-switch' instead of just
+ `rudel-enter'
+ (rudel-state-machine::rudel-switch): always return the new current
+ state; accept successor state from `rudel-enter'
+ (rudel-state-machine::object-print): new method; add current state
+ of state machine to string representation
+ (rudel-state-machine::rudel-state-wait): whitespace fixes
+
+2009-07-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (class rudel-obby-backend): better
+ documentation string
+ (rudel-obby-backend::rudel-ask-connect-info): added documentation
+ string
+ (rudel-obby-backend::rudel-connect): added documentation string
+ (rudel-obby-backend::rudel-ask-host-info): added documentation
+ string
+ (rudel-obby-backend::rudel-host): added documentation string
+ (rudel-obby-backend::rudel-make-document): added documentation
+ string
+ (rudel-obby-send): cosmetic changes
+ (whole file): whitespace fixes
+
+2009-07-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): added Emacs itself and GNUTls
+
+ * rudel-tls.el (rudel-tls-start-tls): added a message
+ (rudel-tls-wait-handshake): switch to filter
+ `rudel-tls-established' instead of restoring the original filter
+ (rudel-tls-established): new function; filters GNUTls messages in
+ encrypted connections
+ (whole file): whitespace fixes
+
+2009-07-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * README (INTRODUCTION): extended a bit
+ (JOINING A SESSION): added prompt/input example and an explanation
+ of encryption issues in the obby backend
+ (KNOWN BUGS): new section; no known bugs yet, though
+
+2009-06-17 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el (require rudel-state-machine): the
+ connection now is a state machine
+ (require rudel-obby-errors): used when analyzing login failures
+ (require rudel-obby-state): useful base classes for states
+ (rudel-obby-client-state-new): new class; initial state of new
+ connections
+ (rudel-obby-client-state-encryption-negotiate): new class;
+ first encryption state
+ (rudel-obby-client-state-encryption-start): new class; second
+ encryption state
+ (rudel-obby-client-state-joining): new class
+ (rudel-obby-client-state-join-failed): new class; entered after
+ failed login attempt
+ (rudel-obby-client-state idle): new class; default state of
+ established connections
+ (rudel-obby-client-state-session-synching): new class;
+ synchronizing session state to client
+ (rudel-obby-client-state-subscribing): new class; first state of
+ document subscription
+ (rudel-obby-client-state-document-synching): new class;
+ synchronizing document state to client
+ (rudel-obby-client-connection-states): new variable; alist of
+ name symbols and associated state classes
+ (rudel-obby-connection::initialize-instance): register states
+ (rudel-obby-connection::rudel-register-state): new method; set
+ connection slot of state to its connection
+ (rudel-obby-connection::rudel-add-context): cleanup
+ (rudel-obby-connection::rudel-message): dispatch message using
+ `rudel-accept'
+ (rudel-obby-connection::rudel-subscribe-to): initiate subscription
+ by switching to state 'subscribing'
+
+ * obby/rudel-obby-state.el (rudel-obby-document-handler): new
+ class; mixin class that provides handling of obby 'document'
+ messages
+
+ * rudel-state-machine.el
+ (rudel-state-machine::initialize-instance): find start state in
+ slots and switch into it
+ (while-file): whitespace fixes
+
+2009-06-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * www/index.html (section download): fixed link to download area
+ (whole file): whitespace cleanup
+
+ * obby/rudel-obby-state.el (new file): finite state machine states
+ for the rudel backend
+ * obby/Project.ede (target rudel/obby): added rudel-obby-state.el
+ * obby/Makefile (target obby_LISP): added rudel-obby-state.el
+
+ * rudel-util.el (require rudel-errors): required for dispatch
+ errors
+ (symbol rudel-dispatch-error): new condition symbol for dispatch
+ errors
+ (rudel-dispatch): new function; dispatch to method based on method
+ name
+ (whole file): whitespace fixes
+
+2009-06-14 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (global-rudel-minor-mode): removed; the variable
+ is created by `define-minor-mode'
+ (minor-mode-alist): managed by `define-minor-mode'
+
+ * rudel-mode.el (require easy-mmode): used to define global rudel
+ minor mode
+ (rudel-minor-keymap): cosmetic changes
+ (global-rudel-minor-mode): use `define-minor-mode' to define the
+ mode
+ (whole file): whitespace cleanup
+
+ * rudel-telepathy.el (whole file): moved to
+ telepathy/rudel-telepathy.el
+ * telepathy/rudel-telepathy.el (whole file): moved from
+ rudel-telepathy.el
+
+ * obby/rudel-obby-server.el (whole file): whitespace cleanup
+ * obby/rudel-obby-client.el (require rudel-obby): removed;
+ unnecessary
+ (rudel-obby-connection::initialize-instance): use &rest for `slots'
+ argument; cosmetic changes
+ (rudel-obby-connection::rudel-change-color-): use own `rudel-send'
+ method instead of the socket's
+ (rudel-obby-connection::rudel-subscribe-to): cosmetic changes
+ (rudel-obby-connection::rudel-unsubscribe-from): cosmetic changes
+ (rudel-obby-connection::rudel-local-operation): cosmetic changes
+ (whole file): whitespace cleanup
+
+2009-06-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-errors.el (new file): error data
+ * rudel-state-machine.el (new file): a simple finite state machine
+ implementation
+ * Project.ede (target rudel): added rudel-errors.el and
+ rudel-state-machine.el
+ * Makefile (target rudel_LISP): added rudel-errors.el and
+ rudel-state-machine.el
+
+2009-06-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el (require rudel-obby-errors): now
+ required
+ (rudel-obby-client::rudel-obby/net6_client_login): check username
+ and color before adding the client
+ (rudel-obby-server::rudel-check-username-and-color): new method;
+ make sure username and color are valid and there are no duplicates
+ * obby/rudel-obby-errors.el (new file): error data for the obby
+ backend
+ * obby/Project.ede (rudel/obby): added rudel-obby-errors.el
+ * obby/Makefile (obby_LISP): added rudel-obby-errors.el
+
+ * rudel.el (rudel-user::rudel-color): added accessor `rudel-color'
+
+ * obby/rudel-obby-server.el (require cl): required
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): send suffices
+ of synchronized documents
+
+2009-06-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document_create): send
+ document/rename message to client when the document suffix changes
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_user_colour): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document_create): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record/del): use
+ `with-parsed-arguments'
+
+ * obby/rudel-obby-server.el (header): fixed version
+
+2009-06-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-operation): fixed wording in
+ comment
+
+ * www/images/development.png (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/development.svg (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/download.png (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/download.svg (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/info.png (whole file): changed size 48x48 -> 64x64
+ * www/images/info.svg (whole file): changed size 48x48 -> 64x64
+
+ * index.html (section introduction): wording fixes; link to Gobby
+ (whole file): removed external link class for sourceforge links
+ (section download): added link to INSTALL file in svn code browser
+ (section footer): fixed copyright
+
+ * compatibility.html (section footer): fixed copyright
+
+2009-06-09 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (section REQUIREMENTS): removed ERT which is not
+ currently used
+ (section INSTALL): some wording and file name fixes
+ (section COMPILING): precise make command
+
+ * www/index.html (section development): fixed mailing list and
+ issue tracker links; removed email address
+
+ * www/compatibility.html (head): fixed charset
+ (section semantic): added missing <p> tag
+
+ * www/compatibility.html (new file): compatibility information
+ * www/index.html (new file): start page
+ * www/style.css (new file): stylesheet
+ * www/images/development.png (new file): development icon
+ * www/images/development.svg (new file): development icon
+ * www/images/download.png (new file): download icon
+ * www/images/download.svg (new file): download icon
+ * www/images/email-link.png (new file): icon for email links
+ * www/images/external-link.png (new file): icon for external links
+ * www/images/info.png (new file): info icon
+ * www/images/info.svg (new file): info icon
+ * www/images/screenshot.png (new file): screenshot for the start
+ page
+
+ * obby/rudel-obby-serverl.el
+ (rudel-obby-client::rudel-obby/obby_document_create): find unique
+ suffix for the new document; send suffix to clients
+
+ * obby/rudel-obby.el (header): fixed license text
+ * obby/rudel-obby-util.el (header): fixed license text
+ * obby/rudel-obby-server.el (header): fixed license text
+ * obby/rudel-obby-client.el (header): fixed license text
+ * jupiter/jupiter.el (header): fixed license text
+ * jupiter/jupiter-operation.el (header): fixed license text
+ * jupiter/jupiter-nop.el (header): fixed license text
+ * jupiter/jupiter-insert.el (header): fixed license text
+ * jupiter/jupiter-delete.el (header): fixed license text
+ * jupiter/jupiter-compound.el (header): fixed license text
+ * rudel.el (header): fixed license text
+ * rudel-util.el (header): fixed license text
+ * rudel-tls.el (header): fixed license text
+ * rudel-telepathy.e (header): fixed license text
+ * rudel-speedbar.el (header): fixed license text
+ * rudel-overlay.el (header): fixed license text
+ * rudel-operators.el (header): fixed license text
+ * rudel-operations.el (header): fixed license text
+ * rudel-mode.el (header): fixed license text
+ * rudel-interactive.el (header): fixed license text
+ * rudel-compat.el (header): fixed license text
+
+ * obby/rudel-obby-util.el (require cl): now required
+ (generic rudel-obby-char->byte): new generic; char positions ->
+ byte positions
+ (jupiter-insert::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-delete::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-compound::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-nop::rudel-obby-char->byte): new method; char positions
+ -> byte positions
+ (generic rudel-obby-byte->char): new generic; byte positions ->
+ char positions
+ (jupiter-insert::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-delete::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-compound::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-nop::rudel-obby-byte->char): new method; byte positions
+ -> char positions
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-operation): call
+ `rudel-obby-char->byte' before processing
+ (rudel-obby-connection::rudel-remote-operation): call
+ `rudel-obby-byte->char' before processing
+ * rudel.el (rudel-buffer-change-workaround-data): new variable;
+ holds change data for later use
+ (rudel-document::rudel-attach-to-buffer): add
+ `rudel-buffer-change-workaround' to 'before-change-functions'
+ (rudel-document::rudel-detach-from-buffer): remove
+ `rudel-buffer-change-workaround' from 'before-change-functions'
+ (rudel-buffer-change-workaround): new function; stores change data
+ for later use
+
+2009-06-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_join): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/net6_client_part): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_welcome): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_init): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_usertable_user): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_user_colour): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document):
+ use `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document_create): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document_remove): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document): use
+ `with-parsed-arguments'; cleanup
+ (rudel-obby-connection::rudel-obby/obby_document/rename): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/subscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/unsubscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): use
+ `with-parsed-arguments'
+
+2009-06-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): use `eql',
+ not `=' when calling `rudel-find-user' since the client id can be
+ nil
+
+ * obby/rudel-obby-util.el (require jupiter): silence byte compiler
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): moved inside file
+ (with-parsed-arguments): new macro; executed forms with variables
+ bound to parsed arguments
+
+2009-06-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (require rudel-interactive): interactive functions use
+ `rudel-read-backend' and `rudel-read-document'
+
+ * rudel.el (rudel-buffer-document): mark as permanent local
+ variable to prevent deletion in the event of a major-mode change
+ (rudel-document::rudel-attach-to-buffer): add (buffer-locally)
+ `rudel-handle-major-mode-change' to 'change-major-mode-hook' such
+ that it can repair damage caused by major-mode changes
+ (rudel-document::rudel-detach-from-buffer): remove
+ `rudel-handle-major-mode-change' from 'change-major-mode-hook'
+ (rudel-mode-changed-buffers) new variable; temporarily stores
+ buffers that underwent major-mode changes
+ (rudel-handle-major-mode-change): new function; schedules buffers
+ for repair after major-mode changes
+ (rudel-after-major-mode-change): new function; repairs buffer
+ objects after major-mode changes
+
+2009-06-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-buffer-has-document-p): use `buffer-local-value'
+ (rudel-buffer-document): use `buffer-local-value'
+ (rudel-set-buffer-document): added documentation string
+
+2009-06-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-handle-buffer-change): There are three cases
+ now: insert, delete and arbitrary changes; arbitrary changes
+ generate a delete and insert operation
+
+ * rudel-mode.el (rudel-minor-keymap): added some comments
+ (global-rudel-minor-mode): extended documentation string; cleaned
+ up code; added comments
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): fixed typo
+ in variable name client-id-numeric
+
+2009-05-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (header): Fixed version (1.0 -> 0.1)
+
+ * obby/rudel-obby-client.el (header): Fixed version (1.0 -> 0.1)
+ (rudel-obby-connection::rudel-obby/obby_document/record/split):
+ introduced temporary variable
+
+2009-??-?? Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-buffer-document): removed; replaced by
+ rudel-buffer-documents hash-table
+ (rudel-buffer-documents): new variable; a hash-table, which
+ associates documents to buffers
+ (rudel-buffer-has-document-p):
+ (rudel-buffer-document):
+ (rudel-set-buffer-document):
+
+2009-03-16 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): do not crash
+ if the client id cannot be found
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-make-document):
+ specify value 1 for slot suffix
+ (rudel-obby-document::suffix): new slot; contains the suffix
+ number of the document
+ (rudel-obby-document::rudel-unique-name): new method; return
+ unique name based on document name and suffix
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document): do
+ not ignore the suffix when creating the document object
+ (rudel-obby-connection::rudel-obby/obby_document_create): do not
+ ignore the suffix when creating the document object
+ (rudel-obby-connection::rudel-obby/obby_document/rename): change
+ document name and suffix as requested
+ * rudel.el (rudel-document::rudel-unique-name): new method;
+ returns a unique name for the document
+ (rudel-document::rudel-suggested-buffer-name): new method; returns
+ a suggested name for the buffer attached to the document
+ (rudel-subscribe): use `rudel-suggested-buffer-name' instead of
+ the object name
+ * rudel-interactive.el (rudel-read-document): use the unique names
+ of the documents instead of the object names
+
+2009-02-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): add hook to
+ detach document from the buffer when the buffer is killed
+ (rudel-document::rudel-detach-from-buffer): remove unpublish
+ function kill buffer hook
+
+2009-02-23 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document): minor cleanup
+ (rudel-document::rudel-attach-to-buffer): stylistic changes
+ (rudel-document::rudel-detach-from-buffer): fixed argument order in
+ call to `rudel-set-buffer-document'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-server::rudel-remove-client): Make sure there is a
+ user object before setting the status to offline
+
+ * obby/rudel-obby-client.el (rudel-obby/net6_encryption_failed):
+ only fail if encryption has been requested in the first
+ place. otherwise, just carry on
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): use
+ `rudel-set-buffer-document'
+ (rudel-document::rudel-detach-from-buffer): use
+ `rudel-set-buffer-document'
+ (rudel-buffer-has-document-p): new function; test whether a buffer
+ has an associated document object
+ (rudel-buffer-document): new function; returns associated document
+ object of a buffer
+ (rudel-set-buffer-document): new functions; sets associated
+ document object of a buffer
+ (rudel-handle-buffer-change): use `rudel-buffer-has-document-p'
+ (rudel-publish-buffer): use `rudel-buffer-has-document-p'
+ (rudel-unpublish-buffer): use `rudel-buffer-has-document-p' and
+ `rudel-buffer-document'
+ * rudel-mode.el (rudel-minor-keymap): use
+ `rudel-buffer-has-document-p'
+
+ * obby/rudel-obby-client.el (rudel-obby/obby_document/rename):
+ new method; dummy implementation
+
+ * obby/rudel-obby-client.el (rudel-obby/net6_client_join):
+ stylistic change
+
+2009-02-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (generic rudel-operation->message): new
+ generic function; serializes an operation
+ (jupiter-insert::rudel-operation->message): new method
+ (jupiter-delete::rudel-operation->message): new method
+ (jupiter-compound::rudel-operation->message): new method
+ (jupiter-nop::rudel-operation->message): new method
+ (rudel-message->operation): new function; deserializes an
+ operation from a received message
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-insert): do not construct
+ message string; use `rudel-operation->message'
+ (rudel-obby-connection::rudel-local-delete): do not construct
+ message string; use `rudel-operation->message'
+ (rudel-obby-connection::rudel-local-operation): new method;
+ handles operation objects that represent local operations
+ (rudel-obby-connection::rudel-remote-operation): new method;
+ handles operation objects that represent remote operations
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins):
+ construct operation name correctly; do not call jupiter context to
+ transform operation
+ (rudel-obby-connection::rudel-obby/obby_document/record/del):
+ construct operation name correctly; do not call jupiter context to
+ transform operation
+ (rudel-obby-connection::rudel-obby/obby_document/record/split):
+ new method; handles split operation messages
+ (rudel-obby-connection::rudel-obby/obby_document/record/noop): new
+ method; handles nop messages
+
+2009-02-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info):
+ ask whether to encrypt the connection
+ (rudel-obby-backend::rudel-connect): create connection object
+ capable of StartTLS encryption when encryption was requested
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_encryption): do not fail
+ when the server requests encryption
+ (rudel-obby-connection::rudel-obby/net6_encryption_begin): start
+ TLS encryption for the connection
+ (rudel-obby-connection::rudel-obby/net6_encryption_failed): new
+ method; stub
+ * rudel-tls.el (new file): StartTLS encryption for Rudel
+ * Project.ede ("rudel"): added rudel-tls.el
+ * Makefile (rudel_LISP): added rudel-tls.el
+
+2009-02-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el (header): fixed email address, keywords, legal
+ notice and file commentary
+
+2009-02-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-compat): require rudel-compat for
+ `read-color'
+ * rudel.el (rudel-compat): require rudel-compat for `read-color'
+ * rudel-interactive.el (rudel-compat): require rudel-compat for
+ `read-color'
+ * rudel-compat.el (new file): compatibility code
+ * Project.ede (rudel): added rudel-compat.el
+ * Makefile (rudel_LISP): regenerated: added rudel-compat.el
+
+2009-02-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (require rudel)
+ * obby/rudel-obby-util.el (require rudel)
+ * obby/rudel-obby-client.el (require rudel-obby): make compilation
+ succeed
+
+ * rudel.el (include eieio-speedbar): I need it for now; I should
+ get rid of it later
+
+ * INSTALL (REQUIREMENTS): added note that CVS version of cedet is
+ required
+ (INSTALLING): added subdirectories jupiter and obby in load path
+ listing; fixed name of autoload file
+
+2009-02-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info)
+ (rudel-obby-backend::rudel-host, rudel-obby-replace-in-string)
+ * obby/rudel-obby-util.el (rudel-obby-dispatch)
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-obby/obby_document)
+ (rudel-obby-server::rudel-broadcast, rudel-obby-server::rudel-make-user)
+ * obby/rudel-obby-client.el (rudel-obby-connection::rudel-obby/net6_client_join)
+ (rudel-obby-connection::rudel-obby/obby_document)
+ * jupiter/jupiter-operation.el (jupiter-operation)
+ * rudel.el (rudel-backend, rudel-session, rudel-server-session)
+ (rudel-connection, rudel-document)
+ (rudel-document::rudel-attach-to-buffer)
+ (rudel-document::rudel-detach-from-buffer)
+ (rudel-document::rudel-insert, rudel-document::rudel-delete)
+ (rudel-change-color)
+ * rudel-util.el (rudel-assemble-line-fragments, rudel-loop-lines)
+ * rudel-overlay.el (rudel-make-author-overlay)
+ * rudel-interactive.el (rudel-read-backend, rudel-read-user-color)
+ (rudel-read-user, rudel-read-document): replaced 't by t
+
+ * rudel-operators.el (rudel-overlay-operators::rudel-insert):
+ Fixed computation of insertion offset when appending to the end of
+ the buffer string
+
+ * rudel.el (rudel-document::rudel-chunks): fixed invalid access to
+ last chunk for empty buffer
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): fixed
+ incorrect slot reference
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): minor
+ rearrangement of expressions
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): minor
+ rearrangement of expressions
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): added
+ documentation string
+ (rudel-obby-client::rudel-obby/obby_document/record/del): added
+ documentation string
+ (rudel-obby-server): cosmetic change
+
+ * jupiter/jupiter.el (jupiter-context::jupiter-remote-operation):
+ improved documentation string; cosmetic changes
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ improved some comments
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): renamed
+ some variables; added documentation string
+ (rudel-document::rudel-insert): improved documentation string
+ (rudel-document::rudel-chunks): do not create chunks when buffer
+ string is empty; improved comments
+ (rudel-choose-backend): compare number using `=' not `eq'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): use
+ `rudel-remote-operation' instead of `rudel-remote-insert'
+ (rudel-obby-client::rudel-obby/obby_document/record/del): use
+ `rudel-remote-operation' instead of `rudel-remote-delete'
+ * obby/rudel-obby-client.el (include rudel-operations): for
+ rudel-insert-op and rudel-delete-op
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `rudel-remote-operation' with rudel-insert-op to insert chunks
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): use
+ `rudel-remote-operation' instead of `rudel-remote-insert'
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): use
+ `rudel-remote-operation' instead of `rudel-remote-delete'
+ * jupiter/jupiter-operation.el (include rudel-operations): for
+ rudel-operation
+ (jupiter-operation): derived from rudel-operation
+ (jupiter-operation::jupiter-apply): removed; replaced by generic
+ `rudel-apply'
+ * jupiter/jupiter-nop.el (jupiter-nop::jupiter-apply): removed;
+ replaced by `rudel-apply'
+ (jupiter-nop::rudel-apply): new method; implements generic
+ `rudel-apply'
+ * jupiter/jupiter-insert.el (include rudel-operations): for
+ jupiter-insert-op
+ (jupiter-insert): derived from jupiter-insert-op
+ (jupiter-insert::jupiter-apply): removed; inherited from
+ jupiter-insert-op
+ (jupiter-insert::slot-missing): removed; inherited from
+ jupiter-insert-op
+ * jupiter/jupiter-delete.el (include rudel-operations): for
+ jupiter-delete-op
+ (jupiter-delete): derived from jupiter-delete-op
+ (jupiter-delete::jupiter-apply): removed; inherited from
+ jupiter-delete-op
+ (jupiter-delete::slot-missing): removed; inherited from
+ jupiter-delete-op
+ * jupiter/jupiter-compound.el (jupiter-compound::jupiter-apply):
+ removed; replaced by `rudel-apply'
+ (jupiter-compound::rudel-apply): new method; implements generic
+ `rudel-apply'
+ * rudel.el (include rudel-operations): everything is represented
+ in terms of operations
+ (include rudel-operators): operations apply changes to objects
+ through operators
+ (rudel-document::rudel-insert): new method; performs insert
+ operation
+ (rudel-document::rudel-delete): new method; performs delete
+ operation
+ (rudel-document::rudel-local-insert): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-local-delete): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-remote-insert): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-remote-delete): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-local-operation): new method; apply
+ operation using overlay and connection operators
+ (rudel-document::rudel-remote-operation): new method; apply
+ operation using document and overlay operators
+ (rudel-handle-buffer-change): realize buffer changes using
+ operations
+ * rudel-operators.el (new file): collections of operations on
+ Rudel data types
+ * rudel-operations.el (new file): operation classes
+
+2009-02-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ handle jupiter-nop
+
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ in inner cond, use matching pattern but empty body for
+ no-operation cases; in outer cond, handle jupiter-nop
+
+ * jupiter/jupiter-compound.el (jupiter-compound): now derived from
+ jupiter-operation; should have been right from the start
+
+2009-01-31 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-default-username): Default name used when
+ prompting for user name; required by rudel-interactive
+
+ * rudel-interactive.el (rudel-read-backend): fixed typo
+
+2009-01-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ fixed two offset calculations
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ fixed offset calculation
+
+ * rudel.el (rudel-backend::rudel-ask-connect-info): changed from
+ method to generic
+ (rudel-backend::rudel-connect): changed from method to generic
+ (rudel-backend::rudel-ask-host-info): changed from method to
+ generic
+ (rudel-backend::rudel-host): changed from method to generic
+ (rudel-backend::rudel-make-document): changed from method to
+ generic
+ (rudel-session::rudel-disconnect): changed from method to generic
+ (rudel-session::rudel-change-color-): changed from method to
+ generic
+ (rudel-session::rudel-publish): changed from method to generic
+ (rudel-session::rudel-subscribe-to): changed from method to
+ generic
+ (rudel-session::rudel-unsubscribe-from): changed from method to
+ generic
+ (rudel-session::rudel-local-insert): changed from method to
+ generic
+ (rudel-session::rudel-local-delete): changed from method to
+ generic
+ (rudel-session::rudel-remote-insert): changed from method to
+ generic
+ (rudel-session::rudel-remote-delete): changed from method to
+ generic
+
+2009-01-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-overlay.el (header): fixed version
+ (whole file): cosmetic changes
+ (rudel-author-overlay-p): added documentation string
+ (rudel-author-overlays): added documentation string
+
+ * rudel-mode.el (rudel-minor-keymap): cosmetic changes
+
+ * rudel-mode.el (rudel-minor-keymap): Separated session
+ participation and hosting items
+
+ * obby/rudel-obby.el (rudel-obby-long-message-threshold): Added
+ documentation string
+ (rudel-obby-long-message-chunk-size): Added documentation string
+ (rudel-obby-backend::rudel-connect): Do not set process object;
+ this is done in the `initialize-instance' method of the base class
+ (rudel-obby-format-color): retrieve color components with
+ `color-values'
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-remove-context): improved
+ documentation string
+ (rudel-obby-connection::rudel-publish): added a comment
+ (rudel-obby-connection::rudel-subscribe-to): added some comments;
+ cleaned up code
+ (rudel-obby-connection::rudel-unsubscribe-from): added a comment
+ (rudel-obby-connection::rudel-obby/net6_ping): added documentation
+ string
+ (rudel-obby-connection::rudel-obby/net6_encryption): added
+ documentation string
+ (rudel-obby-connection::rudel-obby/net6_login_failed): added
+ documentation string
+ (rudel-obby-connection::rudel-obby/net6_client_part): use `='
+ instead of `eq' to compare client ids; fixed documentation string;
+ improved comments
+ (rudel-obby-connection::rudel-obby/obby_user_colour): use `='
+ instead of `eq' to compare user ids
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `=' instead of `eq' to compare user ids; use accessor
+ `user-id-numeric'
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): new functions;
+ dispatches to class methods based on message name; handles errors
+ properly
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-message):
+ use `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-client::rudel-obby/obby_document): use
+ `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-client::rudel-obby/obby_document/record): use
+ `rudel-obby-dispatch' to dispatch message
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-message): use `rudel-obby-dispatch'
+ to dispatch message; moved to a different location
+ (rudel-obby-connection::rudel-obby/obby_document): use
+ `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-connection::rudel-obby/obby_document/record): use
+ `rudel-obby-dispatch' to dispatch message
+
+ * obby/rudel-obby-util.el (generic rudel-message): made the method
+ a generic function and updated the documentation string
+
+2009-01-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-document::revision): removed; The
+ slot is no longer needed
+ * obby/rudel-obby-server.el (require jupiter): uses jupiter
+ algorithm
+ (rudel-obby-client::rudel-obby/obby_document_create): add a
+ jupiter context for the document
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): add a
+ jupiter context for the document
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): remove
+ the jupiter context associated to the document
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ transformed the operation before applying it to the buffer; use
+ the respective jupiter contexts of the receivers when sending the
+ operation
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ transformed the operation before applying it to the buffer; use
+ the respective jupiter contexts of the receivers when sending the
+ operation
+ (rudel-obby-server::contexts): new slot; stores jupiter contexts
+ for pairs of clients and documents
+ (rudel-obby-server::initialize-instance): new method; store an
+ empty hash-table in the `contexts' slot
+ (rudel-obby-server::rudel-find-context): find the jupiter context
+ for a pair of a client and a document
+ (rudel-obby-server::rudel-add-context): add a jupiter context for
+ a pair of a client and a document
+ (rudel-obby-server::rudel-remove-context): remove the jupiter
+ context for a pair of a client and a document
+ (rudel-obby-context-key): return a list of client id and document
+ id
+ * obby/rudel-obby-client.el (require jupiter): uses jupiter
+ algorithm
+ (rudel-obby-connection::contexts): new slot; stores jupiter
+ contexts for documents
+ (rudel-obby-connection::initialize-instance): new method; store an
+ empty hash-table in the `contexts' slot
+ (rudel-obby-connection::rudel-find-context): new method; return
+ the jupiter context for a document
+ (rudel-obby-connection::rudel-add-context): new method; add a
+ jupiter context for a document
+ (rudel-obby-connection::rudel-remove-context): new method; remove
+ the jupiter context for a document
+ (rudel-obby-connection::rudel-publish): add a jupiter context for
+ the new document
+ (rudel-obby-connection::rudel-subscribe-to): add a jupiter context
+ for the new document
+ (rudel-obby-connection::rudel-unsubscribe-from): remove the
+ jupiter context associated to the document
+ (rudel-obby-connection::rudel-local-insert): use revision
+ information from the jupiter context instead of the document;
+ supply the operation to the jupiter context
+ (rudel-obby-connection::rudel-local-delete): use revision
+ information from the jupiter context instead of the document;
+ supply the operation to the jupiter context
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins):
+ transform the operation using the jupiter context instead of using
+ it unmodified
+ (rudel-obby-connection::rudel-obby/obby_document/record/del):
+ transform the operation using the jupiter context instead of using
+ it unmodified
+
+2009-01-22 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el (rudel-obby-connection): removed
+ redundant slot `socket' (inherited from base class)
+
+2009-01-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-user): added comments
+ (rudel-allocate-buffer-clear-existing): added documentation string
+ (rudel-allocate-buffer-make-unique): added documentation string
+
+2009-01-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el, rudel-util.el, rudel-telepathy.el, rudel-speedbar.el,
+ rudel-overlay.el, rudel-mode.el, jupiter/jupiter.el,
+ jupiter/jupiter-operation.el, jupiter/jupiter-nop.el,
+ jupiter/jupiter-insert.el, jupiter/jupiter-delete.el,
+ jupiter/jupiter-compound.el, obby/rudel-obby.el,
+ obby/rudel-obby-util.el, obby/rudel-obby-server.el,
+ obby/rudel-obby-client.el (header): changed email address
+ <scymtym@users.sourceforge.net> ->
+ <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (header): added keywords to file header
+ comment
+
+ * jupiter/jupiter.el (new file): core Jupiter algorithm
+ * jupiter/jupiter-operation.el (new file): base class for Jupiter
+ operations
+ * jupiter/jupiter-insert.el (new file): insert operation for
+ Jupiter algorithm
+ * jupiter/jupiter-delete.el (new file): delete operation for
+ Jupiter algorithm
+ * jupiter/jupiter-nop.el (new file): no-operation for Jupiter
+ algorithm
+ * jupiter/jupiter-compound.el (new file): compound operation for
+ Jupiter algorithm
+
+2009-01-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-user::client-id): added rationale
+ for type (or null integer)
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_join): added
+ documentation string; cosmetic changes
+ (rudel-obby-connection::rudel-obby/net6_client_part): use accessor
+ `rudel-client-id' when searching for the user object; set
+ client-id to nil in the user object; added documentation string
+ (rudel-obby-connection::rudel-obby/obby_sync_usertable_user):
+ store parsed user-id and color in temporaries
+ (rudel-obby-connection::rudel-obby/obby_user_colour):store parsed
+ color in a temporary; use accessor `rudel-id' when finding the
+ user object
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-change-color-): new function;
+ implements changing the color
+
+ * obby/rudel-obby-util.el
+ (rudel-obby-socket-owner::rudel-receive): improved documentation
+ string
+
+2009-01-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): proper list of requirements and sources
+ from which they can be obtained
+ (INSTALLING): initial version of installation instructions
+ (COMPLETING): some notes about compiling
+ * README (INTRODUCTION): short introduction
+ (GETTING STARTED): some notes about enabling Rudel, joining and
+ hosting sessions
+
+2009-01-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-long-message-threshold): new
+ variable; threshold for message size, above which messages are
+ sent in multiple chunks
+ (rudel-obby-long-message-chunk-size): Chunk size used, when
+ chunking long messages.
+ (rudel-obby-user::client-id): allow value nil; added accessor;
+ added documentation string
+ (rudel-obby-send): new function; handles low-level aspects of
+ sending obby protocol messages
+ * obby/rudel-obby-util.el: new file; contains helper
+ functionality, mainly the class `rudel-obby-socket-owner', which
+ handles sending and receiving message
+ * obby/rudel-obby-server.el (includes): replaced rudel-obby with
+ rudel-obby-util, since it contains `rudel-obby-socket-owner'
+ (class rudel-obby-client): added base class
+ `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-receive): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-send): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-message): new method; called by base
+ class when a message is received; dispatches to appropriate
+ handler method
+ (rudel-obby-client::rudel-obby/obby_user_colour): minor change in
+ documentation string
+ * obby/rudel-obby-client.el (includes): replaced rudel-obby with
+ rudel-obby-util, since it contains `rudel-obby-socket-owner'
+ (class rudel-obby-connection): added base class
+ `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-disconnect): just call next method;
+ it does what this method formerly did
+ (rudel-obby-connection::rudel-close): new method; end the session,
+ when the connection is closed
+ (rudel-obby-connection::rudel-receive): deleted, the functionality
+ is provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-send): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-message): new method; called by
+ base class when a message is received; dispatches to appropriate
+ handler method
+
+ * rudel.el (rudel-document::rudel-detach-from-buffer): do nothing,
+ if the document is not attached to any buffer
+
+ * obby/rudel-obby.el (rudel-obby-user): added missing accessor
+ `rudel-connected'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): transmit number
+ of synchronization items; transmit list of disconnected users
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ broadcast only to clients, which are subscribed to the document;
+ send user id of author instead of client id
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ broadcast only to clients, which are subscribed to the document;
+ send user id of author instead of client id
+ (rudel-obby-client::rudel-subscribed-clients-not-self): new
+ method; return a list of clients subscribed to a document
+ excluding the client itself.
+
+ * obby/rudel-obby-server.el (rudel-obby-server::next-client-id):
+ first id should be 1, not 0; fixed initform accordingly
+ (rudel-obby-server::next-user-id):
+ first id should be 1, not 0; fixed initform accordingly
+
+ * rudel.el (rudel-document::rudel-chunks): fixed void variable
+ `chunks-' -> `augmented-chunks'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): send
+ individual buffer chunks with their respective authors instead of
+ one large string without author information
+ * rudel.el (rudel-document::rudel-chunks): new method; return a
+ list of buffer position ranges and the respective authors, that
+ wrote the text
+
+2009-01-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-host): cleanup
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-insert): accept arguments
+ `position' and `data' instead of `from', `to' and `what'; since
+ position is zero-based, transmit it literally
+ (rudel-obby-connection::rudel-local-delete): instead of `from' and
+ `to' accept argument `position'; since position is
+ zero-based. transmit it literally
+ (rudel-obby-connection::rudel-obby/obby_document/record):
+ identified remaining arguments; dispatch actions to appropriate
+ methods; identify methods by interning their symbols
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): new
+ method; handle remote insert actions
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): new
+ method; handle remote delete actions
+ * rudel.el (includes): include rudel-overlay
+ (rudel-document::rudel-detach-from-buffer): improved readability
+ (rudel-document::rudel-local-insert): instead of redundant
+ arguments `from', `to' and `what' accept only `position' and
+ `data'; update overlays
+ (rudel-document::rudel-local-delete): instead of redundant
+ arguments `from', `to' and `length' accept only `position' and
+ `length'; update overlays
+ (rudel-document::rudel-remote-insert): renamed arguments `from' ->
+ `position', `what' -> `data'; update overlays
+ (rudel-document::rudel-remote-delete): replaced arguments `from'
+ and `to' by `position'; update overlays
+ (rudel-handle-buffer-change): call rudel-local-{insert, delete}
+ with changed arguments
+
+2009-01-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-session::rudel-unsubscribed-documents): new
+ method; returns documents, to which the user associated with the
+ session is not yet subscribed
+ (rudel-subscribe): when called interactively, use
+ `rudel-unsubscribed-documents' to offer only unsubscribed
+ documents in completing read
+
+ * rudel-interactive.el (rudel-read-user-name): new function; read
+ a user name; could be used to enforce certain constraints on the
+ name
+ (rudel-read-user-color): new function; read a user color; could be
+ used to enforce certain constraints on the color
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-host-info):
+ new method; ask user for port number
+ (rudel-obby-backend::rudel-host): new method; require obby server
+ component, make the network process and construct the server
+ * obby/rudel-obby-server.el (new file): initial revision of obby
+ server for rudel
+ * obby/rudel-obby-client.el (header section): added keyword and
+ x-rcs
+ (rudel-obby-connection::rudel-publish): new method; send document
+ to server
+ (rudel-obby-connection::rudel-unsubscribe-from): send unsubscribe
+ notification to server
+ (rudel-obby-connection::rudel-local-insert): cleanup
+ (rudel-obby-connection::rudel-local-delete): new method; send
+ delete record to server and increase local revision
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk):
+ improved user locating code; do not complain, when the user is not
+ found
+ (rudel-obby-connection::rudel-obby/obby_document/record): removed
+ useless debug message
+ * rudel.el (class rudel-session): update documentation string
+ (class rudel-server-session): new class; base class for server
+ sessions
+ (rudel-choose-backend): fixed void-variable when called
+ interactively
+ (rudel-host-session): provided initial implementation, which uses
+ the selected backend to create a server
+ (rudel-subscribe): call `set-window-buffer' instead of
+ `show-buffer'
+
+ * obby/rudel-obby.el (header section): fixed history
+ (rudel-obby-version): new constant; holds version of the obby
+ backend
+ (rudel-obby-protocol-version): new constant; holds the obby
+ protocol version understood by the backend
+ (rudel-obby-document::rudel-both-ids): new method; useful when
+ locating documents by means of owner and document id
+
+ * rudel-mode.el (header section): added keywords
+
+ * rudel-interactive.el (header section): added file comment
+
+2008-12-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (class rudel-session): converted to base class for
+ other session classes; removed slots `connection' and `self' which
+ are specific for client sessions
+ (rudel-session::rudel-end): empty now; derived classes do the work
+ (rudel-session::rudel-add-user): use `object-add-to-list'
+ (rudel-session::rudel-remove-user): use `object-remove-from-list'
+ (rudel-session::rudel-add-document): use `object-add-to-list'
+ (rudel-session::rudel-remove-document): use
+ `object-remove-from-list'
+ (class rudel-client-session): derived from `rudel-session';
+ additional slots `connection' and `self'
+ (rudel-client-session::rudel-end): detach buffers from documents
+ and call `rudel-disconnect' on connection
+ (class rudel-connection): documentation string
+ (rudel-connection::rudel-disconnect): remove hook
+ `after-change-functions' only locally
+ (rudel-join-session): construct a proper session name; store
+ backend object in the session; some comments
+
+ * obby/rudel-obby.el (rudel-obby-document): cleanup; improved
+ documentation strings
+
+ * rudel-overlay.el (new file): functions for managing overlays,
+ which indicate the authors of contributions in collaborative
+ buffers
+
+ * rudel.el (rudel-allocate-buffer-function): customization option
+ for buffer allocation function
+ (rudel-subscribe): call buffer allocation function instead of just
+ using the provided name
+ * rudel-interactive.el (rudel-allocate-buffer-clear-existing): new
+ function; in case of a conflict, allocate buffer for subscription
+ by clearing the existing buffer
+ (rudel-allocate-buffer-make-unique): new function; in case of a
+ conflict, allocate buffer for subscription by producing a unique
+ name
+
+ * rudel.el (customization): added customization group definition
+ for `rudel'
+
+ * obby/rudel-obby.el (includes): require `rudel-util' instead of
+ `rudel'
+ (rudel-connect): attach connection to socket object
+ (rudel-obby-document): removed slot `subscribed' as it is now
+ contained in the base class `rudel-document'
+ (rudel-obby-escape-string): call `rudel-obby-replace-in-string'
+ instead of `obby-replace-in-string'
+ (rudel-obby-unescape-string): call `rudel-obby-replace-in-string'
+ instead of `obby-replace-in-string'
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-state-change): required by
+ `rudel-sentinel-dispatch'
+ (rudel-obby-connection::rudel-subscribe-to): do not touch slot
+ `subscribed'
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document):
+ retrieve subscribed users and add to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document_create): add
+ document owner to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document/subscribe): add
+ user to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document/unsubscribe):
+ remove user from `subscribed' slot
+ * rudel.el (rudel-document): added slot `subscribed' which
+ contains a list of subscribed users
+ (rudel-subscribe): do not use `rudel-unsubscribed-documents';
+ instead list all documents for now
+ (rudel-publish-buffer): add self to `subscribed' slot
+
+ * rudel-util.el (rudel-state-change): cleanup; added comments
+
+ * rudel-mode.el (rudel-minor-keymap): Fixed invalid menu
+ definition
+
+ * obby/rudel-obby.el (whole file): moved class
+ `rudel-obby-connection' and related methods into file
+ `rudel-obby-client.el'
+ (rudel-obby-backend): added capability `track-subscriptions'
+ (rudel-obby-backend::rudel-connect): require `rudel-obby-client'
+ before constructing the connection object
+ * obby/rudel-obby-client.el (new file): moved class
+ `rudel-obby-connection' and related methods into this file
+
+2008-12-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-connection::rudel-change-color-): new method
+ handles color changes
+ (rudel-change-color): added basic implementation, which checks the
+ backend, asks the user for a new color and calls the connection
+ object
+
+ * rudel-util.el (rudel-socket-owner::rudel-state-change): called
+ when the state of the connection changes
+ (rudel-socket-owner::rudel-close): called when the connection is
+ closed
+ (rudel-sentinel-dispatch): the argument is a message, not the
+ actual state, the state is retrieved with `process-state'
+
+ * rudel-speedbar.el (whole file): cleanup; improved comments
+
+ * rudel-mode.el (whole file): improved comments
+ (rudel-read-{backend, document}): moved to rudel-interactive.el
+ (rudel-minor-keymap): added key binding for `rudel-change-color';
+ added `options' menu item
+
+ * rudel-interactive.el (whole file): user interaction functions
+ used by all Rudel components
+
+ * rudel-util.el (whole file): utility functions used by all Rudel
+ components
+
+ * rudel.el (whole file): improved comments
+ (rudel-backend::make-document): new function create an appropriate
+ document object for the backend
+ (rudel-session::rudel-end): added documentation string
+ (rudel-session::rudel-add-user): added documentation string
+ (rudel-session::rudel-remove-user): added documentation string
+ (rudel-session::rudel-remove-document): new method; remove
+ document from session
+ (rudel-connection::rudel-publish): new function; called when a
+ buffer is published
+ (rudel-connection::rudel-unsubscribe-from): new function; called
+ when a subscription is canceled
+ (class rudel-user): added documentation strings
+ (class rudel-document): added documentation strings
+ (rudel-document::rudel-attach-to-buffer): add to
+ `after-change-functions' hook only for the buffer in question;
+ added some comments
+ (rudel-document::rudel-detach-from-buffer): cleanup
+ (rudel-document::rudel-remote-insert): added comments
+ (rudel-document::rudel-remote-delete): added comments
+ (rudel-handle-buffer-change): added comments
+ (rudel-choose-backend): added comments
+ (rudel-end-session): additional error check
+ (rudel-subscribe): call `rudel-unsubscribed-documents' when
+ completing document name; added comments
+ (rudel-unpublish-buffer): call `rudel-detach-from-buffer' and
+ `rudel-unsubscribe-from'; added comments
+
+ * obby/rudel-obby.el (whole file): improved comments
+ (rudel-obby-backend::rudel-ask-connect-info): removed :override
+ tag; added comments
+ (rudel-obby-backend::rudel-connect): removed :override tag; use
+ `make-network-process' instead of `open-network-stream' and attach
+ filter and sentinel right away; removed some debug code
+ (rudel-obby-backend::rudel-disconnect): removed :override tag
+ (rudel-obby-backend::rudel-subscribe-to): removed :override tag
+ (rudel-obby-backend::rudel-local-insert): removed :override tag
+ (rudel-obby-backend::rudel-local-delete): removed :override tag
+ (rudel-obby-backend::rudel-make-document): new method; creates a
+ new rudel-obby-document object
+ (rudel-obby-backend::rudel-available-document-id): obtains an
+ unused document id, which can be assigned to a new document
+ (class rudel-obby-connection): removed useless `host' and `port'
+ slots
+ (rudel-obby-connection::rudel-receive): removed some debug code
+ (rudel-obby-connection::rudel-send): removed some debug code
+ (rudel-obby-connection::rudel-obby/net6_client_join): fixed syntax
+ error
+ (class rudel-obby-user): added accessors for slots `client-id' and
+ `user-id'
+ (rudel-obby-user::eieio-speedbar-description): removed :override
+ tag
+ (rudel-obby-user::eieio-speedbar-object-buttonname): removed
+ :override tag
+ (class rudel-obby-document): added accessors and documentation for
+ slot `id'
+ (rudel-obby-document::eieio-speedbar-object-buttonname): removed
+ :override tag
+ (rudel-obby-replace-in-string): new function; replace a set of
+ patterns in a string
+ (rudel-obby-escape-string): new function; replace obby control
+ characters with their escape sequences
+ (rudel-obby-unescape-string): new function; inverse of
+ `rudel-obby-escape-string'
+ (rudel-obby-parse-color): added documentation
+ (rudel-obby-format-color): added documentation
+ (rudel-obby-assemble-message): properly escape message components
+ (rudel-obby-parse-message): properly unescape message components
+
+ * README (whole file): some initial notes
+ * INSTALL (whole file): some initial notes
+
+2008-12-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby (directory): new directory for files belonging to the obby
+ backend
+ * rudel-obby.el (whole file): moved to `obby' directory
+ * obby/rudel-obby.el (whole file): moved here from parent
+ directory
+
+ * Changelog (whole file): renamed to `ChangeLog?'
+ * ChangeLog? (whole file): fixed name
+
+ * INSTALL (whole file): added
+
+ * rudel.el (whole file): fixed some comments, removed some test
+ code
+ (rudel-version): new variable; global Rudel version
+ (rudel-sessions): removed; we only allow one session for now
+ (rudel-session): cleaned up
+ (rudel-session::rudel-end): cleaned up; added some comments
+ (rudel-session::rudel-add-user): cosmetic changes
+ (rudel-session::rudel-remove-user): cosmetic changes
+ (rudel-session::rudel-find-user): cosmetic changes
+ (rudel-session::rudel-add-document): cosmetic changes
+ (rudel-session::rudel-find-document): cosmetic changes
+ (rudel-backend::rudel-connect): improved documentation string
+ (rudel-backend::rudel-ask-host-info): renamed from
+ `rudel-ask-listen-info'
+ (rudel-backend::rudel-host): renamed from `rudel-listen'
+ (rudel-document::rudel-attach-to-buffer): cosmetic changes
+ (rudel-document::rudel-remote-insert): cleaned up
+ (rudel-document::rudel-remote-delete): cleaned up
+ (rudel-load-backends): cosmetic changes
+ (rudel-choose-backend): fixed message display
+ (rudel-host-session): improved documentation string
+ (rudel-change-color): raise an error since this is not yet
+ implemented
+ (rudel-subscribe): added comments
+ (rudel-unpublish-buffer): raise an error if the buffer has not
+ been published
+
+ * rudel.el (whole file): cleanup up some obsolete code
diff --git a/emacs.d/lisp/rudel/.svn/text-base/INSTALL.svn-base b/emacs.d/lisp/rudel/.svn/text-base/INSTALL.svn-base
new file mode 100644
index 0000000..2555d09
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/INSTALL.svn-base
@@ -0,0 +1,58 @@
+* REQUIREMENTS
+
+ Rudel is developed and tested only with GNU Emacs and therefore
+ unlikely to run on other Emacs variants like XEmacs.
+
+ To use Rudel, the following software is required:
+
+** GNU Emacs 22 or above
+ Rudel should work with recent versions of GNU Emacs starting from
+ version 22. Older versions of GNU Emacs or XEmacs may or not work
+ but are not actively tested.
+
+** Collection of Emacs Development Environment Tools (CEDET)
+ Cedet contains the object system Eieio, which is used in Rudel's
+ object-oriented implementation. Cedet can be obtained from
+ http://cedet.sourceforge.net/
+
+ IMPORTANT: It is necessary to use at least the 1.0pre6 version of
+ CEDET since it fixes a serious problem in the object system Eieio.
+
+ As of October 2009, Eieio is included in GNU Emacs. If you are
+ using a version built since then, you do not have to install it
+ yourself.
+
+** GnuTLS (optional)
+ Connections to Gobby servers require the gnutls-cli program.
+
+** Avahi (optional)
+ The Avahi daemon (http://avahi.org) is required for automatic
+ session discovery and advertising.
+
+ A version of GNU Emacs with Zeroconf support (GNU Emacs 23 or
+ above) is required to talk to the Avahi daemon.
+
+* INSTALLING
+
+ To install Rudel, download a released version or the current
+ development version from http://sourceforge.net/projects/rudel/ and
+ place the code in any directory you like.
+
+ Once Eieio (see CEDET in the REQUIREMENTS section above) is
+ installed, add the following to your personal Emacs configuration:
+
+ (load-file "/PATH/TO/RUDEL/rudel-loaddefs.el")
+
+ This will set Rudel up to be loaded on demand when one of the
+ commands `rudel-join-session', `rudel-host-session' or
+ `global-rudel-minor-mode' is invoked.
+
+* COMPILING
+
+ In order to achieve better performance, Emacs can byte-compile the
+ Rudel code. This can be done by opening rudel-compile.el in Emacs
+ and invoking M-x eval-buffer.
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..ff3a264
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,24 @@
+;; Object rudel
+;; EDE project file.
+(ede-proj-project "rudel"
+ :name "rudel"
+ :version "0.3"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp-autoloads "autoloads"
+ :name "autoloads"
+ :path ""
+ :autoload-file "rudel-loaddefs.el"
+ :autoload-dirs '("." "jupiter" "obby" "wave" "zeroconf")
+ )
+ (ede-proj-target-elisp "compile"
+ :name "rudel"
+ :path ""
+ :source '("rudel.el" "rudel-util.el" "rudel-mode.el" "rudel-interactive.el" "rudel-overlay.el" "rudel-speedbar.el" "rudel-operators.el" "rudel-operations.el" "rudel-compat.el" "rudel-tls.el" "rudel-errors.el" "rudel-state-machine.el" "rudel-backend.el" "rudel-protocol.el" "rudel-session-initiation.el" "rudel-icons.el" "rudel-hooks.el" "rudel-transport.el" "rudel-chat.el")
+ )
+ )
+ :mailinglist "rudel-devel@lists.sourceforge.net"
+ :web-site-url "http://rudel.sourceforge.net/"
+ :web-site-directory "/scymtym,rudel@web.sourceforge.net:/home/groups/r/ru/rudel/htdocs"
+ :configuration-variables 'nil
+ )
diff --git a/emacs.d/lisp/rudel/.svn/text-base/README.svn-base b/emacs.d/lisp/rudel/.svn/text-base/README.svn-base
new file mode 100644
index 0000000..aeacba7
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/README.svn-base
@@ -0,0 +1,88 @@
+* INTRODUCTION
+
+ Rudel is collaborative editing environment for GNU Emacs. Its
+ purpose is to share buffers with other users in order to edit the
+ contents of those buffers collaboratively. Rudel supports multiple
+ backends to enable communication with other collaborative editors
+ using different protocols, though currently Obby (for use with the
+ Gobby editor) is the only fully-functional one.
+
+ Since Rudel is not an application, but an extension to Emacs, it is
+ not started and used like most applications (not even Emacs
+ applications like Gnus). Rudel mostly works in the background to
+ change the behavior of the set of Emacs buffers for which it has
+ been activated.
+
+ The user interface consists of a set of key bindings, a menu entry
+ and some visual status indicators, which are added to the text and
+ mode line of buffers for which Rudel has been activated.
+
+* GETTING STARTED
+
+ Assuming Rudel has already been installed and auto loading has been
+ set up, a global Rudel mode can be enabled as follows:
+
+ : M-x global-rudel-minor-mode
+
+ This will enabled Rudel's key bindings and menu entry.
+
+** JOINING A SESSION
+
+ : M-x rudel-join-session [ C-c c j ]
+
+ Depending on the installed Rudel backends, system environment and
+ configuration, a number of questions will be asked, followed by an
+ attempt to join session described by your answers.
+
+ A typical example of the questions asked when joining a session may
+ look like this:
+
+ Server: localhost RET
+ Port (default 6522): RET
+ Username: jan RET
+ Color: light sky blue RET
+ Use Encryption (y or n): n RET
+ Global Password: RET
+ User Password: RET
+
+ IMPORTANT: For sessions using the obby backend (like in the example
+ above), the following restriction has to be taken into account:
+ + When the server is Rudel inside an Emacs process:
+ Encryption cannot be used currently in this case. Consequently
+ the answer to the `Use Encryption (y or n):' prompt above has to
+ be `n RET'.
+ + When the server is a Gobby process:
+ Gobby only supports encrypted connections. So the answer has to
+ be `y RET' is this case.
+
+ It is possible to configure frequently used sessions using the
+ customization options `rudel-configured-sessions'. When one or more
+ sessions are configured, `rudel-join-session' will provide choices
+ like "my-configured-session", ... and "ask-protocol". Selecting
+ "ask-protocol" invokes the behavior described above. Selecting one
+ of the configured sessions connects to that session without asking
+ for all the data.
+
+** HOSTING A SESSION
+
+ : M-x rudel-host-session [ C-c c h ]
+
+ Note that the session starts out without any participating users
+ (This is sometimes referred to as being a dedicated server). If you
+ want to participate in the session you host, you have to join it as
+ described above.
+
+* KNOWN ISSUES
+
+ + Publishing eshell buffers will cause your session to be
+ disconnected since eshell disables the hooks that Rudel uses to
+ catch changes to the buffer. As a workaround, you can use M-x
+ ansi-term or another terminal emulator.
+
+* LICENSE
+
+ Rudel is licensed under the same terms as GNU Emacs.
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/.svn/text-base/TODO.svn-base b/emacs.d/lisp/rudel/.svn/text-base/TODO.svn-base
new file mode 100644
index 0000000..e5e4bf4
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/TODO.svn-base
@@ -0,0 +1,436 @@
+* Future
+** NEW Handle messages spanning multiple frames
+ + Component :: beep-transport
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** NEW Operation log can grow beyond all bounds (#37)
+ + Component :: obby-general
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ When no remote operations are received, the log of local operation
+ is not reset and therefore grows beyond all bounds.
+** NEW Terminating sessions does not work (#47)
+ + Component :: rudel-general
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ There is a menu entry for terminating sessions which are hosted by
+ Rudel, but it does not do anything.
+** NEW Rename document message is not understood (#7)
+ + Component :: obby-client
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** NEW Rename document message is not understood (#8)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** TODO Notification mechanism
+ + Component :: user-interface
+ + Type :: task
+ + Reporter :: jan
+ + Type :: task
+ + Assigned ::
+** TODO SubEthaEdit client functionality
+ + Component :: subethaedit-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Show cursor positions of other users (#5)
+ + Component :: rudel-user-interface
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Some kind of server log buffer (#11)
+ + Component :: rudel-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ It would be nice to log server events. This could be done in a
+ separate buffer or using a dedicated mechanism like
+ rudel-notification.
+** TODO Backends should be able to offer additional menu items (#14)
+ + Component :: rudel-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Obby session can be protected by passwords (#15)
+ + Component :: obby-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Obby users can protect their accounts with passwords (#16)
+ + Component :: obby-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ The Gobby implementation is in obby/inc/server_buffer.hpp:851
+** TODO Zeroconf session notification (#52)
+ + Component :: zeroconf
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+ Watch interesting Zeroconf services and use `rudel-notify` if new
+ services are discovered
+** TODO State machine diagram (#59)
+ + Component :: obby-client
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO State machine diagram (#60)
+ + Component :: obby-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Send key presses as chat messages (#61)
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: Jan
+ + Assigned ::
+ Sending key presses as chat messages could be really useful for
+ somebody something using rudel.
+** STARTED BEEP transport
+ + Component :: beep-transport
+ + Type :: task
+ + Reporter :: jan
+ + Assigned :: jan
+** STARTED Reference manual (#46)
+ + Component :: documentation
+ + Type :: task
+ + Reporter :: jan
+ + Assigned :: jan
+ In addition to the `README`, a proper reference manual would be
+ nice. At some point, complete info documentation may be
+ desirable. Docbook seems to be the best approach since we get (at
+ least):
+ + Pdf
+ + Html
+ + Info
+
+
+* Milestone rudel-0.4
+** TODO Telepathy transport
+ + Component :: telepathy-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+
+* Milestone rudel-0.3
+** TODO Multiple username/password attempts in one login attempt
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Infinote client functionality
+ + Component :: infinote-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Support for trees of documents
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** NEW Get rid of error calls in the server (#58)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ It makes no sense to call `error` when something goes wrong in
+ server code that is called from the process filter. Instead, we
+ should try to recover.
+** NEW Global mode line publish state mode does not work for all new buffers (#55)
+ + Component :: rudel-user-interface
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ `global-mode-line-publish-state-mode` is define using
+ `define-globalized-mode`. This seems to only enabled the associated
+ minor mode for buffers create by `find-file` and after major mode
+ changes. The minor mode is not activated for buffers create by
+ `create-buffer`. Since this is used when subscribing to documents,
+ this is a problem.
+** NEW Handle net6_encryption_info messages (#57)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** TODO Only read color hue, not complete colors (#53)
+ + Component :: rudel-user-interface
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ Taking control over saturation and value away from the user makes
+ it impossible to choose unreadable colors.
+
+
+* Milestone rudel-0.2
+** DONE Use state pattern (#18)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Server buffers go out of sync when multi-byte characters are used (#56)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Terminate connections properly when something goes wrong (#51)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Removing documents does not work (#45)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Search list of offline users when new users log in (#44)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Reference card (#2)
+ + Component :: documentation
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE ode-line indicator of buffer status (#6)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Author overlay face may not exist (#54)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Visualization of user status (#9)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Update overlays when users change colors (#23)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Allow to toggle display of author overlays (#33)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Update file headers (#50)
+ + Component :: documentation
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: trivial
+ + Reporter :: jan
+** DONE Proper Zeroconf support (#21)
+ + Component :: zeroconf
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Add discovery component (#22)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Define initialize-instance with slots or &rest slots? (#49)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** DONE Use oref to get object names (#24)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Overlays should be removed when a buffer is detached from its document (#39)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Unsafe use of (call-next-method) (#48)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Handle `net6_login_failed' message (#10)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Add debug hints to macros (#43)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Use state pattern (#17)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Use with-parsed-arguments (#40)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+
+
+* Milestone rudel-0.1
+** FIXED User names and colors are not checked for conflicts (#12)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Write some html for rudel.sourceforge.net (#27)
+ + Component :: www
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** INVALID Repeated publishing leads to multiple document instances (#30)
+ + Component :: obby-backend
+ + Resolution :: invalid
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Document suffixes are not handled properly (#42)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Fix license texts (#32)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: trivial
+ + Reporter :: jan
+** WONTFIX Overlays break on last character (#29)
+ + Component :: rudel-user-interface
+ + Resolution :: worksforme
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Encodings are not handled in obby backend (#1)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Major mode changes break subscribed buffers (#19)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Editing in overwrite mode breaks synchronization (#35)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Yanking produces insertion and immediate deletion of the region (#36)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Documents with identical names but distinct suffixes map to same buffer (#41)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Killing a buffer does not detach it from its document (#38)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** INVALID Rudel client crashes Gobby (#25)
+ + Component :: obby-general
+ + Resolution :: invalid
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Add screenshot of session with Gobby (#20)
+ + Component :: www
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: trivial
+ + Reporter :: jan
+** DONE Replace 't with t (#34)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Operations of type jupiter-compound cannot be applied to buffers
+ (#31)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Do not sync any chunks when buffer is empty (#28)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Implement Jupiter algorithm (#13)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: major
+ + Reporter :: jan
+** DONE Replace email address (#26)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Mark contributions using overlays (#4)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: major
+ + Reporter :: jan
+** FIXED When a user leaves and joins a second user object is created (#3)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-backend.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-backend.el.svn-base
new file mode 100644
index 0000000..79cfef6
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-backend.el.svn-base
@@ -0,0 +1,305 @@
+;;; rudel-backend.el --- A generic backend management mechanism for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, factory
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a generic mechanism that handles registration,
+;; query and instantiation of Rudel backends for any number of
+;; functional categories.
+;;
+;; The class and collaboration design is as follows: for each
+;; category, which is identified by a symbol, there is a factory
+;; object (an instance of `rudel-backend-factory') that is responsible
+;; for creating backend objects of the category. Examples of
+;; categories are 'transport', 'protocol' and 'session-initiation'.
+;; In addition to creating backend object, factories also allow
+;; querying backends based on desired capabilities and load backend
+;; implementations only when required.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+
+;;; Class rudel-backend
+;;
+
+(defclass rudel-backend ()
+ ((version :initarg :version
+ :type list
+ :documentation
+ "A list of the form (MAJOR MINOR [MICRO
+WHATEVER*]) describing the version of the backend.")
+ (capabilities :initarg :capabilities
+ :type list
+ :initform nil
+ :documentation
+ "A list of symbols, or lists whose car is a
+symbol, that each describe one capability of the backend."))
+ "Base class for backend classes."
+ :abstract t)
+
+(defmethod rudel-capable-of-p ((this rudel-backend) capability)
+ "Return t if the backend THIS is capable of CAPABILITY."
+ (with-slots (capabilities) this
+ (member capability capabilities)))
+
+
+;;; Class rudel-backend-factory
+;;
+
+(defclass rudel-backend-factory ()
+ ((backends :initarg :backends
+ :type hash-table
+ :documentation
+ "Mapping of symbolic names to classes (prior to
+instantiation) or objects (after instantiation) for all backends
+known to the factory object.")
+ (factories :type hash-table
+ :allocation :class
+ :documentation
+ "Mapping of backend categories to responsible
+factory objects."))
+ "Factory class that holds an object for each known backend
+category. Objects manage backend implementation for one backend
+category each.")
+(oset-default rudel-backend-factory factories
+ (make-hash-table :test #'eq))
+
+(defmethod initialize-instance ((this rudel-backend-factory) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+ (oset this :backends (make-hash-table :test #'eq)))
+
+;;;###autoload
+(defmethod rudel-get-factory :static ((this rudel-backend-factory)
+ category)
+ "Return the factory responsible for CATEGORY.
+If there is no responsible factory, create one and return it."
+ (with-slots (factories) this
+ (or (gethash category factories)
+ (puthash category (rudel-backend-factory category) factories)))
+ )
+
+;;;###autoload
+(defmethod rudel-add-backend ((this rudel-backend-factory)
+ name class &optional replace)
+ "Add factory class CLASS with name NAME to THIS.
+if REPLACE is non-nil, replace a registered implementation of the
+same name."
+ (with-slots (backends) this
+ (when (or (not (gethash name backends))
+ replace)
+ (puthash name class backends))))
+
+(defmethod rudel-get-backend ((this rudel-backend-factory) name)
+ "Return backend object for name NAME or nil if there is none.
+The returned backend is of the form (NAME . OBJECT).
+
+Backends are loaded, if necessary."
+ ;; Load all available backends
+ (rudel-load-backends this)
+
+ ;; Find the backend and return it.
+ (with-slots (backends) this
+ (let ((backend (gethash name backends)))
+ (when backend
+ (cons name backend))))
+ )
+
+(defmethod rudel-all-backends ((this rudel-backend-factory))
+ "Return a list of all backends registered with THIS.
+Each list element is of the form (NAME . CLASS-OR-OBJECT)."
+ (let ((backend-list))
+ (with-slots (backends) this
+ (maphash (lambda (name class)
+ (push (cons name class) backend-list))
+ backends))
+ backend-list)
+ )
+
+(defmethod rudel-suitable-backends ((this rudel-backend-factory) predicate)
+ "Return a list of backends which satisfy PREDICATE.
+Each list element is of the form (NAME . OBJECT).
+Backends are loaded, if necessary."
+ ;; Load all available backends
+ (rudel-load-backends this)
+
+ ;; Retrieve and return all backends, possibly filtering the list
+ ;; using PREDICATE.
+ (if predicate
+ (remove-if-not
+ (lambda (cell)
+ (and (object-p (cdr cell))
+ (funcall predicate (cdr cell))))
+ (rudel-all-backends this))
+ (rudel-all-backends this))
+ )
+
+(defmethod rudel-load-backends ((this rudel-backend-factory))
+ "Load backends in THIS factory if necessary.
+Loading errors are not reported explicitly, but can be detected
+by checking for backends that still are classes rather than
+objects."
+ ;; Map lambda that loads unloaded backends over all backends. Store
+ ;; objects back after loading.
+ (with-slots (backends) this
+ (maphash
+ (lambda (name class)
+ (unless (object-p class)
+ (condition-case error
+ (puthash name (make-instance
+ class (symbol-name name)) backends)
+ (error (display-warning
+ '(rudel backend)
+ (format "Could not load backend `%s': %s"
+ name
+ (error-message-string error))
+ :warning)))))
+ backends))
+ )
+
+
+;;; High-level frontend functions
+;;
+
+(defsubst rudel-backend-cons-p (cell)
+ "Check whether CELL is a cons of a backend name and object."
+ (and (consp cell)
+ (symbolp (car cell))
+ (object-p (cdr cell))))
+
+;;;###autoload
+(defun rudel-backend-get (category name)
+ "A shortcut for getting backend NAME of category CATEGORY.
+The returned backend is of the form (NAME . OBJECT)."
+ (rudel-get-backend (rudel-backend-get-factory category) name))
+
+;;;###autoload
+(defun rudel-backend-get-factory (category)
+ "A shortcut for getting the factory object for CATEGORY."
+ (rudel-get-factory rudel-backend-factory category))
+
+(defun rudel-backend-suitable-backends (category predicate)
+ "Return backends from category CATEGORY that satisfy PREDICATE.
+Each list element is of the form (NAME . OBJECT)."
+ (rudel-suitable-backends
+ (rudel-backend-get-factory category)
+ predicate))
+
+(defun rudel-backend-choose (category &optional predicate)
+ "Choose a backend from CATEGORY satisfying PREDICATE automatically or by asking the user.
+The returned backend is of the form (NAME . CLASS-OR-OBJECT)."
+ (let ((backends (rudel-backend-suitable-backends
+ category predicate)))
+ (unless backends
+ (error "No backends available"))
+
+ (if (= (length backends) 1)
+ ;; If there is only one backend, we can choose that one right
+ ;; away displaying a message to avoid confusing the user.
+ (let ((backend (nth 0 backends)))
+ (message "Using backend `%s'" (symbol-name (car backend)))
+ (sit-for 0.5)
+ backend)
+
+ ;; When we have more than one backend, we have to ask the user,
+ ;; which one she wants.
+ (require 'rudel-interactive)
+ (rudel-read-backend backends nil 'object)))
+ )
+
+
+;;; User interaction functions
+;;
+
+(defun rudel-backend-dump (&optional load)
+ "Create display information about backends in a buffer.
+If LOAD is non-nil, load all backends before display. This makes
+available information available for the backends"
+ (interactive "p")
+ (save-excursion
+ ;; Setup a new buffer.
+ (set-buffer (get-buffer-create "*Rudel Backends*"))
+ (erase-buffer)
+ (set-window-buffer nil (current-buffer))
+ (maphash
+ (lambda (category factory)
+ ;; Load backends if requested.
+ (unless (zerop load)
+ (rudel-load-backends factory))
+
+ ;; Insert header for this category.
+ (insert (propertize
+ (format "Category %s\n" category)
+ 'face 'bold))
+ (insert (apply #'format
+ " %-20s %-6s %-7s %s\n"
+ (mapcar
+ (lambda (header)
+ (propertize header 'face 'italic))
+ '("name" "loaded" "version" "capabilities"))))
+
+ ;; Insert all backends provided by this factory.
+ (dolist (backend (rudel-all-backends factory))
+ (insert (format " %-20s %-6s %-7s (%s)\n"
+ (propertize
+ (symbol-name (car backend))
+ 'face 'font-lock-type-face)
+ (propertize
+ (prin1-to-string (object-p (cdr backend)))
+ 'face 'font-lock-variable-name-face)
+ (propertize
+ (if (object-p (cdr backend))
+ (mapconcat #'prin1-to-string
+ (oref (cdr backend) :version)
+ ".")
+ "?")
+ 'face 'font-lock-constant-face)
+ (propertize
+ (if (object-p (cdr backend))
+ (mapconcat #'prin1-to-string
+ (oref (cdr backend) :capabilities)
+ " ")
+ "?")
+ 'face 'font-lock-constant-face))))
+
+ ;; One empty line between backend categories.
+ (insert "\n"))
+ (oref rudel-backend-factory factories)))
+ )
+
+(provide 'rudel-backend)
+;;; rudel-backend.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-chat.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-chat.el.svn-base
new file mode 100644
index 0000000..c7e992f
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-chat.el.svn-base
@@ -0,0 +1,103 @@
+;;; rudel-chat.el --- Handling of chat messages
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, chat, message
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains some functions that deal with incoming chat
+;; messages. Backends that support receiving chat message should
+;; dispatch them using `rudel-chat-dispatch-message'. Chat messages
+;; will be processed in a customizable way from there.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+
+;;; Customization
+;;
+
+(defcustom rudel-chat-handler-function #'rudel-chat-handle-buffer
+ "A function that is called when chat messages arrive."
+ :group 'rudel
+ :type '(choice (const :tag "Display messages in the echo area"
+ rudel-chat-handle-message)
+ (const :tag "Log messages into a buffer"
+ rudel-chat-handle-buffer)
+ (function :tag "Other function"))
+ )
+
+
+;;; Variables and constants
+;;
+
+(defconst rudel-chat-buffer-name "*rudel-chat-log*"
+ "Name of the buffer into which received chat message should be
+inserted.")
+
+
+;;; Interface functions
+;;
+
+(defun rudel-chat-dispatch-message (sender message)
+ "Dispatch SENDER and MESSAGE to customizable handler function."
+ (funcall rudel-chat-handler-function sender message))
+
+
+;;; Handler functions
+;;
+
+(defun rudel-chat-handle-message (sender text)
+ "Display SENDER and MESSAGE in the echo area."
+ (message "%s says: %s"
+ (rudel-chat-format-sender sender)
+ text))
+
+(defun rudel-chat-handle-buffer (sender text)
+ "Insert SENDER and MESSAGE in a buffer."
+ (let ((buffer (or (get-buffer rudel-chat-buffer-name)
+ (pop-to-buffer rudel-chat-buffer-name))))
+ (with-current-buffer buffer
+ (goto-char (point-min))
+ (insert (format "%s: %s\n"
+ (rudel-chat-format-sender sender)
+ text))))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-chat-format-sender (user)
+ "Format USER handling nil values."
+ (if user
+ (object-name-string user)
+ "<unknown sender>"))
+
+(provide 'rudel-chat)
+;;; rudel-chat.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-compat.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-compat.el.svn-base
new file mode 100644
index 0000000..630496c
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-compat.el.svn-base
@@ -0,0 +1,158 @@
+;;; rudel-compat.el --- Compatibility code for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;; Copyright (C) 2009 Phil Hagelberg
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Phil Hagelberg <phil@enigma>
+;; Keywords: rudel, compatibility
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains compatibility code required to make Rudel work
+;; with different versions of Emacs.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(unless (fboundp 'read-color)
+ (defun read-color (prompt &rest ignored)
+ "Poor man's read color without completion.
+You have to take care to only enter valid color names."
+ (read-string prompt)))
+
+
+;;; Spinner Progress Reporter
+;;
+
+(unless (functionp 'progress-reporter-spin)
+ (defvar progress-spinner-values ["-" "\\" "|" "/"])
+
+ (defsubst progress-reporter-update (reporter &optional value)
+ "Report progress of an operation in the echo area.
+
+The first parameter, REPORTER, should be the result of a call to
+`make-progress-reporter'. For reporters for which the max value
+is known, the second argument determines the actual progress of
+operation; it must be between MIN-VALUE and MAX-VALUE as passed
+to `make-progress-reporter'.
+
+However, if the change since last echo area update is too small
+or not enough time has passed, then do nothing (see
+`make-progress-reporter' for details).
+
+In this case, this function is very inexpensive, you need not
+care how often you call it."
+ (if (progress-reporter-spinner-p reporter)
+ (progress-reporter-spin reporter)
+ (when (>= value (car reporter))
+ (progress-reporter-do-update reporter value))))
+
+ (defun make-progress-reporter (message &optional min-value max-value
+ current-value min-change min-time)
+ "Return progress reporter object to be used with `progress-reporter-update'.
+
+MESSAGE is shown in the echo area. When at least 1% of operation
+is complete, the exact percentage will be appended to the
+MESSAGE. When you call `progress-reporter-done', word \"done\"
+is printed after the MESSAGE. You can change MESSAGE of an
+existing progress reporter with `progress-reporter-force-update'.
+
+If provided, MIN-VALUE and MAX-VALUE designate starting (0%
+complete) and final (100% complete) states of operation. The
+latter should be larger; if this is not the case, then simply
+negate all values. Optional CURRENT-VALUE specifies the progress
+by the moment you call this function. You should omit it or set
+it to nil in most cases since it defaults to MIN-VALUE.
+
+Optional MIN-CHANGE determines the minimal change in percents to
+report (default is 1%.) Optional MIN-TIME specifies the minimal
+time before echo area updates (default is 0.2 seconds.) If
+`float-time' function is not present, then time is not tracked
+at all. If OS is not capable of measuring fractions of seconds,
+then this parameter is effectively rounded up.
+
+If MIN-VALUE and MAX-VALUE are unknown, they may be omitted to
+return a \"pulsing\" progress reporter."
+ (unless min-time
+ (setq min-time 0.2))
+ (let ((reporter
+ (cons min-value ;; Force a call to `message' now
+ (vector (if (and (fboundp 'float-time)
+ (>= min-time 0.02))
+ (float-time) nil)
+ (or min-value 0)
+ max-value
+ message
+ (if min-change (max (min min-change 50) 1) 1)
+ min-time))))
+ (progress-reporter-update reporter (or current-value min-value))
+ reporter))
+
+ (defun progress-reporter-force-update (reporter &optional value new-message)
+ "Report progress of an operation in the echo area unconditionally.
+
+First two parameters are the same as for
+`progress-reporter-update'. Optional NEW-MESSAGE allows you to
+change the displayed message."
+ (let ((parameters (cdr reporter)))
+ (when new-message
+ (aset parameters 3 new-message))
+ (when (aref parameters 0)
+ (aset parameters 0 (float-time)))
+ (if (progress-reporter-spinner-p reporter)
+ (progress-reporter-spin reporter)
+ (progress-reporter-do-update reporter value))))
+
+ (defun progress-reporter-spinner-p (reporter)
+ "Return t if REPORTER has an unknown max value."
+ (null (aref (cdr reporter) 2)))
+
+ (defun progress-reporter-spin (reporter)
+ "Advance indicator of spinning REPORTER."
+ (let* ((parameters (cdr reporter))
+ (index (+ (aref parameters 1) 1)))
+ (aset parameters 1 index)
+ (let ((message-log-max nil)) ; No logging
+ (message "%s %s"
+ (aref progress-spinner-values (mod index 4))
+ (aref parameters 3))))))
+
+(unless (functionp 'string-match-p)
+ (defsubst string-match-p (regexp string &optional start)
+ "Same as `string-match' except this function does not change the match data"
+ (let ((inhibit-changing-match-data t))
+ (string-match regexp string start))))
+
+(defun rudel-get-coding-system (name)
+ (if (functionp 'coding-system-from-name)
+ (coding-system-from-name name)
+ ;; May need to try a little harder here for Emacs 22 depending on
+ ;; what kind of encoding names are given us.
+ (intern name)))
+
+(provide 'rudel-compat)
+;;; rudel-compat.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-compile.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-compile.el.svn-base
new file mode 100644
index 0000000..aeba765
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-compile.el.svn-base
@@ -0,0 +1,46 @@
+;;; rudel-compile.el --- Byte-compile Rudel
+;;
+;; Copyright (C) 2009 Phil Hagelberg
+;;
+;; Author: Phil Hagelberg <phil@enigma>
+;; Keywords: Rudel, compile
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Press M-x eval-buffer to byte-compile Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(let ((rudel-dir (file-name-directory
+ (or (buffer-file-name) load-file-name))))
+ ;; Adjust load path for compilation.
+ (dolist (dir '("." "jupiter" "obby" "zeroconf"))
+ (let ((d (concat rudel-dir "/" dir)))
+ (add-to-list 'load-path d)))
+
+ ;; Byte compile everything.
+ (byte-recompile-directory rudel-dir 0))
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-debug.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-debug.el.svn-base
new file mode 100644
index 0000000..747bf68
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-debug.el.svn-base
@@ -0,0 +1,215 @@
+;;; rudel-debug.el --- Debugging functions for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, debugging
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Debugging functions for Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'data-debug)
+(require 'eieio-datadebug)
+
+(require 'rudel-util)
+
+
+;;; Customization
+;;
+
+(defgroup rudel-debug nil
+ "Customization options related to Rudel's debugging functions."
+ :group 'rudel)
+
+(defface rudel-debug-sent-data-face
+ '((default (:background "orange")))
+ "Face used for sent data."
+ :group 'rudel-debug)
+
+(defface rudel-debug-received-data-face
+ '((default (:background "light sky blue")))
+ "Face used for received (but not yet processed) data."
+ :group 'rudel-debug)
+
+(defface rudel-debug-received-processed-data-face
+ '((default (:background "DeepSkyBlue1")))
+ "Face used for received data after processing."
+ :group 'rudel-debug)
+
+(defface rudel-debug-state-face
+ '((default (:background "light gray")))
+ "Face used when indicating state changes."
+ :group 'rudel-debug)
+
+(defface rudel-debug-special-face
+ '((default (:background "light sea green")))
+ "Face used for additional information."
+ :group 'rudel-debug)
+
+(defvar rudel-debug-tag-faces
+ '((:sent . (rudel-debug-sent-data-face "< "))
+ (:received . (rudel-debug-received-data-face "> "))
+ (:received-processed . (rudel-debug-received-processed-data-face ">> "))
+ (:state . (rudel-debug-state-face "| "))
+ (:special . (rudel-debug-special-face "; ")))
+ "Associate tag to faces and prefixes.")
+
+
+;;; Data debug functions
+;;
+
+(defun rudel-adebug-session ()
+ "Analyze current session in data debug buffer."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-current-buffer (data-debug-new-buffer "RUDEL-SESSION")
+ (data-debug-insert-thing rudel-current-session "# " "")))
+
+(defun rudel-adebug-server (server)
+ "Analyze server in data debug buffer."
+ (interactive)
+
+ (with-current-buffer (data-debug-new-buffer "RUDEL-SERVER")
+ (data-debug-insert-thing server "# " "")))
+
+
+;;; Advice stuff
+;;
+
+(defadvice rudel-join-session (after rudel-debug last activate)
+ "Run data-debug inspection on newly created session objects."
+ (require 'rudel-debug)
+ (rudel-adebug-session))
+
+(defadvice rudel-host-session (after rudel-debug last activate)
+ "Run data-debug inspection on newly created server objects."
+ (require 'rudel-debug)
+ (rudel-adebug-server ad-return-value))
+
+
+;;; Network functions
+;;
+
+(defun rudel-suspend-session-socket ()
+ "Suspend the socket associated to the current session."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (connection) rudel-current-session
+ (with-slots (socket) connection
+ (stop-process socket))))
+
+(defun rudel-resume-session-socket ()
+ "Resume the socket associated to the current session."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (connection) rudel-current-session
+ (with-slots (socket) connection
+ (continue-process socket))))
+
+
+;;; Reset functions
+;;
+
+(defun rudel-kill-processes ()
+ "TODO"
+ (interactive)
+ (mapc #'delete-process (process-list)))
+
+(defun rudel-reset ()
+ "TODO"
+ (interactive)
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-buffer-document
+ (setq rudel-buffer-document nil))))
+ (rudel-kill-processes)
+ (setq rudel-current-session nil))
+
+
+;;; Socket debugging
+;;
+
+(defmethod rudel-state-change :before ((this rudel-socket-owner)
+ state message)
+ "Print STATE and MESSAGE to debug stream."
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :state
+ (format "connection state changed to %s: \"%s\""
+ (upcase (symbol-name state))
+ ;; MESSAGE ends with a newline; remove it
+ (substring message 0 -1))))
+ )
+
+
+;;; Utility functions
+;;
+
+(defun rudel-debug-stream-name (socket)
+ "Return debug stream name for SOCKET."
+ (process-name socket))
+
+(defun rudel-debug-stream-insert (stream tag data &optional object)
+ "Insert DATA and possibly OBJECT into stream using TAG as style."
+ (let* ((buffer-name (format "*%s stream*" stream))
+ (buffer (or (get-buffer buffer-name)
+ (data-debug-new-buffer buffer-name)))
+ (appearance (cdr (assoc tag rudel-debug-tag-faces)))
+ (face (when appearance
+ (or (nth 0 appearance)
+ 'default)))
+ (prefix (or (nth 1 appearance)
+ "")))
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char 0)
+ (insert prefix
+ (propertize data 'face face)
+ (if (string= (substring data -1) "\n")
+ "" "\n"))
+ (when object
+ (data-debug-insert-thing object prefix ""))))
+ )
+
+(provide 'rudel-debug)
+;;; rudel-debug.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-errors.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-errors.el.svn-base
new file mode 100644
index 0000000..9811511
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-errors.el.svn-base
@@ -0,0 +1,66 @@
+;;; rudel-errors.el --- Error data used in Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, errors, conditions
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; The following condition hierarchy is defined:
+;;
+;; error
+;; +- rudel-error
+;; +- rudel-join-error
+;; +- rudel-host-error
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+;; rudel-join-error
+
+(intern "rudel-join-error")
+
+(put 'rudel-join-error 'error-conditions
+ '(error
+ rudel-error rudel-join-error))
+
+(put 'rudel-join-error 'error-message
+ "Could not join session")
+
+;; rudel-host-error
+
+(intern "rudel-host-error")
+
+(put 'rudel-host-error 'error-conditions
+ '(error
+ rudel-error rudel-host-error))
+
+(put 'rudel-host-error 'error-message
+ "Could not host session")
+
+(provide 'rudel-errors)
+;;; rudel-errors.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-hooks.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-hooks.el.svn-base
new file mode 100644
index 0000000..0cc9a3e
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-hooks.el.svn-base
@@ -0,0 +1,252 @@
+;;; rudel-hooks.el --- Hooks for Rudel events
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, hook
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains all global hooks (as opposed to hooks provided
+;; by individual objects) provided by Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+
+;;; Hook variables
+;;
+
+(defvar rudel-session-start-hook nil
+ "This hook is run when a new session is started.
+The only argument is the session object.")
+
+(defvar rudel-session-end-hook nil
+ "This hook is run when a session ends.
+The only argument is the session object.")
+
+(defvar rudel-session-add-user-hook nil
+ "This hook is run when a user is added to a session.
+The arguments are the session and the user.")
+
+(defvar rudel-session-remove-user-hook nil
+ "This hook is run when a user is removed from a session.
+The arguments are the session and the user.")
+
+(defvar rudel-session-add-document-hook nil
+ "This hook is run when a document is added to a session.
+The arguments are the session and the document.")
+
+(defvar rudel-session-remove-document-hook nil
+ "This hook is run when a document is removed from a session.
+The arguments are the session and the document.")
+
+
+(defvar rudel-user-change-hook nil
+ "This hooks is run when a user object changes.
+The only argument is the user object.")
+
+
+(defvar rudel-document-attach-hook nil
+ "This hook is run when a document is attached to a buffer.
+The arguments are the document and the buffer.")
+
+(defvar rudel-document-detach-hook nil
+ "This hook is run when document is detached from its buffer.
+The arguments are the document and the buffer.")
+
+
+;;; Handlers
+;;
+
+(defun rudel-hooks--session-start (session)
+ "Watch SESSION for added/removed users and documents."
+ ;; Install handlers for the hooks of the session.
+ (with-slots (users documents) session
+
+ ;; Watch for session end.
+ (object-add-hook session 'end-hook
+ #'rudel-hooks--session-end)
+
+ ;; Watch all users in the session.
+ (dolist (user users)
+ (rudel-hooks--session-add-user session user))
+
+ ;; Watch session for added/removed users.
+ (object-add-hook
+ session 'add-user-hook
+ #'rudel-hooks--session-add-user)
+ (object-add-hook
+ session 'remove-user-hook
+ #'rudel-hooks--session-remove-user)
+
+ ;; Watch all documents in the session.
+ (dolist (document documents)
+ (rudel-hooks--session-add-document session document))
+
+ ;; Watch session for added/removed documents.
+ (object-add-hook
+ session 'add-document-hook
+ #'rudel-hooks--session-add-document)
+ (object-add-hook
+ session 'remove-document-hook
+ #'rudel-hooks--session-remove-document))
+ )
+
+(defun rudel-hooks--session-end (session)
+ "Stop watching SESSION for added/removed users and documents."
+ ;; Remove handlers from the session.
+ (with-slots (users documents) session
+
+ ;; Stop watching for session end.
+ (object-remove-hook session 'end-hook
+ #'rudel-hooks--session-end)
+
+ ;; Stop watching all users in the session.
+ (dolist (user users)
+ (rudel-hooks--session-remove-user session user))
+
+ ;; Stop watching session for added/removed users.
+ (object-remove-hook
+ session 'add-user-hook
+ #'rudel-hooks--session-add-user)
+ (object-remove-hook
+ session 'remove-user-hook
+ #'rudel-hooks--session-remove-user)
+
+ ;; Stop watching all documents in the session.
+ (dolist (document documents)
+ (rudel-hooks--session-remove-document session document))
+
+ ;; Stop watching session for added/removed documents.
+ (object-remove-hook
+ session 'add-document-hook
+ #'rudel-hooks--session-add-document)
+ (object-remove-hook
+ session 'remove-document-hook
+ #'rudel-hooks--session-remove-document))
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-end-hook session)
+ )
+
+(defun rudel-hooks--session-add-user (session user)
+ "Watch USER for changes and run `rudel-session-add-user-hook'."
+ ;; Watch USER.
+ (object-add-hook user 'change-hook #'rudel-hooks--user-change)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-add-user-hook session user))
+
+(defun rudel-hooks--session-remove-user (session user)
+ "Stop watching USER and run `rudel-session-remove-user-hook'"
+ ;; Stop watching USER.
+ (object-remove-hook user 'change-hook #'rudel-hooks--user-change)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-remove-user-hook
+ session user))
+
+(defun rudel-hooks--session-add-document (session document)
+ "Watch DOCUMENT and run `rudel-session-add-document-hook'."
+ ;; Watch document for attach/detach.
+ (object-add-hook document 'attach-hook
+ #'rudel-hooks--document-attach)
+ (object-add-hook document 'detach-hook
+ #'rudel-hooks--document-detach)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-add-document-hook
+ session document)
+ )
+
+(defun rudel-hooks--session-remove-document (session document)
+ "Stop watching DOCUMENT and run `rudel-session-remove-document-hook'."
+ ;; Stop watching DOCUMENT for attach/detach.
+ (object-remove-hook
+ document 'attach-hook #'rudel-hooks--document-attach)
+ (object-remove-hook
+ document 'detach-hook #'rudel-hooks--document-detach)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-remove-document-hook
+ session document)
+ )
+
+
+(defun rudel-hooks--user-change (user)
+ "Run `rudel-user-change-hook' with argument USER."
+ (run-hook-with-args 'rudel-user-change-hook user))
+
+
+(defun rudel-hooks--document-attach (document buffer)
+ "Run `rudel-document-attach-hook' with arguments DOCUMENT and BUFFER."
+ (run-hook-with-args 'rudel-document-attach-hook
+ document buffer))
+
+(defun rudel-hooks--document-detach (document buffer)
+ "Run `rudel-document-detach-hook' with arguments DOCUMENT and BUFFER."
+ (run-hook-with-args 'rudel-document-detach-hook
+ document buffer))
+
+
+;;; Initialization
+;;
+
+(defun rudel-hooks--install-handlers ()
+ "Install handlers for session start/end."
+ ;; Install handlers for already started sessions.
+ (when (boundp 'rudel-current-session)
+ (mapc
+ #'rudel-hooks--session-start
+ (when rudel-current-session
+ (list rudel-current-session))))
+
+ ;; Watch for session start/end.
+ (add-hook 'rudel-session-start-hook
+ #'rudel-hooks--session-start)
+ )
+
+(defun rudel-hooks--uninstall-handlers ()
+ "Uninstall handlers for session start/end."
+ ;; Stop watching session start/end.
+ (remove-hook 'rudel-session-start-hook
+ #'rudel-hooks--session-start)
+
+ ;; Uninstall handlers for already started sessions.
+ (when (boundp 'rudel-current-session)
+ (mapc
+ #'rudel-hooks--session-end
+ (when rudel-current-session
+ (list rudel-current-session))))
+ )
+
+(rudel-hooks--install-handlers)
+
+(provide 'rudel-hooks)
+;;; rudel-hooks.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-icons.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-icons.el.svn-base
new file mode 100644
index 0000000..9bb35b5
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-icons.el.svn-base
@@ -0,0 +1,90 @@
+;;; rudel-icons.el --- Icons used by Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, icons
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file loads all icons used in Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'image)
+
+
+;;; Image constants
+;;
+
+(defconst rudel-icons-image-formats '(svg png)
+ "Image formats to try (in that order) when loading Rudel icons.")
+
+(defconst rudel-icons-directory
+ (file-name-as-directory
+ (concat (file-name-directory
+ (locate-library "rudel-icons.el"))
+ "icons"))
+ "Directory that holds Rudel icon files.")
+
+
+;;; Helper macro
+;;
+
+(defmacro rudel-defimage (name &optional docstring)
+ "Load image from Rudel icon directory and define image named NAME.
+Optional argument DOCSTRING is the documentation string to
+associate with the image."
+ (declare (doc-string 2))
+ (let ((icon (intern (format "rudel-icon-%s" name)))
+ (specs (mapcar
+ (lambda (type)
+ `(:type ,type
+ :ascent center
+ :mask heuristic
+ :file ,(concat rudel-icons-directory
+ name "." (symbol-name type))))
+ rudel-icons-image-formats)))
+ `(defimage ,icon
+ (,@specs)
+ ,(or docstring
+ (format "%s icon." (capitalize name)))))
+ )
+
+
+;;; Image definitions
+;;
+
+(rudel-defimage "person")
+(rudel-defimage "document")
+(rudel-defimage "connected")
+(rudel-defimage "disconnected")
+(rudel-defimage "plaintext")
+(rudel-defimage "encrypted")
+
+(provide 'rudel-icons)
+;;; rudel-icons.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-interactive.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-interactive.el.svn-base
new file mode 100644
index 0000000..5dda752
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-interactive.el.svn-base
@@ -0,0 +1,181 @@
+;;; rudel-interactive.el --- User interaction functions for Rudel.
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, user, interface, interaction
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Functions for user interactions commonly used in Rudel components.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Function for reading Rudel objects from the user.
+;;
+
+(defun rudel-read-backend (backends &optional prompt return)
+ "Read a backend name from BACKENDS and return that name or the actual backend depending on RETURN.
+If RETURN is 'object, return the backend object which is of the
+form (NAME . CLASS-OR-OBJECT); Otherwise return the name as
+string."
+ (unless prompt
+ (setq prompt "Backend: "))
+ (let* ((backend-names (mapcar (lambda (cell)
+ (symbol-name (car cell)))
+ backends))
+ (backend-name (completing-read prompt backend-names nil t)))
+ (cond
+ ((eq return 'object)
+ (assoc (intern backend-name) backends))
+ (t backend-name)))
+ )
+
+(defun rudel-read-session (sessions &optional prompt return)
+ "Read a session name from SESSIONS and return that name or the session info depending on RETURN.
+If PROMPT is non-nil use as prompt string.
+If RETURN is 'object, return the session object; Otherwise return
+the name as string."
+ (unless prompt
+ (setq prompt "Session: "))
+ ;; For presentation and identification of sessions, use the :name
+ ;; property.
+ (flet ((to-string (session)
+ (if (rudel-backend-cons-p session)
+ (symbol-name (car session))
+ (plist-get session :name))))
+ ;; Read a session by name, then return that name or the
+ ;; corresponding session info.
+ (let ((session-name (completing-read prompt
+ (mapcar #'to-string sessions)
+ nil t)))
+ (cond
+ ((eq return 'object)
+ (find session-name sessions
+ :key #'to-string :test #'string=))
+ (t session-name))))
+ )
+
+(defun rudel-read-user-name ()
+ "Read a username.
+The default is taken from `rudel-default-username'."
+ (read-string "Username: " rudel-default-username))
+
+(defun rudel-read-user-color ()
+ "Read a color."
+ (read-color "Color: " t))
+
+(defun rudel-read-user (&optional users prompt return)
+ "Read a user name from USERS and return that name or the actual user depending on RETURN.
+If USERS is nil, use the user list of `rudel-current-session'.
+If RETURN. is 'object, return the user object; Otherwise return
+the name as string."
+ ;; If no user list is provided, the user list of the current session
+ ;; is used.
+ (unless users
+ (if rudel-current-session
+ (setq users (oref rudel-current-session :users))
+ (error "No user list and no active Rudel session")))
+ (unless prompt
+ (setq prompt "User: "))
+ ;; Construct a list of user name, read a name with completion and
+ ;; return a user name of object.
+ (let* ((user-names (mapcar 'object-name-string users))
+ (user-name (completing-read prompt user-names nil t)))
+ (cond
+ ((eq return 'object)
+ (find user-name users
+ :test 'string= :key 'object-name-string))
+ (t user-name)))
+ )
+
+(defun rudel-read-document (&optional documents prompt return)
+ "Read a document name from DOCUMENTS and return that name or the actual document depending on RETURN.
+If RETURN. is 'object, return the backend object; Otherwise
+return the name as string."
+ (unless documents
+ (if rudel-current-session
+ (setq documents (oref rudel-current-session :documents))
+ (error "No document list and no active Rudel session")))
+ (unless documents
+ (error "No documents")) ; TODO error is a bit harsh
+ (unless prompt
+ (setq prompt "Document: "))
+
+ ;; Construct list of names, read one name and return that name or
+ ;; the named object.
+ (let* ((document-names (mapcar #'rudel-unique-name documents))
+ (document-name (completing-read prompt document-names nil t)))
+ (cond
+ ((eq return 'object)
+ (find document-name documents
+ :test #'string= :key #'rudel-unique-name))
+ (t document-name)))
+ )
+
+
+;;; Buffer allocation functions
+;;
+
+(defun rudel-allocate-buffer-clear-existing (name)
+ "When the requested buffer NAME exists, clear its contents and use it."
+ (let ((buffer (get-buffer name)))
+ (if buffer
+ (progn
+ ;; Ask the user whether it is OK to erase the contents of
+ ;; the buffer.
+ (unless (yes-or-no-p (format
+ "Buffer `%s' already exists; Erase contents? "
+ name))
+ (error "Buffer `%s' already exists" name)) ;; TODO throw or signal; not error
+ ;; When the buffer is attached to a different document, ask
+ ;; whether it is OK to detach the buffer.
+ (let ((document (rudel-buffer-document buffer)))
+ (unless (or (not document)
+ (yes-or-no-p (format
+ "Buffer `%s' is attached to the document `%s'; Detach? "
+ name
+ (rudel-unique-name document))))
+ (error "Buffer `%s' already attached to a document" name)))
+ ;; Delete buffer contents; maybe detach buffer first.
+ (when (rudel-buffer-has-document-p buffer)
+ (rudel-unpublish-buffer buffer))
+ (with-current-buffer buffer
+ (erase-buffer)))
+ (setq buffer (get-buffer-create name)))
+ buffer)
+ )
+
+(defun rudel-allocate-buffer-make-unique (name)
+ "When the requested buffer NAME exists, create another buffer."
+ (get-buffer-create (generate-new-buffer-name name)))
+
+(provide 'rudel-interactive)
+;;; rudel-interactive.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-loaddefs.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-loaddefs.el.svn-base
new file mode 100644
index 0000000..9de8708
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-loaddefs.el.svn-base
@@ -0,0 +1,23 @@
+;;; rudel-loaddefs.el
+
+(autoload 'rudel-join-session "rudel" "Start a collaborative Rudel session" t)
+(autoload 'rudel-host-session "rudel" "Host a collaborative Rudel session" t)
+(autoload 'rudel-speedbar "rudel-speedbar"
+ "Show connected users and documents for the Rudel session in speedbar" t)
+(autoload 'global-rudel-minor-mode "rudel-mode"
+ "Bindings for rudel session-level commands" t)
+
+(global-set-key (kbd "C-c c j") 'rudel-join-session)
+
+(setq rudel-dir (file-name-directory (or (buffer-file-name) load-file-name)))
+
+(dolist (dir '("." "jupiter" "obby" "zeroconf"))
+ (add-to-list 'load-path (concat rudel-dir "/" dir)))
+
+(eval-after-load 'rudel
+ '(progn (global-rudel-minor-mode)
+ (require 'rudel-obby)
+ (when (require 'zeroconf nil t)
+ (require 'rudel-zeroconf))))
+
+(provide 'rudel-loaddefs) \ No newline at end of file
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-mode.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-mode.el.svn-base
new file mode 100644
index 0000000..182188a
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-mode.el.svn-base
@@ -0,0 +1,621 @@
+;;; rudel-mode.el --- Global and buffer-local Rudel minor modes
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, mode
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the following global and buffer-local Rudel
+;; minor modes:
+;;
+;; + `rudel-header-subscriptions-minor-mode': Display subscribed users
+;; and their respective status in the header line
+;; + `rudel-mode-line-publish-state-minor-mode': Display publication
+;; state of buffers in their mode lines
+;; + `global-rudel-minor-mode': Installs a keymap and a Rudel menu
+
+
+;;; History:
+;;
+;; 0.4 - Display buffer publication state in mode line.
+;;
+;; 0.3 - Display subscriptions in header line.
+;;
+;; 0.2 - Use define-minor-mode.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'easy-mmode)
+(require 'easymenu)
+
+(require 'rudel)
+(require 'rudel-hooks)
+
+
+;;; Customization Options
+;;
+
+(defcustom rudel-header-subscriptions-use-images t
+ "Use images when displaying subscribed users in header-line."
+ :group 'rudel
+ :type 'boolean
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-header-subscriptions--options-changed))))
+
+(defcustom rudel-header-subscriptions-separator " "
+ "String used to separate indicator strings of subscribed users."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-header-subscriptions--options-changed))))
+
+(defcustom rudel-mode-line-publish-state-unpublished-string "-"
+ "String used to indicate not published state in the mode line."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-mode-line-publish-state--options-changed))))
+
+(defcustom rudel-mode-line-publish-state-published-string "P"
+ "String used to indicate published state in the mode line."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-mode-line-publish-state--options-changed))))
+
+(dolist (v '(rudel-header-subscriptions-use-images
+ rudel-header-subscriptions-separator
+ rudel-mode-line-publish-state-unpublished-string
+ rudel-mode-line-publish-state-published-string))
+ (put v 'save-local-variable t))
+
+
+;;; Header line subscriptions helper functions
+;;
+
+(defun rudel-header-subscriptions--make-format (document)
+ "Return a Lisp object usable as `header-line-format' generated from DOCUMENT."
+ (with-slots (subscribed) document
+ (mapconcat
+ (lambda (user)
+ (rudel-display-string
+ user rudel-header-subscriptions-use-images))
+ subscribed rudel-header-subscriptions-separator)))
+
+(defun rudel-header-subscriptions--update-from-document (document)
+ "Update header-line of the buffer attached to DOCUMENT."
+ (with-slots (buffer) document
+ (when buffer
+ (with-current-buffer buffer
+ (setq header-line-format
+ (rudel-header-subscriptions--make-format document))
+ (force-mode-line-update)))))
+
+(defun rudel-header-subscriptions--update-from-buffer ()
+ "Update header-line of the current buffer from associated document."
+ (setq header-line-format
+ (when (rudel-buffer-document)
+ (rudel-header-subscriptions--make-format
+ (rudel-buffer-document))))
+ (force-mode-line-update))
+
+(defun rudel-header-subscriptions--options-changed ()
+ "Update headers in buffers that have header subscriptions mode enabled."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-header-subscriptions-minor-mode
+ (rudel-header-subscriptions--update-from-buffer)))))
+
+
+;;; Header line indication of users' status and activities
+;;
+
+(defun rudel-header-subscriptions--user-change (document user)
+ "Update header line after USER changed."
+ ;; Update the header line to reflect the changes to USER.
+ (rudel-header-subscriptions--update-from-document document))
+
+(defun rudel-header-subscriptions--add-user (document user)
+ "Start monitoring USER and update header line."
+ ;; Monitor USER.
+ (lexical-let ((document document))
+ (object-add-hook user 'change-hook
+ (lambda (user)
+ (rudel-header-subscriptions--user-change
+ document user))))
+
+ ;; Update the header line once to get the user added.
+ (rudel-header-subscriptions--update-from-document document)
+ )
+
+(defun rudel-header-subscriptions--remove-user (document user)
+ "Stop monitoring USER and update header line."
+ ;; TODO Stop monitoring USER.
+ ;; (object-remove-hook user 'change-hook
+
+ ;; Update the header line once to get the user removed.
+ (rudel-header-subscriptions--update-from-document document)
+ )
+
+;;;###autoload
+(define-minor-mode rudel-header-subscriptions-minor-mode
+ "Toggle Rudel header subscriptions minor mode.
+
+This mode displays users subscribed to the document associated
+with the buffer in the header-line. Depending on the kind of
+session, additional information like connection status,
+encryption or activity indication may be displayed with each
+user.
+
+If ARG is null, toggle Rudel header subscriptions mode.
+If ARG is a number greater than zero, turn on Rudel header
+subscriptions mode; otherwise, turn it off."
+ :init-value nil
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq rudel-header-subscriptions-minor-mode nil))
+
+ ;; Mode is being enabled and the buffer has an attached document.
+ ((and rudel-header-subscriptions-minor-mode
+ (rudel-buffer-document))
+ (let ((document (rudel-buffer-document)))
+
+ ;; Monitor all users that already are subscribed to the
+ ;; document.
+ (with-slots (subscribed) document
+ (dolist (user subscribed)
+ (rudel-header-subscriptions--add-user document user)))
+
+ ;; Monitor future (un)subscribe events.
+ (object-add-hook document 'subscribe-hook
+ #'rudel-header-subscriptions--add-user)
+ (object-add-hook document 'unsubscribe-hook
+ #'rudel-header-subscriptions--remove-user))
+
+ ;; Update header line.
+ (rudel-header-subscriptions--update-from-buffer))
+
+ ;; Mode is being disabled, but the buffer has an attached document.
+ ((and (not rudel-header-subscriptions-minor-mode)
+ (rudel-buffer-document))
+ (let ((document (rudel-buffer-document)))
+
+ ;; Stop monitoring all users that are subscribed to the
+ ;; document.
+ (with-slots (subscribed) document
+ (dolist (user subscribed)
+ (rudel-header-subscriptions--remove-user document user)))
+
+ ;; Stop monitoring (un)subscribe events.
+ (object-remove-hook document 'subscribe-hook
+ #'rudel-header-subscriptions--add-user)
+ (object-remove-hook document 'unsubscribe-hook
+ #'rudel-header-subscriptions--remove-user))
+
+ ;; Reset header line to default format.
+ (setq header-line-format default-header-line-format)
+ (force-mode-line-update)) ;; TODO remove all handlers
+
+ ;; No buffer document
+ (t
+ ;; Ensure the mode is disabled.
+ (setq rudel-header-subscriptions-minor-mode nil)
+
+ ;; Reset header line to default format.
+ (setq header-line-format default-header-line-format)
+ (force-mode-line-update)))
+ )
+
+
+;;; Global header subscriptions mode
+;;
+
+;; Tracking stuff for the global mode
+
+(defun rudel-header-subscriptions--attach (document buffer)
+ "Activate header subscriptions mode for BUFFER."
+ (with-current-buffer buffer
+ (rudel-header-subscriptions-minor-mode 1)))
+
+(defun rudel-header-subscriptions--detach (document buffer)
+ "Deactivate header subscriptions mode for BUFFER."
+ (with-current-buffer buffer
+ (rudel-header-subscriptions-minor-mode 0)))
+
+(defun rudel-header-subscriptions--add-document (session document)
+ "Watch DOCUMENT for attach/detach events."
+ ;; When document is attached to a buffer, turn the mode on.
+ (with-slots (buffer) document
+ (when buffer
+ (rudel-header-subscriptions--attach document buffer)))
+
+ ;; Watch document for attaching and detaching.
+ (object-add-hook
+ document 'attach-hook #'rudel-header-subscriptions--attach)
+ (object-add-hook
+ document 'detach-hook #'rudel-header-subscriptions--detach))
+
+(defun rudel-header-subscriptions--remove-document (session document)
+ "Stop watching DOCUMENT for attach/detach events."
+ ;; When document is attached to a buffer, turn the mode off.
+ (with-slots (buffer) document
+ (when buffer
+ (rudel-header-subscriptions--detach document buffer)))
+
+ ;; Stop watching document for attaching and detaching.
+ (object-remove-hook
+ document 'attach-hook #'rudel-header-subscriptions--attach)
+ (object-remove-hook
+ document 'detach-hook #'rudel-header-subscriptions--detach))
+
+(defun rudel-header-subscriptions--session-start (session)
+ "Watch SESSION documents and watch for added/removed documents."
+ ;; Watch all documents in the session.
+ (with-slots (documents) session
+ (dolist (document documents)
+ (rudel-header-subscriptions--add-document session document)))
+
+ ;; Watch session for added/removed documents.
+ (object-add-hook
+ session 'add-document-hook
+ #'rudel-header-subscriptions--add-document)
+ (object-add-hook
+ session 'remove-document-hook
+ #'rudel-header-subscriptions--remove-document)
+ )
+
+(defun rudel-header-subscriptions--session-end (session)
+ "Stop watching SESSION for added/removed documents."
+ ;; Stop watching all documents in the session.
+ (with-slots (documents) session
+ (dolist (document documents)
+ (rudel-header-subscriptions--remove-document session document)))
+
+ ;; Stop watching session for added/removed documents.
+ (object-remove-hook
+ session 'add-document-hook
+ #'rudel-header-subscriptions--add-document)
+ (object-remove-hook
+ session 'remove-document-hook
+ #'rudel-header-subscriptions--remove-document)
+ )
+
+;;;###autoload
+(define-globalized-minor-mode global-rudel-header-subscriptions-mode
+ rudel-header-subscriptions-minor-mode
+ rudel-header-subscriptions-minor-mode
+ :group 'rudel)
+
+(defadvice global-rudel-header-subscriptions-mode
+ (around track-subscriptions activate)
+ "Start/stop tracking subscriptions when the mode is (de)activated."
+ (let ((value ad-do-it))
+ (if value
+
+ ;; Add handlers to session start and end hooks and run the
+ ;; start handler on already started sessions.
+ (progn
+
+ ;; Go through all existing sessions.
+ (mapc #'rudel-header-subscriptions--session-start
+ (when rudel-current-session
+ (list rudel-current-session)))
+
+ ;; Watch for new/ended sessions.
+ (add-hook 'rudel-session-start-hook
+ #'rudel-header-subscriptions--session-start)
+ (add-hook 'rudel-session-end-hook
+ #'rudel-header-subscriptions--session-end))
+
+ ;; Remove handlers from session start and end hooks and run the
+ ;; end handler on active sessions.
+ (mapc #'rudel-header-subscriptions--session-end
+ (when rudel-current-session
+ (list rudel-current-session)))
+
+ (remove-hook 'rudel-session-start-hook
+ #'rudel-header-subscriptions--session-start)
+ (remove-hook 'rudel-session-end-hook
+ #'rudel-header-subscriptions--session-end)))
+ )
+
+
+;;; Mode line indication of buffer state
+;;
+
+(defvar rudel-mode-line-publish-state-string
+ (propertize
+ "-"
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is not published")
+ "Contains a mode line fragment indicating the publication state
+of the buffer.")
+(make-variable-buffer-local 'rudel-mode-line-publish-state-string)
+(put 'rudel-mode-line-publish-state-string 'risky-local-variable t)
+
+(defun rudel-mode-line-publish-state--add-indicator-to-mode-line ()
+ "Add Rudel publish state indicator to mode line."
+ (let* ((new-format (copy-list mode-line-format))
+ (format-rest (nthcdr
+ (position 'mode-line-modified mode-line-format)
+ new-format))
+ (format-rest-cdr (cdr format-rest)))
+ (setcdr format-rest (cons 'rudel-mode-line-publish-state-string
+ format-rest-cdr))
+ (setq mode-line-format new-format))
+ (force-mode-line-update))
+
+(defun rudel-mode-line-publish-state--remove-indicator-from-mode-line ()
+ "Remove Rudel publish state indicator from mode line."
+ (let ((format-rest (nthcdr
+ (position 'mode-line-remote mode-line-format)
+ mode-line-format)))
+ ;; Only change the mode line if our indicator is present.
+ (when (eq (second format-rest) 'rudel-mode-line-publish-state-string)
+ (setcdr format-rest (cddr format-rest))
+ (force-mode-line-update))))
+
+(defun rudel-mode-line-publish-state--update-string ()
+ "Update variable `rudel-mode-line-publish-state-string'."
+ ;; Update `rudel-mode-line-publish-state-string' with appropriate
+ ;; propertized indicator string.
+ (setq rudel-mode-line-publish-state-string
+ (cond
+ ((rudel-buffer-document)
+ (propertize
+ rudel-mode-line-publish-state-published-string
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is published"))
+ (t
+ (propertize
+ rudel-mode-line-publish-state-unpublished-string
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is not published"))))
+
+ ;; Update the mode line.
+ (force-mode-line-update)
+ )
+
+(defun rudel-mode-line-publish-state--document-attach (document buffer)
+ "Handle attaching of DOCUMENT to BUFFER.
+When `rudel-mode-line-publish-state-minor-mode' is enabled in
+BUFFER, update the state string."
+ ;; Only act when BUFFER has the minor mode enabled.
+ (with-current-buffer buffer
+ (when rudel-mode-line-publish-state-minor-mode
+ ;; Update the mode line.
+ (rudel-mode-line-publish-state--update-string)
+
+ ;; Watch for detaching of DOCUMENT from BUFFER.
+ (object-add-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)))
+ )
+
+(defun rudel-mode-line-publish-state--document-detach (document buffer)
+ "Handle detaching of DOCUMENT from BUFFER."
+ ;; Update the mode line of BUFFER.
+ (with-current-buffer buffer
+ (rudel-mode-line-publish-state--update-string))
+
+ ;; Stop watching for detaching of DOCUMENT from BUFFER. It (or a
+ ;; different document) has to attach again first, before the next
+ ;; detaching can occur.
+ (object-remove-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)
+ )
+
+(defun rudel-mode-line-publish-state--options-changed ()
+ "Update mode lines in buffers that have mode line publish state mode enabled."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-mode-line-publish-state-minor-mode
+ (rudel-mode-line-publish-state--update-string)))))
+
+;;;###autoload
+(define-minor-mode rudel-mode-line-publish-state-minor-mode
+ "Toggle Rudel mode line publish state minor mode.
+
+This mode displays an indicator of the buffer's state with
+respect to an associated Rudel document in the mode line. If the
+buffer has an attached document, the string \"P\" is displayed
+after the remote file indicator. Otherwise, the string \"-\" is
+displayed.
+
+If ARG is null, toggle Rudel mode line publish state minor mode.
+If ARG is a number greater than zero, turn on Rudel minor mode
+line publish state mode; otherwise, turn it off."
+ :init-value nil
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq rudel-mode-line-publish-state-minor-mode nil))
+
+ ;; Mode is enabled
+ (rudel-mode-line-publish-state-minor-mode
+ ;; Extend and update the mode line, no matter whether the buffer
+ ;; has a document or not.
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line)
+ (rudel-mode-line-publish-state--update-string)
+
+ ;; Watch document, if available or attach events, when a document
+ ;; is not available.
+ (let ((document (rudel-buffer-document)))
+ (if document
+ ;; Handle detaching of the document from the buffer.
+ (object-add-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)
+ ;; Handle attaching of documents to buffers. We use the global
+ ;; hook here, installing the handler twice is prevented by
+ ;; `add-hook'.
+ (add-hook 'rudel-document-attach-hook
+ #'rudel-mode-line-publish-state--document-attach))))
+
+ ;; Mode is disabled
+ (t
+ ;; Maybe stop watching for the document detaching from the buffer.
+ (let ((document (rudel-buffer-document)))
+ (when document
+ (object-remove-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)))
+
+ ;; Remove the indicator from the mode line.
+ (rudel-mode-line-publish-state--remove-indicator-from-mode-line)))
+ )
+
+
+;;; Global mode line publish state mode
+;;
+
+;;;###autoload
+(define-globalized-minor-mode global-rudel-mode-line-publish-state-mode
+ rudel-mode-line-publish-state-minor-mode
+ rudel-mode-line-publish-state-minor-mode
+ :group 'rudel)
+
+
+;;; Global Rudel mode, menu and keymap
+;;
+
+(defvar rudel-minor-keymap
+ (let ((map (make-sparse-keymap))
+ (sub-map (make-sparse-keymap)))
+ ;; Define sub keymap
+ (define-key sub-map "j" #'rudel-join-session)
+ (define-key sub-map "h" #'rudel-host-session)
+ (define-key sub-map "e" #'rudel-end-session)
+
+ (define-key sub-map "c" #'rudel-change-color)
+
+ (define-key sub-map "p" #'rudel-publish-buffer)
+ (define-key sub-map "u" #'rudel-unpublish-buffer)
+ (define-key sub-map "s" #'rudel-subscribe)
+
+ ;; Bind the sub keymap into map
+ (define-key map "\C-cc" sub-map)
+ map)
+ "Keymap used in Rudel minor mode.")
+
+(when rudel-minor-keymap
+ (easy-menu-define
+ rudel-minor-menu rudel-minor-keymap "Rudel Minor Mode Menu"
+ '("Rudel"
+ [ "Join Session" rudel-join-session
+ (not rudel-current-session) ]
+ [ "Leave Session" rudel-end-session
+ rudel-current-session ]
+ "---"
+ [ "Host a Session" rudel-host-session
+ t ]
+ "---"
+ [ "Change Color" rudel-change-color
+ (and rudel-current-session
+ (rudel-capable-of-p
+ (oref rudel-current-session :backend)
+ 'change-color)) ] ; TODO bulky
+ "---"
+ [ "Publish current Buffer" rudel-publish-buffer
+ (and rudel-current-session
+ (not (rudel-buffer-has-document-p))) ]
+ [ "Unpublish current Buffer" rudel-unpublish-buffer
+ (rudel-buffer-has-document-p) ]
+ [ "Subscribe to Document" rudel-subscribe
+ rudel-current-session ]
+ "---"
+ [ "Rudel Overview" rudel-speedbar
+ t ]
+ "---"
+ ( "Options"
+ [ "Highlight Contributions in Authors' Colors"
+ (lambda ()
+ (interactive)
+ (setq rudel-overlay-author-display
+ (not rudel-overlay-author-display))
+ (rudel-overlay-options-changed))
+ :style toggle
+ :selected rudel-overlay-author-display ]
+ ( "Show subscribed Users"
+ [ "In this Buffer"
+ rudel-header-subscriptions-minor-mode
+ :style toggle
+ :selected rudel-header-subscriptions-minor-mode ]
+ [ "Globally"
+ global-rudel-header-subscriptions-mode
+ :style toggle
+ :selected global-rudel-header-subscriptions-mode ] )
+ ( "Show Status in mode line"
+ [ "In this Buffer"
+ rudel-mode-line-publish-state-minor-mode
+ :style toggle
+ :selected rudel-mode-line-publish-state-minor-mode ]
+ [ "Globally"
+ global-rudel-mode-line-publish-state-mode
+ :style toggle
+ :selected global-rudel-mode-line-publish-state-mode ] ) ) )
+ )
+ )
+
+;;;###autoload
+(define-minor-mode global-rudel-minor-mode
+ "Toggle global Rudel minor mode (No modeline indicator).
+
+If ARG is null, toggle global Rudel mode.
+If ARG is a number greater than zero, turn on global Rudel mode;
+otherwise, turn it off."
+ :init-value nil
+ :keymap rudel-minor-keymap
+ :global t
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq global-rudel-minor-mode nil))
+
+ ;; Mode is enabled
+ (global-rudel-minor-mode
+ )
+
+ ;; Mode is disabled
+ (t
+ ))
+ )
+
+(provide 'rudel-mode)
+;;; rudel-mode.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-operations.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-operations.el.svn-base
new file mode 100644
index 0000000..3637303
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-operations.el.svn-base
@@ -0,0 +1,133 @@
+;;; rudel-operations.el --- Rudel domain operations
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, operations
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains classes representing operations like insertions
+;; and deletions, that are import for Rudel's domain of collaborative
+;; editing.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+
+;;; Class rudel-operation
+;;
+
+(defclass rudel-operation ()
+ ()
+ "Abstract base class for operations."
+ :abstract t)
+
+(defgeneric rudel-apply ((this rudel-operation) object)
+ "Apply the change represented by THIS to OBJECT.")
+
+
+;;; Class rudel-insert-op
+;;
+
+;; TODO should be rudel-insert but there is a method of the same name
+(defclass rudel-insert-op (rudel-operation)
+ ((from :initarg :from
+ :type (or null (integer 0))
+ :documentation
+ "Start of the region affected by this operation or
+nil. nil means end of buffer")
+ (data :initarg :data
+ :type string
+ :documentation
+ "The inserted string."))
+ "Objects of this class represent insertion operations.")
+
+(defmethod rudel-apply ((this rudel-insert-op) object)
+ "Apply THIS to OBJECT by inserting the associated data."
+ (with-slots (from data) this
+ (rudel-insert object from data)))
+
+(defmethod slot-missing ((this rudel-insert-op)
+ slot-name operation &optional new-value)
+ "Simulate read-only slots :length and :to."
+ (cond
+ ;; Slot :length
+ ((and (or (eq slot-name :length)
+ (eq slot-name 'length))
+ (eq operation 'oref))
+ (with-slots (data) this
+ (length data)))
+ ;; Slot :to
+ ((and (or (eq slot-name :to)
+ (eq slot-name 'to))
+ (eq operation 'oref))
+ (with-slots (from length) this
+ (+ from length)))
+ ;; Call next method
+ (t (call-next-method)))
+ )
+
+
+;;; Class rudel-delete-op
+;;
+
+;; TODO should be rudel-delete but there is a method of the same name
+(defclass rudel-delete-op (rudel-operation)
+ ((from :initarg :from
+ :type (integer 0)
+ :documentation
+ "Start of the region affected by this operation.")
+ (to :initarg :to
+ :type (integer 0)
+ :documentation
+ "End of the region affected by this operation."))
+ "Objects of this class represent deletion operations.")
+
+(defmethod rudel-apply ((this rudel-delete-op) object)
+ "Apply THIS to OBJECT by deleting the associated region."
+ (with-slots (from length) this
+ (rudel-delete object from length)))
+
+(defmethod slot-missing ((this rudel-delete-op)
+ slot-name operation &optional new-value)
+ "Simulate slot :length"
+ (cond
+ ;; Slot :length
+ ((or (eq slot-name :length)
+ (eq slot-name 'length))
+ (with-slots (from to) this
+ (if (eq operation 'oref)
+ (- to from)
+ (setq to (+ from new-value)))))
+ ;; Call next method
+ (t (call-next-method)))
+ )
+
+(provide 'rudel-operations)
+;;; rudel-operations.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-operators.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-operators.el.svn-base
new file mode 100644
index 0000000..e51982e
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-operators.el.svn-base
@@ -0,0 +1,172 @@
+;;; rudel-operators.el --- Sets of modification operators for Rudel objects
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, operators
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Collections of operations on specific objects are collected into
+;; classes. Current there are
+;;
+;; - rudel-document-operators: realize operations on document objects
+;;
+;; - rudel-connection-operators: realize operations on connection
+;; objects
+;;
+;; - rudel-overlay-operators: realize operations by altering the
+;; overlays of buffer objects
+;;
+;; - rudel-hook-operators: realize operations by calling hooks
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-overlay)
+
+
+;;; Class rudel-document-operators
+;;
+
+(defclass rudel-document-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "Document to which modification operators are
+applied."))
+ "Provides operation methods which modify an associated document.")
+
+(defmethod rudel-insert ((this rudel-document-operators) position data)
+ "Insert DATA at POSITION into the document attached to THIS."
+ (with-slots (document) this
+ (rudel-insert document position data)))
+
+(defmethod rudel-delete ((this rudel-document-operators) position length)
+ "Delete a region of LENGTH characters at POSITION from the document attached to THIS."
+ (with-slots (document) this
+ (rudel-delete document position length)))
+
+
+;;; Class rudel-connection-operators
+;;
+
+(defclass rudel-connection-operators ()
+ ((connection :initarg :connection
+ :type rudel-connection-child
+ :documentation
+ "Connection on which the operations are
+performed.")
+ (document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "Document object to which operations refer."))
+ "Provides operation methods which affect an associated
+connection.")
+
+(defmethod rudel-insert ((this rudel-connection-operators) position data)
+ "Notify the connection associated to THIS of the insertion of DATA at POSITION."
+ (with-slots (connection document) this
+ (rudel-local-insert connection document position data)))
+
+(defmethod rudel-delete ((this rudel-connection-operators) position length)
+ "Notify the connection associated to THIS of a deletion of LENGTH at POSITION."
+ (with-slots (connection document) this
+ (rudel-local-delete connection document position length)))
+
+
+;;; Class rudel-overlay-operators
+;;
+
+(defclass rudel-overlay-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "The document to the overlays of which the
+operations are applied")
+ (user :initarg :user
+ :type rudel-user-child
+ :documentation
+ "The user object associated to operations."))
+ "Provides operation methods which affect the overlays of a
+buffer.")
+
+(defmethod rudel-insert ((this rudel-overlay-operators) position data)
+ "Update the overlays associated to THIS to incorporate an insertion of DATA at POSITION."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+
+ ;; Since we inserted something, (point-max) is at least the
+ ;; length of the insertion + 1. So we can safely subtract the
+ ;; length of the insertion and 1.
+ (unless position
+ (with-current-buffer buffer
+ (setq position (- (point-max) (length data) 1))))
+
+
+ (rudel-update-author-overlay-after-insert
+ buffer (+ position 1) (length data) user)))
+ )
+
+(defmethod rudel-delete ((this rudel-overlay-operators) position length)
+ "Update the overlays associated to THIS to incorporate a deletion of LENGTH at POSITION."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (rudel-update-author-overlay-after-delete
+ buffer (+ position 1) length user))))
+
+
+;;; Class rudel-hook-operators
+;;
+
+(defclass rudel-hook-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "The document object to which operations refer.")
+ (user :initarg :user
+ :type rudel-user-child
+ :documentation
+ "The user object associated to operations."))
+ "Provides operation methods which cause corresponding hooks to
+be called.")
+
+(defmethod rudel-insert ((this rudel-hook-operators) position data)
+ "Call insert hook associated to THIS with POSITION and DATA."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (run-hook-with-args 'rudel-insert-hook buffer user position data))))
+
+(defmethod rudel-delete ((this rudel-hook-operators) position length)
+ "Call delete hook associated to THIS with POSITION and LENGTH."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (run-hook-with-args 'rudel-delete-hook buffer user position length))))
+
+(provide 'rudel-operators)
+;;; rudel-operators.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-overlay.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-overlay.el.svn-base
new file mode 100644
index 0000000..093afdf
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-overlay.el.svn-base
@@ -0,0 +1,275 @@
+;;; rudel-overlay.el --- Overlay functions for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, overlay
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'custom)
+
+(eval-when-compile
+ (require 'cl))
+
+
+;;; Rudel overlay faces
+;;
+
+(defcustom rudel-overlay-author-display t
+ "Indicate authorship by setting text color to user color."
+ :group 'rudel
+ :type 'boolean
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-overlay)
+ (rudel-overlay-options-changed))))
+
+(put 'rudel-overlay-author-display 'safe-local-variable t)
+
+(defface rudel-author-overlay-face
+ '((default (:background "black")))
+ "*Face used to highlight contributions according to their authors.
+Attributes involving color are not applied literally. Instead the
+color is replaced with the color associated with the respective
+author."
+ :group 'rudel)
+
+
+;;; General overlay functions
+;;
+
+(defun rudel-overlay-p (overlay)
+ "Non-nil if OVERLAY is a Rudel overlay."
+ (overlay-get overlay :rudel))
+
+(defun rudel-overlay-length (overlay)
+ "Distance between end and start of OVERLAY."
+ (- (overlay-end overlay) (overlay-start overlay)))
+
+(defun rudel-overlay-user (overlay)
+ "User object associated to OVERLAY."
+ (overlay-get overlay :user))
+
+(defun rudel-overlays (&optional predicate)
+ "Return a list of Rudel-related overlays or overlays satisfying PREDICATE.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+
+ (let* ((overlay-lists (overlay-lists))
+ (overlays (append (car overlay-lists)
+ (cdr overlay-lists))))
+ (remove-if-not predicate overlays))
+ )
+
+(defun rudel-overlays-at (position &optional predicate)
+ "Return a list of Rudel-related overlays at POSITION.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+ (remove-if-not predicate (overlays-at position)))
+
+(defun rudel-overlays-in (start end &optional predicate)
+ "Return a list of Rudel-related overlays in the range START to END.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+ (remove-if-not predicate (overlays-in start end)))
+
+(defun rudel-overlays-remove-all ()
+ "Remove all Rudel overlays from the current buffer."
+ (mapc #'delete-overlay (rudel-overlays)))
+
+
+;;; Author overlay
+;;
+
+(defun rudel-author-overlay-p (overlay)
+ "Predicate for author overlays."
+ (eq (overlay-get overlay :rudel) 'author))
+
+(defun rudel-author-overlays ()
+ "Return the list of author overlays in the current buffer."
+ (rudel-overlays #'rudel-author-overlay-p))
+
+(defun rudel-author-overlay-at (position &optional author)
+ ""
+ (let ((overlays (rudel-overlays-at
+ position #'rudel-author-overlay-p)))
+ ;; There can only be one rudel overlay at any given position
+ (when overlays
+ (when (or (not author)
+ (eq (rudel-overlay-user (car overlays)) author))
+ (car overlays))))
+ )
+
+(defun rudel-author-overlays-in (start end &optional author)
+ ""
+ (rudel-overlays-in
+ start end
+ (lambda (overlay)
+ (and (rudel-overlay-p overlay)
+ (or (not author)
+ (eq (rudel-overlay-user overlay) author)))))
+ )
+
+(defun rudel-make-author-overlay (buffer from to author)
+ "Make and return an overlay for the range FROM to TO in BUFFER suitable for contributions by AUTHOR.
+AUTHOR has to be an object of type rudel-user-child."
+ (let ((overlay (make-overlay from to buffer t)))
+ (rudel-overlay-author-set-properties overlay author)
+ overlay))
+
+(defun rudel-overlay-author-set-properties (overlay author)
+ "Set properties of OVERLAY according to slots of AUTHOR.
+AUTHOR has to be an object of type rudel-user-child."
+ (with-slots ((name :object-name) color) author
+ (overlay-put overlay :rudel 'author)
+ (overlay-put overlay :user author)
+ (overlay-put overlay 'face (when rudel-overlay-author-display
+ (rudel-overlay-make-face
+ (rudel-overlay-make-face-symbol
+ 'author name)
+ 'rudel-author-overlay-face
+ color)))
+ (overlay-put overlay 'help-echo (when rudel-overlay-author-display
+ (format "Written by %s" name))))
+ )
+
+(defun rudel-overlay-author-update (overlay)
+ "Update properties of OVERLAY from its attached user object."
+ (let ((author (rudel-overlay-user overlay)))
+ (rudel-overlay-author-set-properties overlay author)))
+
+
+;;; Update functions for author overlays
+;;
+
+(defun rudel-update-author-overlay-after-insert (buffer position length author)
+ "Update author overlays in BUFFER to incorporate an insertion of length LENGTH at POSITION by AUTHOR.
+POSITION refers to an Emacs buffer position.
+AUTHOR has to be an object of type rudel-author-child."
+ (when author
+ (with-current-buffer buffer
+ (let* ((end (+ position length))
+ (before (when (> position 1)
+ (rudel-author-overlay-at (- position 1) author)))
+ (at (rudel-author-overlay-at position))
+ (after (when (< end (point-max))
+ (rudel-author-overlay-at (+ end 1) author))))
+ (cond
+ ;; If there is an overlay, we have to split it unless the
+ ;; author is AUTHOR or we are on its boundary.
+ (at
+ (unless (eq (rudel-overlay-user at) author)
+ (let* ((on-start (= (overlay-start at) position))
+ (on-end (= (- (overlay-end at) 1) position))
+ (before (unless on-start
+ (if on-end at (copy-overlay at))))
+ (after (unless on-end at)))
+ (when before
+ (move-overlay before (overlay-start before) position))
+ (when after
+ (move-overlay after end (overlay-end after)))
+ (rudel-make-author-overlay buffer position end author))))
+ ;; There is no overlay under the insert, but there are
+ ;; overlays of the same author immediately before and after
+ ;; the insert. We merge these two into one large overlay
+ ;; including the insert.
+ ((and before after)
+ (let ((end (overlay-end after)))
+ (delete-overlay after)
+ (move-overlay before (overlay-start before) end)))
+ ;; If there is an overlay of the same author before the
+ ;; insert, we extend it.
+ (before
+ (move-overlay before (overlay-start before) end))
+ ;; If there is an overlay of the same author after the
+ ;; insert, we extend it.
+ (after
+ (move-overlay after position (overlay-end after)))
+ ;; If there are no overlays at all, we create a suitable one.
+ (t
+ (rudel-make-author-overlay buffer position end author))))))
+ )
+
+(defun rudel-update-author-overlay-after-delete (buffer position length author)
+ "Update author overlays in BUFFER to incorporate a deletion of length LENGTH at POSITION by AUTHOR.
+POSITION refers to an Emacs buffer position.
+AUTHOR has to be an object of type rudel-author-child."
+ (with-current-buffer buffer
+ (mapc
+ (lambda (overlay)
+ (when (zerop (rudel-overlay-length overlay))
+ (delete-overlay overlay)))
+ (rudel-author-overlays-in position position)))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-overlay-make-face-symbol (category name)
+ "Allocate a symbol for a face for CATEGORY and NAME."
+ (intern (format "rudel-%s-overlay-%s-face"
+ (if (stringp category)
+ category
+ (symbol-name category))
+ name)))
+
+(defun rudel-overlay-make-face (face template color)
+ "Copy TEMPLATE to FACE and replace color attributes with COLOR.
+TEMPLATE has to be a face. FACE can be nil or a face. In the
+latter case, FACE is returned unmodified."
+ (unless (facep face)
+ (make-face face)
+ (copy-face template face)
+ (rudel-overlay-set-face-attributes face color))
+ face)
+
+(defun rudel-overlay-set-face-attributes (face color)
+ "Set color-related attributes of FACE with respect to COLOR."
+ (when (facep face)
+ (dolist (property '(:foreground :background :underline :overline))
+ (unless (eq (face-attribute face property) 'unspecified)
+ (set-face-attribute face nil property color)))))
+
+(defun rudel-overlay-options-changed ()
+ "Update Rudel overlays after a change of customization options."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (mapc #'rudel-overlay-author-update (rudel-overlays)))))
+
+(provide 'rudel-overlay)
+;;; rudel-overlay.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-protocol.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-protocol.el.svn-base
new file mode 100644
index 0000000..c60718c
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-protocol.el.svn-base
@@ -0,0 +1,83 @@
+;;; rudel-protocol.el --- Interface implemented by Rudel protocol backends
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, protocol
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the interface for Rudel protocol backends. This
+;; interface consists of the following functions:
+;;
+;; + joining sessions
+;; + `rudel-ask-join-info'
+;; + `rudel-join'
+;; + hosting sessions
+;; + `rudel-ask-host-info'
+;; + `rudel-host'
+;; + factory functions
+;; + `rudel-make-document'
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Class rudel-protocol-backend
+;;
+
+(defclass rudel-protocol-backend (rudel-backend)
+ ()
+ "Interface implemented by protocol backends."
+ :abstract t)
+
+(defgeneric rudel-ask-join-info ((this rudel-protocol-backend))
+ "Retrieve information for joining a session from user.
+Return a property list that contains the collected information.")
+
+(defgeneric rudel-join ((this rudel-protocol-backend) info)
+ "Create a new connection according to the data in the property list INFO.
+Implementations can rely on the fact that the property :session
+contains the `rudel-session' object to which the new connection
+will be associated.")
+
+(defgeneric rudel-ask-host-info ((this rudel-protocol-backend))
+ "Retrieve information for hosting a session from user.
+Return a property list that contains the collected information.")
+
+(defgeneric rudel-host ((this rudel-protocol-backend) info)
+ "Create a new session according to the property list INFO.")
+
+(defgeneric rudel-make-document ((this rudel-protocol-backend)
+ name session)
+ "Create a new document object named NAME for SESSION.")
+
+(provide 'rudel-protocol)
+;;; rudel-protocol.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-session-initiation.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-session-initiation.el.svn-base
new file mode 100644
index 0000000..395ab07
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-session-initiation.el.svn-base
@@ -0,0 +1,352 @@
+;;; rudel-session-initiation.el --- Session discovery and advertising functions
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, session, initiation, service, discovery, advertising
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Interfaces for session initiation and discovery.
+;;
+;; The central interface is
+;; `rudel-session-initiation-backend'. Backends implementing this
+;; interface can provide methods to discover sessions, to advertise
+;; sessions, or both.
+;;
+;; The client programming interface consists of a priority which is
+;; one of:
+;;
+;; + `primary'
+;; + `fallback'
+;;
+;; and the following functions:
+;;
+;; + `rudel-session-initiation-discover'
+;; + `rudel-session-initiation-advertise'
+;; + `rudel-session-initiation-withdraw'
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Customization options
+;;
+
+(defcustom rudel-configured-sessions nil
+ "List of configured sessions.
+
+Each session is described as a plist (a list of keys and values
+see Info node `(elisp)Property Lists'). Keys are specified using
+keywords and look like this: :host, :username, :color. Values are
+mostly strings, but symbols and numbers are possible as well.
+
+The following keys are required for any session:
+
+* :name (string)
+* :backend (string or symbol)
+
+Other keys are optional and depend on the selected
+backend. Required keys for which no value is specified will be
+prompted for when selecting the session. The values of the :name
+properties have to be distinct for all configured sessions.
+
+Additional keys required by most backends:
+
+* :host (string)
+* :port (number)
+* :username (string)
+* :color (string)
+
+Here is a complete example of customized values for the obby
+backend:
+
+* :name \"sonian\"
+* :backend obby
+* :host \"sobby\"
+* :port 6522
+* :encryption t
+* :username \"phil\"
+* :color \"white\"
+* :global-password \"\" (this means \"no password\")
+* :user-password \"\"
+
+The programmatic equivalent looks like this:
+
+(add-to-list
+ 'rudel-configured-sessions
+ (list :name \"myserver\"
+ :backend 'obby
+ :host \"my.sobby-server.net\"
+ :username user-login-name
+ ;; Use M-x list-colors-display to see color choices.
+ :color \"white\"
+ :encryption t
+ :port 6522
+ ;; empty string means no password
+ :global-password \"\"
+ :user-password \"\"))"
+ :group 'rudel
+ :type '(repeat :tag "Connections"
+ (plist :tag "Connection"
+ :options ((:name string)
+ (:backend symbol)
+ (:username string)
+ (:color color))))
+ )
+
+
+;;; Variables and constants
+;;
+
+(defvar rudel-session-discovered-hook nil
+ "This hook is run when collaboration sessions are discovered.")
+
+(defvar rudel-session-vanished-hook nil
+ "This hook is run when previously discovered collaboration
+session disappear.")
+
+
+;;; Class rudel-session-initiation-backend
+;;
+
+(defclass rudel-session-initiation-backend (rudel-backend)
+ ((priority :initarg :priority
+ :type symbol
+ :accessor rudel-priority
+ :documentation
+ "Priority of the session initiation method
+implemented by this backend. Has to be either 'primary or
+'fallback"))
+ "Interface implemented by session initiation backends."
+ :abstract t)
+
+(defgeneric rudel-discover ((this rudel-session-initiation-backend))
+ "Return a list of discovered sessions.
+Each list element is a connect info property list. See
+`rudel-join-session' for a description of the format of this
+list.
+
+The presence of an implementation of this generic function should
+be indicated by the presence of the 'discover' capability.")
+
+(defgeneric rudel-advertise ((this rudel-session-initiation-backend) info)
+ "Advertise session described by INFO.
+INFO is a connect info property list. See `rudel-host-session'
+for a description of the format of this list.
+
+The presence of an implementation of this generic function should
+be indicated by the presence of the 'advertise' capability.")
+
+
+;;; Client programming interface functions.
+;;
+
+(defun rudel-session-initiation-suitable-backends (capability)
+ "Return primary and fallback backends that have CAPABILITY.
+The returned list is of the form (PRIMARY FALLBACK), where
+PRIMARY and FALLBACK are lists of backends of the respective
+priority."
+ (let* (;; Select all backends, which can discover sessions
+ (suitable-backends (rudel-backend-suitable-backends
+ 'session-initiation
+ (lambda (backend)
+ (rudel-capable-of-p backend capability))))
+ ;; Select primary backends
+ (primary-backends (remove*
+ 'fallback suitable-backends
+ :key (lambda (backend)
+ (rudel-priority (cdr backend)))))
+ ;; Select fallback backends
+ (fallback-backends (remove*
+ 'primary suitable-backends
+ :key (lambda (backend)
+ (rudel-priority (cdr backend))))))
+ (list primary-backends fallback-backends))
+ )
+
+(defun rudel-session-initiation-discover (&optional backend-name)
+ "Return a list of session using BACKEND-NAME when non-nil.
+BACKEND-NAME is a symbol. When it is non-nil, only the specified
+backend is used to discover session.
+
+The returned list is of the form (INFO-1 ... INFO-N FALLBACK-1
+... FALLBACK-M) where INFO-I are connect info property lists (see
+`rudel-join-session') and FALLBACK-I are conses of the form (NAME
+. CLASS-OR-OBJECT) that specify fallback backends."
+ (multiple-value-bind (primary-backends fallback-backends)
+ (rudel-session-initiation-suitable-backends 'discover)
+ ;; Retrieve session list from primary backend and fall back to
+ ;; fallback backends if the list is empty.
+ (if backend-name
+ (let ((backend (find backend-name fallback-backends :key #'car)))
+ (rudel-discover (cdr backend)))
+ (let ((primary-results
+ (remove-if #'null
+ (apply #'append
+ (mapcar #'rudel-discover
+ (mapcar #'cdr primary-backends))))))
+ (append primary-results fallback-backends))))
+ )
+
+(defun rudel-session-initiation-advertise (info)
+ "Advertise the session described by INFO.
+INFO is a connect info property list. See `rudel-host-session'
+for a description of the format of this list.
+
+Primary backends are tried first. If none succeeds, fallback
+backends are tried.
+
+The result is non-nil if at least one backend was able to
+advertise the session."
+ (multiple-value-bind (primary-backends fallback-backends)
+ (rudel-session-initiation-suitable-backends 'advertise)
+ (or ;; Try to advertise the session using primary backends.
+ (some (mapcar (lambda (backend)
+ (rudel-advertise backend info))
+ (mapcar #'cdr primary-backends)))
+ ;; When the primary backends fail, try to advertise the
+ ;; session using fallback backends
+ (some (mapcar (lambda (backend)
+ (rudel-advertise backend info))
+ (mapcar #'cdr fallback-backends)))))
+ )
+
+
+;;; Class rudel-ask-protocol-backend
+;;
+
+(defconst rudel-ask-protocol-version '(0 1)
+ "Version of the ask-protocol backend for Rudel.")
+
+;;;###autoload
+(defclass rudel-ask-protocol-backend (rudel-session-initiation-backend)
+ ((capabilities :initform (discover))
+ (priority :initform fallback))
+ "This fallback backend can \"discover\" sessions by letting the
+user select a suitable backend and asking for connect information
+required by the chosen backend.")
+
+(defmethod initialize-instance ((this rudel-ask-protocol-backend)
+ &rest slots)
+ "Set backend version."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-ask-protocol-version))
+
+(defmethod rudel-discover ((this rudel-ask-protocol-backend))
+ "\"Discover\" sessions by asking the user about the backend to use and the connect info."
+ (let ((backend (rudel-backend-choose
+ 'protocol
+ (lambda (backend)
+ (rudel-capable-of-p backend 'join)))))
+ (list (append (list :name "asked"
+ :backend backend)
+ (rudel-ask-connect-info (cdr backend)))))
+ )
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'ask-protocol 'rudel-ask-protocol-backend)
+
+
+;;; Class rudel-configured-sessions-backend
+;;
+
+(defconst rudel-configured-sessions-version '(0 1)
+ "Version of the configured-sessions backend for Rudel.")
+
+;;;###autoload
+(defclass rudel-configured-sessions-backend
+ (rudel-session-initiation-backend)
+ ((capabilities :initform (discover))
+ (priority :initform primary))
+ "This fallback backend can \"discover\" sessions the user has
+configured using customization.")
+
+(defmethod initialize-instance ((this rudel-configured-sessions-backend)
+ &rest slots)
+ "Set backend version."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-configured-sessions-version))
+
+(defmethod rudel-discover ((this rudel-configured-sessions-backend))
+ "\"Discover\" sessions the has configured."
+ ;; Iterate over all configured sessions in order to make
+ ;; adjustments.
+ (mapcar #'rudel-session-initiation-adjust-info
+ rudel-configured-sessions))
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'configured-sessions 'rudel-configured-sessions-backend)
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-session-initiation-adjust-info (info)
+ "Resolve arguments that need resolving in INFO."
+ ;; Start with a new, empty property list.
+ (let ((adjusted-info)
+ (key (car info))
+ (value (cadr info))
+ (rest info))
+ ;; Iterate over all properties in INFO.
+ (while rest
+ (setq rest (cddr rest))
+ (cond
+ ;; Resolve backend arguments.
+ ((eq key :backend)
+ (let ((backend (rudel-backend-get 'protocol
+ (if (stringp value)
+ (intern value)
+ value))))
+ (push backend adjusted-info)
+ (push key adjusted-info)))
+ ;; Keep other arguments unmodified.
+ (t
+ (push value adjusted-info)
+ (push key adjusted-info)))
+ ;; Advance to next key value pair.
+ (setq key (car rest)
+ value (cadr rest)))
+ ;; Return the transformed session information.
+ adjusted-info)
+ )
+
+(provide 'rudel-session-initiation)
+;;; rudel-session-initiation.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-speedbar.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-speedbar.el.svn-base
new file mode 100644
index 0000000..8c2caa8
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-speedbar.el.svn-base
@@ -0,0 +1,214 @@
+;;; rudel-speedbar.el --- Speedbar rendering of Rudel objects
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, collaboration, speedbar
+;; X-RCS: $Id: rudel-speedbar.el,v 1.32 2008/10/10 21:47:28 zappo Exp $
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+;;; Commentary:
+;;
+;; This implements rendering of Rudel objects in speedbar.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'speedbar)
+(require 'eieio-speedbar)
+
+
+;;; Class rudel-user methods
+;;
+
+(defmethod eieio-speedbar-description ((this rudel-user))
+ "Provide a speedbar description for OBJ."
+ (format "User %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-user))
+ "Return a string to use as a speedbar button for OBJECT."
+ (format "%s" (object-name-string this)))
+
+
+;;; Class rudel-document methods
+;;
+
+(defmethod eieio-speedbar-description ((this rudel-document))
+ "Construct a description for from the name of document object THIS."
+ (format "Document %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-document))
+ "Return a string to use as a speedbar button for OBJECT."
+ (rudel-unique-name this))
+
+;;; Speedbar support mode
+;;
+(defun rudel-speedbar-make-map ()
+ "Make the generic object based speedbar keymap."
+ (speedbar-make-specialized-keymap))
+
+(defvar rudel-speedbar-key-map
+ (rudel-speedbar-make-map)
+ "A Generic object based speedbar display keymap.")
+
+(defvar rudel-speedbar-menu
+ '([ "Compile" rudel-speedbar-compile-line t])
+ "Menu part in easymenu format used in speedbar while browsing objects.")
+
+(defun rudel-speedbar-toplevel-buttons (dir)
+ "Return a list of objects to display in speedbar.
+Argument DIR is the directory from which to derive the list of objects."
+ (when rudel-current-session
+ (with-slots (users documents) rudel-current-session
+ (append users documents))))
+
+(eieio-speedbar-create 'rudel-speedbar-make-map
+ 'rudel-speedbar-key-map
+ 'rudel-speedbar-menu
+ "Collaboration Session"
+ 'rudel-speedbar-toplevel-buttons)
+
+;;;###autoload
+(defun rudel-speedbar ()
+ "Show connected users and available documents of Rudel session in speedbar."
+ (interactive)
+ (speedbar-frame-mode 1)
+ (speedbar-change-initial-expansion-list "Collaboration Session")
+ (speedbar-get-focus))
+
+;;; Speedbar Project Methods
+;;
+;; (defun rudel-find-nearest-file-line ()
+;; "Go backwards until we find a file."
+;; (save-excursion
+;; (beginning-of-line)
+;; (looking-at "^\\([0-9]+\\):")
+;; (let ((depth (string-to-number (match-string 1))))
+;; (while (not (re-search-forward "[]] [^ ]"
+;; (save-excursion (end-of-line)
+;; (point))
+;; t))
+;; (re-search-backward (format "^%d:" (1- depth)))
+;; (setq depth (1- depth)))
+;; (speedbar-line-token))))
+;;
+;; (defmethod eieio-speedbar-derive-line-path ((obj rudel-session) &optional depth)
+;; "Return the path to OBJ.
+;; Optional DEPTH is the depth we start at."
+;; "session" ;(file-name-directory (oref obj file))
+;; )
+;;
+;; (defmethod eieio-speedbar-derive-line-path ((obj rudel-session) &optional depth)
+;; "Return the path to OBJ.
+;; Optional DEPTH is the depth we start at."
+;; (let ((proj (rudel-target-parent obj)))
+;; ;; Check the type of line we are currently on.
+;; ;; If we are on a child, we need a file name too.
+;; (save-excursion
+;; (let ((lt (speedbar-line-token)))
+;; (if (or (eieio-object-p lt) (stringp lt))
+;; (eieio-speedbar-derive-line-path proj)
+;; ;; a child element is a token. Do some work to get a filename too.
+;; (concat (eieio-speedbar-derive-line-path proj)
+;; (rudel-find-nearest-file-line)))))))
+;;
+;; (defmethod eieio-speedbar-description ((obj rudel-session))
+;; "Provide a speedbar description for OBJ."
+;; "bla") ;(rudel-description obj))
+;;
+;;
+;; (defmethod eieio-speedbar-object-buttonname ((object rudel-project))
+;; "Return a string to use as a speedbar button for OBJECT."
+;; (if (rudel-parent-project object)
+;; (rudel-name object)
+;; (concat (rudel-name object) " " (oref object version))))
+;;
+;;
+;; (defmethod eieio-speedbar-object-children ((this rudel-project))
+;; "Return the list of speedbar display children for THIS."
+;; (condition-case nil
+;; (with-slots (subproj targets) this
+;; (append subproj targets))
+;; (error nil)))
+;;
+;;
+;; ;;; Generic file management for TARGETS
+;; ;;
+;; (defun rudel-file-find (text token indent)
+;; "Find the file TEXT at path TOKEN.
+;; INDENT is the current indentation level."
+;; (speedbar-find-file-in-frame
+;; (expand-file-name token (speedbar-line-directory indent)))
+;; (speedbar-maybee-jump-to-attached-frame))
+;;
+;; (defun rudel-create-tag-buttons (filename indent)
+;; "Create the tag buttons associated with FILENAME at INDENT."
+;; (let* ((lst (speedbar-fetch-dynamic-tags filename)))
+;; ;; if no list, then remove expando button
+;; (if (not lst)
+;; (speedbar-change-expand-button-char ??)
+;; (speedbar-with-writable
+;; ;; We must do 1- because indent was already incremented.
+;; (speedbar-insert-generic-list (1- indent)
+;; lst
+;; 'rudel-tag-expand
+;; 'rudel-tag-find)))))
+;;
+;; (defun rudel-tag-expand (text token indent)
+;; "Expand a tag sublist. Imenu will return sub-lists of specialized tag types.
+;; Etags does not support this feature. TEXT will be the button
+;; string. TOKEN will be the list, and INDENT is the current indentation
+;; level."
+;; (cond ((string-match "+" text) ;we have to expand this file
+;; (speedbar-change-expand-button-char ?-)
+;; (speedbar-with-writable
+;; (save-excursion
+;; (end-of-line) (forward-char 1)
+;; (speedbar-insert-generic-list indent token
+;; 'rudel-tag-expand
+;; 'rudel-tag-find))))
+;; ((string-match "-" text) ;we have to contract this node
+;; (speedbar-change-expand-button-char ?+)
+;; (speedbar-delete-subblock indent))
+;; (t (error "Ooops... not sure what to do")))
+;; (speedbar-center-buffer-smartly))
+;;
+;; (defun rudel-tag-find (text token indent)
+;; "For the tag TEXT in a file TOKEN, goto that position.
+;; INDENT is the current indentation level."
+;; (let ((file (rudel-find-nearest-file-line)))
+;; (speedbar-find-file-in-frame file)
+;; (save-excursion (speedbar-stealthy-updates))
+;; ;; Reset the timer with a new timeout when cliking a file
+;; ;; in case the user was navigating directories, we can cancel
+;; ;; that other timer.
+;; ; (speedbar-set-timer speedbar-update-speed)
+;; (goto-char token)
+;; (run-hooks 'speedbar-visiting-tag-hook)
+;; ;;(recenter)
+;; (speedbar-maybee-jump-to-attached-frame)
+;; ))
+
+(provide 'rudel-speedbar)
+
+;;; rudel-speedbar.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-state-machine.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-state-machine.el.svn-base
new file mode 100644
index 0000000..d96bcc7
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-state-machine.el.svn-base
@@ -0,0 +1,331 @@
+;;; rudel-state-machine.el --- A simple state machine for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, FSM
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This is a simple implementation of a finite state machine
+;; (FSM). The is modeled by rudel-state-machine class, objects of
+;; which contain state objects of classes derived from
+;; rudel-state. There are no explicit transition rules, since states
+;; specify their successors.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-errors)
+(require 'rudel-compat) ;; for pulsing progress reporter
+
+
+;;; Errors related to the state machine
+;;
+
+;; rudel-state-error
+
+(intern "rudel-state-error")
+
+(put 'rudel-state-error 'error-conditions
+ '(error
+ rudel-error rudel-state-error))
+
+(put 'rudel-state-error 'error-message
+ "Invalid state or state transition")
+
+;; rudel-invalid-successor-state
+
+(intern "rudel-invalid-successor-state")
+
+(put 'rudel-invalid-successor-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-invalid-successor-state))
+
+(put 'rudel-invalid-successor-state 'error-message
+ "Invalid successor state in state transition")
+
+;; rudel-entered-error-state
+
+(intern "rudel-entered-error-state")
+
+(put 'rudel-entered-error-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-entered-error-state))
+
+(put 'rudel-entered-error-state 'error-message
+ "Transition to error state")
+
+;; rudel-no-start-state
+
+(intern "rudel-no-start-state")
+
+(put 'rudel-no-start-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-no-start-state))
+
+(put 'rudel-no-start-state 'error-message
+ "No start state specified for state machine")
+
+
+;;; Class rudel-state
+;;
+
+(defclass rudel-state ()
+ ()
+ "A state that can be used in state machines."
+ :abstract t)
+
+(defgeneric rudel-accept ((this rudel-state) &rest arguments)
+ "Executed when the machine receives an event while in state THIS.")
+
+(defgeneric rudel-enter ((this rudel-state) &rest arguments)
+ "Executed when the machine switches to state THIS.")
+
+(defgeneric rudel-leave ((this rudel-state))
+ "Executed when the machine leaves state THIS.")
+
+
+;;; Class rudel-state-machine
+;;
+
+(defclass rudel-state-machine ()
+ ((states :initarg :states
+ :type list ;; alist
+ :initform nil
+ :documentation
+ "A list (NAME . STATE) conses where NAME is a symbol
+and STATE is an object of a class derived from rudel-state.")
+ (state :initarg :state
+ :type rudel-state-child
+ :documentation
+ "The current state of the machine."))
+ "A finite state machine.")
+
+(defmethod initialize-instance :after ((this rudel-state-machine)
+ &rest slots)
+ "Set current state of THIS to a proper initial value.
+If a start state is specified in the arguments to the
+constructor, that state is used. If there is no such state, the
+list of states is search for a state named start. If that fails
+as well, the first state in the state list is used."
+ (with-slots (states) this
+ ;; Find a suitable start state and switch to it.
+ (let ((start (or (plist-get slots :start)
+ (car (assoc 'start states))
+ (when (length states)
+ (car (nth 0 states))))))
+ (unless start
+ (signal 'rudel-no-start-state nil))
+ ;; Make start state the current state and call send an enter
+ ;; message.
+ (let ((start (cdr (assoc start states))))
+ (oset this :state start)
+ (rudel--switch-to-return-value
+ this start (rudel-enter start)))))
+ )
+
+(defmethod rudel-find-state ((this rudel-state-machine) name)
+ "Return state object for symbol NAME."
+ (with-slots (states) this
+ (cdr (assoc name states))))
+
+(defmethod rudel-register-state ((this rudel-state-machine) name state)
+ "Register STATE and its NAME with THIS state machine."
+ (object-add-to-list this :states (cons name state) t))
+
+(defmethod rudel-register-states ((this rudel-state-machine) states)
+ "Register STATES with THIS state machine.
+STATES is a list of cons cells whose car is a symbol - the name
+of the state - and whose cdr is a class."
+ (dolist (symbol-and-state states)
+ (destructuring-bind (name . class) symbol-and-state
+ (rudel-register-state
+ this name (make-instance class (symbol-name name)))))
+ )
+
+(defmethod rudel-current-state ((this rudel-state-machine) &optional object)
+ "Return name and, optionally, state object of the current state of THIS.
+If OBJECT is non-nil, (NAME . OBJECT) is returned. Otherwise,
+just NAME."
+ (with-slots (states state) this
+ (let ((state-symbol (car (find state states :key #'cdr :test #'eq))))
+ (if object
+ (cons state-symbol state)
+ state-symbol)))
+ )
+
+(defmethod rudel-accept ((this rudel-state-machine) &rest arguments)
+ "Process an event described by ARGUMENTS."
+ (with-slots (state) this
+ ;; Let the current state decide which state is next.
+ (let ((next (apply #'rudel-accept state arguments)))
+ (cond
+ ;; If NEXT is nil, a symbol or a state object, we switch states
+ ;; without passing any data.
+ ((or (null next) (symbolp next) (rudel-state-child-p next))
+ (rudel-switch this next))
+
+ ;; If NEXT is a list, it contains the symbol of the successor
+ ;; state and additional data.
+ ((listp next)
+ (apply #'rudel-switch this next))
+
+ ;; Other types cannot be processed.
+ (t
+ (signal 'wrong-type-argument (list (type-of next)))))))
+ )
+
+(defmethod rudel-switch ((this rudel-state-machine) next
+ &rest arguments)
+ "Leave current state and switch to state NEXT.
+ARGUMENTS are passed to the `rudel-enter' method of the successor
+state."
+ (with-slots (states state) this
+ (cond
+ ;; When NEXT is a state object, use it.
+ ((rudel-state-child-p next))
+
+ ;; When NEXT is nil, stay in the current state.
+ ((null next)
+ (setq next state))
+
+ ;; When NEXT is a symbol (but not nil), look up the corresponding
+ ;; state. Signal an error, if there is none.
+ ((symbolp next)
+ (let ((next-state (assoc next states)))
+ (unless next-state
+ (signal 'rudel-invalid-successor-state
+ (list next '<- state)))
+ (setq next (cdr next-state))))
+
+ ;; Other types cannot be processed.
+ (t
+ (signal 'wrong-type-argument (list (type-of next)))))
+
+ ;; Unless the successor state is equal to the current state, leave
+ ;; the current state and switch to the successor.
+ (if (and (eq state next)
+ (null arguments))
+ ;; Return state
+ state
+ ;; Notify (old) current state.
+ (rudel-leave state)
+ ;; Update current state.
+ (setq state next)
+ ;; Notify (new) current state. Using the call's value as next
+ ;; state is a bit dangerous since a long sequence of immediate
+ ;; state switches could exhaust the stack.
+ (rudel--switch-to-return-value
+ this state (apply #'rudel-enter state arguments))))
+ )
+
+(defmethod rudel--switch-to-return-value ((this rudel-state-machine)
+ state next)
+ "Switch from STATE to the next state indicated by NEXT.
+STATE is the current state.
+NEXT can nil, a list or a `rudel-state' object."
+ (cond
+ ;; Remain in current state.
+ ((null next)
+ state)
+ ;; NEXT contains next state and arguments to pass to it when
+ ;; switching.
+ ((listp next)
+ (apply #'rudel-switch this next))
+ ;; Otherwise NEXT is a `rudel-state' object.
+ (t
+ (rudel-switch this next)))
+ )
+
+(defmethod object-print ((this rudel-state-machine) &rest strings)
+ "Add current state to the string representation of THIS."
+ (if (slot-boundp this 'state)
+ (with-slots (state) this
+ (apply #'call-next-method
+ this
+ (format " state: %s"
+ (object-name-string state))
+ strings))
+ (call-next-method this " state: #start"))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-state-wait (machine success-states
+ &optional error-states callback)
+ "Repeatedly call CALLBACK until MACHINE is in a state in SUCCESS-STATES or ERROR-STATES.
+MACHINE should be of type rudel-state-machine-child or at least
+have a method `rudel-get-state'.
+
+SUCCESS-STATES and ERROR-STATES are lists which contain the
+names (as symbols) of success and error states respectively.
+This function does not return when MACHINE enters states not in
+SUCCESS-STATES or ERROR-STATES. As a result, a deadlock can occur
+when MACHINE deadlocks or cycles through states not in either
+list infinitely.
+
+When non-nil, CALLBACK has to be a function that accepts one
+argument of the form (SYMBOL . STATE) where SYMBOL is the name
+symbol of the current state and STATE is the state object."
+ ;; Wait until MACHINE enter a state in SUCCESS-STATES or
+ ;; ERROR-STATES.
+ (let ((result
+ (catch 'state-wait
+ (while t
+ ;; Retrieve current state.
+ (destructuring-bind (symbol . state)
+ (rudel-current-state machine t)
+
+ ;; Check against success and error states.
+ (when (memq symbol success-states)
+ (throw 'state-wait (cons 'success (cons symbol state))))
+ (when (memq symbol error-states)
+ (throw 'state-wait (cons 'error (cons symbol state))))
+
+ ;; Update progress indicator and sleep.
+ (when callback
+ (funcall callback (cons symbol state)))
+ (sleep-for 0.05))))))
+ (when callback
+ (funcall callback t))
+
+ ;; If MACHINE ended up in an error state, signal
+ (unless (eq (car result) 'success)
+ (signal 'rudel-entered-error-state (cdr result)))
+ ;; Return state
+ (cdr result))
+ )
+
+(provide 'rudel-state-machine)
+;;; rudel-state-machine.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-tls.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-tls.el.svn-base
new file mode 100644
index 0000000..a770851
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-tls.el.svn-base
@@ -0,0 +1,201 @@
+;;; rudel-tls.el --- Start TLS protocol.
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, TLS, encryption, starttls, gnutls
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This contains a simple implementation of the so calls Start TLS
+;; protocol, which means enabling TLS encryption for an existing
+;; network connection.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'format-spec)
+
+(require 'rudel)
+(require 'rudel-util)
+
+
+;;; Customization
+;;
+
+(defcustom rudel-tls-client-program
+ "gnutls-cli"
+ "The gnutls client program to use for encrypted connections."
+ :group 'rudel
+ :type 'file)
+
+(defcustom rudel-tls-client-arguments
+ "--starttls --kx ANON_DH --port %p %h"
+ "Arguments passed to the gnutls client program."
+ :group 'rudel
+ :type 'string)
+
+
+;;; TLS functions
+;;
+
+(defun rudel-tls-make-process (&rest args)
+ "Make a network process with keyword arguments ARGS.
+This function works similar to `make-network-process'. Supported
+keyword arguments are :name (ignore), :host, :port, :filter
+and :sentinel. The returned process object is suitable for
+start-TLS. Once the enclosing protocol indicates TLS encryption
+should start, `rudel-tls-start-tls' can be called to enabled TLS
+for the network connection."
+ (let* ((host (plist-get args :host)) ;; TODO clumsy
+ (port (plist-get args :service))
+ (filter (plist-get args :filter))
+ (sentinel (plist-get args :sentinel))
+ ;; Compile the command to start the TLS binary.
+ (arguments (format-spec rudel-tls-client-arguments
+ (format-spec-make
+ ?h host
+ ?p (number-to-string port))))
+ ;; Start the TLS program.
+ (process (apply #'start-process
+ (format "*tls-%s*" host) nil
+ rudel-tls-client-program
+ (split-string arguments " "))))
+
+ ;; Store filter function and attach proxy filter to handle TLS
+ ;; handshake.
+ (when filter
+ (rudel-set-process-object process filter :old-filter))
+ (set-process-filter process #'rudel-tls-wait-init)
+
+ ;; Attach sentinel function.
+ (when sentinel
+ (set-process-sentinel process sentinel))
+
+ ;; Mark the process as supporting TLS encryption
+ (rudel-set-process-object process t :supports-tls)
+
+ process)
+ )
+
+(defun rudel-tls-start-tls (process)
+ "Enable TLS encryption for the network connection PROCESS.
+This only works if PROCESS has been created by
+`rudel-tls-make-process'."
+ ;; Save current filter function.
+ (rudel-set-process-object
+ process (process-filter process) :old-filter)
+ ;; Install TLS handshake filter function and signal program to start
+ ;; TLS handshake.
+ (message "tls-start-tls: switching to \"handshake\" filter")
+ (set-process-filter process #'rudel-tls-wait-handshake)
+ (signal-process process 'sigalrm)
+ )
+
+(defun rudel-tls-wait-init (process data)
+ "Is installed as process filter on PROCESS until gnutls is done printing messages."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter))
+ (client-mode))
+
+ ;; Assemble lines that were not generated by gnutls. It is very
+ ;; brittle to wait for last line of gnutls output like, but it
+ ;; cannot be helped.
+ (rudel-loop-lines data line
+ (if client-mode
+ (setq client-data (concat client-data line "\n"))
+ (when (string-match-p "- Simple Client Mode.*" line)
+ (setq client-mode t))))
+
+ ;; When there are any lines not generated by gnutls,
+ ;; initialization is over. Process the data and install the old
+ ;; filter function.
+ (when client-data
+ (funcall old-filter process client-data))
+ (when client-mode
+ (message "tls-wait-init: switching back to old filter")
+ (set-process-filter process old-filter)))
+ )
+
+(defun rudel-tls-wait-handshake (process data)
+ "Is installed as process filter on PROCESS while gnutls is doing the TLS handshake."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter))
+ (client-mode))
+
+ ;; Assemble lines that were not generated by gnutls. It is very
+ ;; brittle to wait for last line of gnutls output like, but it
+ ;; cannot be helped.
+ (rudel-loop-lines data line
+ (if client-mode
+ (setq client-data (concat client-data line "\n"))
+ (when (string-match-p "- Compression.*" line)
+ (setq client-mode t))))
+
+ ;; When there are any lines not generated by gnutls, handshake is
+ ;; over. Process the data and install `established' filter
+ ;; function.
+ (when client-data
+ (funcall old-filter process client-data))
+ (when client-mode
+ (message "tls-wait-handshake: switching to \"established\" filter")
+ (set-process-filter process #'rudel-tls-established)
+ (rudel-set-process-object process t :encryption)))
+ )
+
+(defun rudel-tls-established (process data)
+ "Is installed as process filter on PROCESS after gnutls has established TLS encryption."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter)))
+
+ ;; Assemble lines that were not generated by gnutls.
+ (rudel-loop-lines data line
+ (unless (string-match-p "- Peer has closed the GNUTLS connection" line)
+ (setq client-data (concat client-data line "\n"))))
+
+ ;; When there are any lines not generated by gnutls, pass those to
+ ;; the old filter function.
+ (when client-data
+ (funcall old-filter process client-data)))
+ )
+
+(provide 'rudel-tls)
+;;; rudel-tls.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-transport.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-transport.el.svn-base
new file mode 100644
index 0000000..8f0b21d
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-transport.el.svn-base
@@ -0,0 +1,72 @@
+;;; rudel-transport.el --- Rudel transport interface and backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, transport
+;; X-RCS: $Id:$
+;;
+;; 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 3 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, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the interface for Rudel transport backends.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Class rudel-transport
+;;
+
+(defclass rudel-transport ()
+ ()
+ "Interface for transport objects.")
+
+(defgeneric rudel-transport-send ((this rudel-transport) data)
+ "Send DATA through THIS transport object.")
+
+(defgeneric rudel-transport-set-handler ((this rudel-transport)
+ handler)
+ "Install HANDLER as dispatcher for messages received by THIS.")
+
+
+;;; Class rudel-transport-backend
+;;
+
+(defclass rudel-transport-backend (rudel-backend)
+ ()
+ "Interface implemented by transport backends."
+ :abstract t)
+
+(defgeneric rudel-make-connection ((this rudel-transport-backend) info)
+ "Create a transport object according to INFO.")
+
+(defgeneric rudel-wait-for-connections ((this rudel-transport-backend)
+ info)
+ "Create a transport object according to INFO.")
+
+(provide 'rudel-transport)
+;;; rudel-transport.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel-util.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel-util.el.svn-base
new file mode 100644
index 0000000..12a967c
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel-util.el.svn-base
@@ -0,0 +1,261 @@
+;;; rudel-util.el --- Miscellaneous functions for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, miscellaneous, util
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains miscellaneous functions for Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-errors)
+
+
+;;; Errors
+;;
+
+;; rudel-dispatch-error
+
+(intern "rudel-dispatch-error")
+
+(put 'rudel-dispatch-error 'error-conditions
+ '(error
+ rudel-error rudel-dispatch-error))
+
+(put 'rudel-dispatch-error 'error-message
+ "Could not dispatch message to handler")
+
+
+;;; Class rudel-hook-object
+;;
+
+(defclass rudel-hook-object ()
+ ()
+ "Mixin for classes that offer one or more hooks for each of
+their objects.
+
+This idiom is usually called something like signal/slot or
+event/subscription, but for Emacs, the notion of hooks seems more
+appropriate."
+ :abstract t)
+
+(defmethod object-add-hook ((this rudel-hook-object)
+ hook function &optional append)
+ "Add FUNCTION to HOOK for THIS.
+If APPEND is non-nil FUNCTION becomes the last element in the
+list of hooks."
+ (let ((value (slot-value this hook)))
+ (unless (member function value)
+ (set-slot-value this hook
+ (if append (append value (list function))
+ (cons function value)))))
+ )
+
+(defmethod object-remove-hook ((this rudel-hook-object)
+ hook function)
+ "Remove FUNCTION from HOOK for THIS."
+ (set-slot-value this hook
+ (remove function (slot-value this hook))))
+
+(defmethod object-run-hook-with-args ((this rudel-hook-object)
+ hook &rest arguments)
+ "Run HOOK of THIS with arguments ARGUMENTS."
+ (let ((hook (slot-value this hook)))
+ (apply #'run-hook-with-args 'hook this arguments)))
+
+
+;;; Class rudel-socket-owner
+;;
+
+(defclass rudel-socket-owner ()
+ ((socket :initarg :socket
+ :type process
+ :documentation
+ "The process object representing the socket through
+which the communication happens."))
+ "Class rudel-socket-owner ")
+
+(defmethod initialize-instance :after ((this rudel-socket-owner)
+ &rest slots)
+ "Attach THIS to as process object of our socket."
+ ;; Attach to our socket.
+ (with-slots (socket) this
+ (rudel-set-process-object socket this))
+ )
+
+(defmethod rudel-disconnect ((this rudel-socket-owner))
+ "Disconnect the network connection owned by THIS."
+ (with-slots (socket) this
+ (delete-process socket)))
+
+(defmethod rudel-state-change ((this rudel-socket-owner) state message)
+ "Called when the state of THIS changes to STATE.
+MESSAGE is the message emitted when the state transition
+occurred."
+ (with-slots (socket) this
+ (case state
+ ;; Nothing to do here.
+ (run
+ nil)
+
+ ;; Dispatch events which indicate the termination of the
+ ;; connection to `rudel-close'.
+ ((closed failed exit)
+ (rudel-close this))))
+ )
+
+(defmethod rudel-close ((this rudel-socket-owner))
+ "Called when the connection associated to THIS is closed.")
+
+
+;;; Networking helper functions and macros
+;;
+
+(defun rudel-process-object (process &optional key)
+ "Return the object attached to PROCESS using identifier KEY."
+ (unless key
+ (setq key :object))
+ (get (intern (process-name process)) key))
+
+(defun rudel-set-process-object (process object &optional key)
+ "Set object attached to PROCESS using identifier KEY to OBJECT."
+ (unless key
+ (setq key :object))
+ (put (intern (process-name process)) key object))
+
+(defun rudel-filter-dispatch (process data)
+ "Call `rudel-receive' method of object attached to PROCESS with DATA."
+ (let ((object (rudel-process-object process)))
+ (rudel-receive object data)))
+
+(defun rudel-sentinel-dispatch (process message)
+ "Call `rudel-state-change' method of the object attached to PROCESS with state and MESSAGE."
+ (let ((object (rudel-process-object process))
+ (state (process-status process)))
+ (rudel-state-change object state message)))
+
+
+;;; Fragmentation and assembling functions.
+;;
+
+(defmacro rudel-assemble-line-fragments (data storage)
+ "Find an return complete lines in DATA, store excess data in STORAGE.
+If STORAGE is non-nil when calling, consider content as leftover
+data from last and concatenate with DATA before processing."
+ (declare (debug (form form)))
+ (let ((index (make-symbol "index")))
+ `(progn
+ ;; If there are stored fragments, append them to the new data.
+ (when ,storage
+ (setq ,data (concat ,storage ,data))
+ (setq ,storage nil))
+ ;; Try to find a line break in the augmented data.
+ (let ((,index (position ?\n ,data :from-end t)))
+ (unless (and ,index (eq ,index (- (length ,data) 1)))
+ (setq ,storage (if ,index
+ (substring ,data (+ ,index 1))
+ ,data))
+ (setq ,data (when ,index
+ (substring ,data 0 (+ ,index 1))))))
+ ,data))
+ )
+
+(defmacro rudel-loop-lines (data var &rest forms)
+ "Execute FROMS with VAR subsequently bound to all lines in DATA."
+ (declare (indent 2)
+ (debug (form symbolp &rest form)))
+ (let ((lines (make-symbol "lines")))
+ `(when ,data
+ (let ((,lines (split-string ,data "\n" t)))
+ (dolist (,var ,lines)
+ (progn ,@forms)))))
+ )
+
+(defmacro rudel-loop-chunks (data var size &rest forms)
+ "Execute FROMS in a loop with VAR bound to chunks of DATA of SIZE.
+Unless (zerop (mod (length data) size) 0) the final chunk is
+truncated. The expression SIZE is evaluated in each loop unless
+it is a number."
+ (declare (indent 3)
+ (debug (form symbolp numberp &rest form)))
+ ;; If we got a constant number as SIZE, we can check right away.
+ (when (and (numberp size) (<= size 0))
+ (error "Size should be positive"))
+
+ (let ((rest (make-symbol "rest"))
+ (amount (make-symbol "amount"))
+ ;; If SIZE has to be evaluated, we have to check at runtime.
+ (check (unless (numberp size)
+ `((when (<= ,size 0)
+ (error "Size should be positive"))))))
+ `(progn
+ ,@check
+ (let ((,rest ,data)
+ (,var)
+ (,amount))
+ (while (not (string= ,rest ""))
+ (setq ,amount (min (length ,rest) ,size)
+ ,var (substring ,rest 0 ,amount)
+ ,rest (substring ,rest ,amount))
+ (progn ,@forms)))))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-dispatch (object prefix name arguments)
+ "Call method (concat PREFIX NAME) of OBJECT with ARGUMENTS.
+If no such method can be found, the condition
+rudel-dispatch-error is signalled."
+ ;; Construct a matching symbol.
+ (let* ((method (intern-soft (concat prefix name))))
+ ;; If we found a suitable method, run it; Otherwise signal.
+ (unless method
+ (signal 'rudel-dispatch-error 'method-symbol-unbound))
+ (condition-case error
+ ;; Try to call METHOD. This can still fail when METHOD is not
+ ;; defined for the class of OBJECT.
+ (apply method object arguments)
+ ;; Only handle a condition 'no-method-definition' that refers to
+ ;; METHOD, otherwise continue unwinding.
+ (no-method-definition
+ (if (eq method (cadr error))
+ (signal 'rudel-dispatch-error 'no-method-for-object)
+ (signal (car error) (cdr error))))))
+ )
+
+(provide 'rudel-util)
+;;; rudel-util.el ends here
diff --git a/emacs.d/lisp/rudel/.svn/text-base/rudel.el.svn-base b/emacs.d/lisp/rudel/.svn/text-base/rudel.el.svn-base
new file mode 100644
index 0000000..88603fa
--- /dev/null
+++ b/emacs.d/lisp/rudel/.svn/text-base/rudel.el.svn-base
@@ -0,0 +1,1012 @@
+;;; rudel.el --- A collaborative editing framework for Emacs
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, collaboration
+;; URL: http://rudel.sourceforge.net/
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Rudel is a framework for collaborative editing in Emacs. Its
+;; architecture allows communication with arbitrary collaborative
+;; editors.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+(require 'eieio-base)
+
+(require 'eieio-speedbar) ;; TODO required for now
+
+(require 'rudel-util)
+(require 'rudel-backend)
+(require 'rudel-session-initiation)
+(require 'rudel-operations)
+(require 'rudel-operators)
+(require 'rudel-overlay)
+(require 'rudel-hooks)
+(require 'rudel-interactive) ;; for `rudel-read-backend',
+ ;; `rudel-read-document',
+ ;; `rudel-read-session'
+(require 'rudel-icons)
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Global variables
+;;
+
+(defconst rudel-version '(0 3)
+ "Version of the Rudel framework.")
+
+(defvar rudel-current-session nil
+ "Global object representing the current Rudel session.
+nil if there is no active session.")
+
+(defvar rudel-buffer-document nil
+ "Buffer-local variable which holds the Rudel document associated with the buffer.")
+(make-variable-buffer-local 'rudel-buffer-document)
+(put 'rudel-buffer-document 'permanent-local t)
+
+(defvar rudel-buffer-change-workaround-data nil
+ "Buffer-local variable which holds change data that could not be accessed otherwise.
+It would be nice to find another way to do this.")
+(make-variable-buffer-local 'rudel-buffer-change-workaround-data)
+(put 'rudel-buffer-change-workaround-data 'permanent-local t)
+
+
+;;; Customization
+;;
+
+(defgroup rudel nil
+ "Rudel collaborative editing framework."
+ :group 'applications)
+
+(defcustom rudel-allocate-buffer-function
+ 'rudel-allocate-buffer-clear-existing
+ "A function used to find or create buffers to associate to documents.
+The function is called with the document name as the sole
+argument and has to return a buffer object which will be attached
+to the document in question."
+ :group 'rudel
+ :type '(choice (const :tag "Clear content of existing buffer"
+ rudel-allocate-buffer-clear-existing )
+ (const :tag "Create a new uniquely named buffer"
+ rudel-allocate-buffer-make-unique )
+ (function :tag "Other function"))
+ :require 'rudel-interactive)
+
+(defcustom rudel-default-username (user-login-name)
+ "*"
+ :group 'rudel
+ :type '(string))
+
+
+;;; Class rudel-session
+;;
+
+(defclass rudel-session (rudel-hook-object)
+ ((backend :initarg :backend
+ :type rudel-backend-child
+ :documentation
+ "The backend used by this session.")
+ (users :initarg :users
+ :type list
+ :initform nil
+ :documentation
+ "The list of users participating in this
+session.")
+ (documents :initarg :documents
+ :type list
+ :initform nil
+ :documentation
+ "This list of documents available in
+this session.")
+ ;; Hooks
+ (end-hook :initarg :end-hook
+ :type list
+ :initform nil
+ :documentation
+ "")
+ (add-user-hook :initarg :add-user-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user gets added
+to the session.
+The arguments are the session and the user object.")
+ (remove-user-hook :initarg :remove-user-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user gets
+removed from the session.
+The arguments are the session and the user object.")
+ (add-document-hook :initarg :add-document-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a document gets
+added to the session.
+The arguments are the session and the document object.")
+ (remove-document-hook :initarg :remove-document-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a document gets
+removed from the session.
+The arguments are the session and the document object."))
+ "This class serves as a base class for rudel-client-session and
+rudel-server-session. Consequently, it consists of slots common
+to client and server sessions."
+ :abstract t)
+
+(defmethod rudel-end ((this rudel-session))
+ "Terminate THIS session performing all necessary cleanup."
+ ;; Run the hook.
+ (object-run-hook-with-args this 'end-hook))
+
+(defmethod rudel-add-user ((this rudel-session) user)
+ "Add USER to the user list of THIS session.
+
+Runs object hook (see `rudel-hook-object') `add-user-hook' with
+arguments THIS and USER."
+ ;; Add USER to list.
+ (object-add-to-list this :users user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'add-user-hook user))
+
+(defmethod rudel-remove-user ((this rudel-session) user)
+ "Remove USER from the user list of THIS session.
+
+Runs object hook (see `rudel-hook-object') `remove-user-hook'
+with arguments THIS and USER."
+ ;; Remove USER from list.
+ (object-remove-from-list this :users user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'remove-user-hook user))
+
+(defmethod rudel-find-user ((this rudel-session)
+ which &optional test key)
+ "Find user WHICH in the user list.
+WHICH is compared to the result of KEY using TEST."
+ (unless test
+ (setq test #'string=))
+ (unless key
+ (setq key #'object-name-string))
+ (with-slots (users) this
+ (find which users :key key :test test))
+ )
+
+(defmethod rudel-add-document ((this rudel-session) document)
+ ""
+ (unless (slot-boundp document :session)
+ (oset document :session this))
+
+ ;; Add DOCUMENT to the list of documents in THIS session.
+ (object-add-to-list this :documents document)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'add-document-hook document))
+
+(defmethod rudel-remove-document ((this rudel-session) document)
+ "Remove DOCUMENT from THIS session, detaching it if necessary."
+ ;; Detach document from its buffer when necessary.
+ (when (rudel-attached-p document)
+ (rudel-detach-from-buffer document))
+
+ ;; Remove DOCUMENT from the list of documents in THIS session.
+ (object-remove-from-list this :documents document)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'remove-document-hook document))
+
+(defmethod rudel-find-document ((this rudel-session)
+ which &optional test key)
+ "Find document WHICH in the document list.
+WHICH is compared to the result of KEY using TEST."
+ (unless test
+ (setq test #'string=))
+ (unless key
+ (setq key #'object-name-string))
+ (with-slots (documents) this
+ (find which documents :key key :test test))
+ )
+
+(defmethod rudel-unsubscribed-documents ((this rudel-session))
+ ""
+ (unless (slot-boundp this :self)
+ (error "Cannot find unsubscribed documents unless slot self is bound"))
+ (with-slots (documents self) this
+ (remove-if
+ (lambda (document)
+ (with-slots (subscribed) document
+ (memq self subscribed)))
+ documents))
+ )
+
+
+;;; Class rudel-client-session
+;;
+(defclass rudel-client-session (rudel-session)
+ ((connection :initarg :connection
+ :type (or null rudel-connection-child)
+ :initform nil
+ :documentation
+ "The connection used for communication by this
+session.")
+ (self :initarg :self
+ :type rudel-user-child
+ :documentation
+ "Points into USERS to the user object representing
+the local user"))
+ "Objects represent a collaborative editing session from a
+client perspective.")
+
+(defmethod rudel-end ((this rudel-client-session))
+ ;; Clean everything up
+ (with-slots (connection users documents) this
+ ;; Detach all documents from their buffers
+ (mapc #'rudel-detach-from-buffer documents)
+
+ ;; Terminate the connection
+ (when connection
+ (condition-case nil
+ (rudel-disconnect connection)
+ (error nil))))
+
+ ;;
+ (when (next-method-p)
+ (call-next-method))
+ )
+
+
+;;; Class rudel-server-session
+;;
+
+(defclass rudel-server-session (rudel-session)
+ ()
+ "Class rudel-server-session "
+ :abstract t)
+
+
+;;; Class rudel-connection
+;;
+
+(defclass rudel-connection ()
+ ((session :initarg :session
+ :type rudel-session-child
+ :documentation
+ ""))
+ "This abstract class defines the interface implementations of
+client protocols have to obey."
+ :abstract t)
+
+(defgeneric rudel-disconnect ((this rudel-connection))
+ "Close the connection.")
+
+(defgeneric rudel-change-color- ((this rudel-connection) color) ;; TODO name
+ "")
+
+(defgeneric rudel-publish ((this rudel-connection) document)
+ "")
+
+(defgeneric rudel-subscribe-to ((this rudel-connection) document)
+ "")
+
+(defgeneric rudel-unsubscribe-from ((this rudel-connection) document) ; TODO name should be rudel-unsubscribe
+ "")
+
+(defgeneric rudel-local-insert ((this rudel-connection))
+ "")
+
+(defgeneric rudel-local-delete ((this rudel-connection))
+ "")
+
+(defgeneric rudel-remote-insert ((this rudel-connection))
+ "")
+
+(defgeneric rudel-remote-delete ((this rudel-connection))
+ "")
+
+
+;;; Class rudel-user
+;;
+
+(defclass rudel-user (eieio-named
+ eieio-speedbar-file-button
+ rudel-hook-object)
+ ((color :initarg :color
+ :accessor rudel-color
+ :documentation
+ "Color used to indicate ownership or authorship
+by the user. Examples includes text written by the user or the
+user name itself.")
+ (change-hook :initarg :change-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when this user object
+changes."))
+ "Objects of this class represent users participating in
+collaborative editing session. Note that a participating user
+does not have to be connected to the session at any given time."
+ :abstract t)
+
+(defmethod rudel-display-string ((this rudel-user)
+ &optional use-images align)
+ "Return a textual representation of THIS for user interface stuff."
+ (with-slots ((name :object-name) color) this
+ (propertize
+ (concat
+ (when use-images
+ (propertize "*" 'display rudel-icon-person))
+ name)
+ 'face (list :background color)))
+ )
+
+
+;;; Class rudel-document
+;;
+
+(defclass rudel-document (eieio-named
+ eieio-speedbar-file-button
+ rudel-hook-object)
+ ((session :initarg :session
+ :type rudel-session
+ :documentation
+ "")
+ (buffer :initarg :buffer
+ :type (or null buffer)
+ :initform nil
+ :documentation
+ "")
+ (subscribed :initarg :subscribed
+ :type list
+ :initform nil
+ :documentation
+ "")
+ ;; Hooks
+ (subscribe-hook :initarg :subscribe-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user subscribes to
+this document object.")
+ (unsubscribe-hook :initarg :unsubscribe-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user unsubscribes
+from this document object.")
+ (attach-hook :initarg :attach-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a buffer is attached
+to this document object.")
+ (detach-hook :initarg :detach-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when the attached buffer
+is detached from this document object."))
+ "This class represents a document, which participants of a
+collaborative editing session can subscribe to."
+ :abstract t)
+
+(defmethod rudel-unique-name ((this rudel-document))
+ "Returns a suggested name for the buffer attached to THIS document."
+ (object-name-string this))
+
+(defmethod rudel-suggested-buffer-name ((this rudel-document))
+ "Returns a suggested name for the buffer attached to THIS document."
+ (rudel-unique-name this))
+
+(defmethod rudel-attached-p ((this rudel-document))
+ (with-slots (buffer) this
+ buffer))
+
+(defmethod rudel-attach-to-buffer ((this rudel-document) buffer)
+ "Attach THIS document to BUFFER"
+ (with-slots ((doc-buffer :buffer)) this
+ ;; Set buffer slot of THIS to BUFFER and associated THIS with
+ ;; BUFFER.
+ (setq doc-buffer buffer)
+ (rudel-set-buffer-document this buffer)
+
+ (with-current-buffer doc-buffer
+ ;; Add the handler function for buffer changes to the buffer's
+ ;; change hook.
+ (add-hook 'after-change-functions
+ #'rudel-handle-buffer-change
+ nil t)
+
+ ;; Store change data before the change a done. This is necessary
+ ;; because the number of bytes (not characters) cannot otherwise
+ ;; be recovered after a deletion.
+ (add-hook 'before-change-functions
+ #'rudel-buffer-change-workaround
+ nil t)
+
+ ;; Add a handler to the kill-buffer hook to unsubscribe from the
+ ;; document when the buffer gets killed.
+ (add-hook 'kill-buffer-hook
+ #'rudel-unpublish-buffer
+ nil t)
+
+ ;;
+ (add-hook 'change-major-mode-hook
+ #'rudel-handle-major-mode-change
+ nil t))
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'attach-hook doc-buffer))
+ )
+
+(defmethod rudel-detach-from-buffer ((this rudel-document))
+ "Detach document THIS from its buffer.
+Do nothing, if THIS is not attached to any buffer."
+ (with-slots (buffer) this
+ (let ((buffer-save buffer))
+
+ ;; Only try to detach from BUFFER, if it is non-nil. BUFFER can
+ ;; be nil, if the user did not subscribe to the document, or
+ ;; unsubscribed after subscribing.
+ (when buffer
+
+ (with-current-buffer buffer
+ ;; Remove our handler function from the kill-buffer hook.
+ (remove-hook 'kill-buffer-hook
+ #'rudel-unpublish-buffer
+ t)
+
+ ;; Remove our handler function from the after-change hook.
+ (remove-hook 'after-change-functions
+ #'rudel-handle-buffer-change
+ t)
+
+ ;; Remove our handler function from the before-change hook.
+ (remove-hook 'before-change-functions
+ #'rudel-buffer-change-workaround
+ t)
+
+ ;; Remove all overlays.
+ (rudel-overlays-remove-all)
+
+ ;; Remove the major mode change handler.
+ (remove-hook 'change-major-mode-hook
+ #'rudel-handle-major-mode-change
+ t))
+
+ ;; Unset buffer slot of THIS and delete association of THIS with
+ ;; BUFFER.
+ (rudel-set-buffer-document nil buffer)
+ (setq buffer nil))
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'detach-hook buffer-save)))
+ )
+
+(defmethod rudel-add-user ((this rudel-document) user)
+ "Add USER to the list of subscribed users of THIS.
+
+Runs object hook (see `rudel-hook-object') `subscribe-hook' with
+arguments THIS and USER."
+ ;; Add USER to list.
+ (object-add-to-list this :subscribed user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'subscribe-hook user))
+
+(defmethod rudel-remove-user ((this rudel-document) user)
+ "Remove USER from the list of subscribed users of THIS.
+
+Runs object hook (see `rudel-hook-object') `unsubscribe-hook'
+with arguments THIS and USER."
+ ;; Remove USER from list.
+ (object-remove-from-list document :subscribed user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'unsubscribe-hook user))
+
+(defmethod rudel-insert ((this rudel-document) position data)
+ "Insert DATA at POSITION into the buffer attached to THIS.
+When POSITION is nil `point-max' is used to determine the
+insertion position.
+Modification hooks are disabled during the insertion."
+ (with-slots (buffer) this
+ (save-excursion
+ (set-buffer buffer)
+
+ (unless position
+ (setq position (- (point-max) 1)))
+
+ (let ((inhibit-modification-hooks t))
+ (goto-char (+ position 1))
+ (insert data))))
+ )
+
+(defmethod rudel-delete ((this rudel-document) position length)
+ "Delete a region of LENGTH character at POSITION from the buffer attached to THIS.
+Modification hooks are disabled during the insertion."
+ (with-slots (buffer) this
+ (save-excursion
+ (set-buffer buffer)
+
+ (let ((inhibit-modification-hooks t))
+ (delete-region (+ position 1) (+ position length 1)))))
+ )
+
+(defmethod rudel-local-operation ((this rudel-document) operation)
+ "Apply the local operation OPERATION to THIS."
+ (with-slots (session buffer) this
+ (with-slots (connection (user :self)) session
+ (dolist (operators (list
+
+ ;; Update overlays
+ (rudel-overlay-operators
+ "overlay-operators"
+ :document this
+ :user user)
+
+ ;; Notify connection
+ (rudel-connection-operators
+ "connection-operators"
+ :connection connection
+ :document this)))
+
+ ;; Apply the operation using each set of operators
+ (rudel-apply operation operators))))
+ )
+
+(defmethod rudel-remote-operation ((this rudel-document) user operation)
+ "Apply the remote operation OPERATION performed by USER to THIS."
+ (dolist (operators (append
+
+ ;; Update buffer contents
+ (list (rudel-document-operators
+ "document-operators"
+ :document this))
+
+ ;; Update overlays
+ (when user
+ (list (rudel-overlay-operators
+ "overlay-operators"
+ :document this
+ :user user)))))
+
+ ;; Apply the operation using each set of operators
+ (rudel-apply operation operators))
+ )
+
+(defmethod rudel-chunks ((this rudel-document))
+ "Return a list of text chunks of the associated buffer.
+Each element in the chunk is a list structured like this (START
+END AUTHOR). START and END are numbers, AUTHOR is of type (or
+null rudel-user-child)."
+ (with-slots (buffer) this
+ ;; Extract buffer string and a list of chunks partitioning the
+ ;; string according to the respective author (or nil).
+ (with-current-buffer buffer
+ (let ((string (buffer-string)) ;; TODO no-properties?
+ (overlay-chunks (mapcar
+ (lambda (overlay)
+ (list (- (overlay-start overlay) 1)
+ (- (overlay-end overlay) 1)
+ (rudel-overlay-user overlay)))
+ (sort* (rudel-author-overlays)
+ '< :key 'overlay-start)))
+ (last)
+ (augmented-chunks))
+
+ ;; Iterate through the list of chunks to find gaps between
+ ;; chunks (also before the first) and insert entries with
+ ;; author nil accordingly.
+ (dolist (chunk overlay-chunks)
+ (when (or (and (not last)
+ (> (nth 0 chunk) 0))
+ (and last
+ (/= (nth 1 last)
+ (nth 0 chunk))))
+ (push (list (if last (nth 1 last) 0)
+ (nth 0 chunk)
+ nil)
+ augmented-chunks))
+ (push chunk augmented-chunks)
+ (setq last chunk))
+
+ ;; If there is text after the last chunk, create another one
+ ;; with author nil. If there were no chunks at all, this chunk
+ ;; can also cover the whole buffer string.
+ (when (or (and (not last)
+ (/= (length string) 0))
+ (and last
+ (/= (nth 1 last) (length string))))
+ (push (list (if last (nth 1 last) 0)
+ (length string)
+ nil)
+ augmented-chunks))
+
+ ;; Sort chunks according to the start position.
+ (sort* augmented-chunks '< :key 'car))))
+ )
+
+
+;;; Buffer-related functions
+;;
+
+(defun rudel-buffer-has-document-p (&optional buffer)
+ "Return non-nil if a document object is attached to BUFFER.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (buffer-local-value 'rudel-buffer-document buffer))
+
+(defun rudel-buffer-document (&optional buffer)
+ "Return the document object attached to BUFFER.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (buffer-local-value 'rudel-buffer-document buffer))
+
+(defun rudel-set-buffer-document (document &optional buffer)
+ "Associate BUFFER to DOCUMENT.
+If DOCUMENT is nil, make it not associated to any buffer.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (setq rudel-buffer-document document)))
+
+(defun rudel-handle-buffer-change (from to length)
+ "Handle buffer change at range FROM to TO with length LENGTH by relaying them to the document object of the buffer.
+See after-change-functions for more information."
+ (when (rudel-buffer-has-document-p)
+ (let ((document (rudel-buffer-document))
+ (text)) ; TODO with-rudel-buffer-document?
+ (cond
+ ;; The change was an insert
+ ((and (/= from to)
+ (zerop length))
+ (with-slots (buffer) document
+ (with-current-buffer buffer
+ (setq text (buffer-substring-no-properties from to)))
+ (rudel-local-operation document
+ (rudel-insert-op
+ "insert"
+ :from (- from 1)
+ :data text))))
+
+ ;; The change was a delete
+ ((and (= from to)
+ (not (zerop length)))
+ (rudel-local-operation document
+ (rudel-delete-op
+ "delete"
+ :from (- from 1)
+ :length length)))
+
+ ;; The operation was neither an insert nor a delete. This seems
+ ;; to mean that the region has changed arbitrarily. The only
+ ;; option we have is sending a delete and corresponding insert
+ ;; message that emulate the change.
+ (t
+ (with-slots (buffer) document
+ (with-current-buffer buffer
+ (setq text (buffer-substring-no-properties from to)))
+ (rudel-local-operation document
+ (rudel-delete-op
+ "delete"
+ :from (- from 1)
+ :length length))
+ (rudel-local-operation document
+ (rudel-insert-op
+ "insert"
+ :from (- from 1)
+ :data text)))))))
+ )
+
+(defun rudel-buffer-change-workaround (from to)
+ (when (/= from to)
+ (setq rudel-buffer-change-workaround-data
+ (list from to
+ (buffer-substring-no-properties from to)))))
+
+
+;;; Protection against major mode changes
+;;
+
+(defvar rudel-mode-changed-buffers nil
+ "List of buffers that may need to be repaired after a major
+ mode change.")
+
+(defun rudel-handle-major-mode-change ()
+ "Store the current buffer to repair damage done by major mode change.
+
+Note: The way this works is inspired by mode-local.el by David
+Ponce and Eric M. Ludlam."
+ ;; Store the buffer for later repair.
+ (add-to-list 'rudel-mode-changed-buffers (current-buffer))
+
+ ;; Schedule `rudel-after-major-mode-change' to run after the
+ ;; command, that caused the major mode change.
+ (add-hook 'post-command-hook
+ #'rudel-after-major-mode-change)
+ )
+
+(defun rudel-after-major-mode-change ()
+ "Repair damage done by major mode changes.
+As a function in `post-command-hook', this is run after there was
+a `major-mode' change.
+
+Note: The way this works is inspired by mode-local.el by David
+Ponce and Eric M. Ludlam."
+ ;; Remove this function from `post-command-hook'.
+ (remove-hook 'post-command-hook
+ #'rudel-after-major-mode-change)
+
+ ;; Repair all buffers affected by the major mode change.
+ (dolist (buffer rudel-mode-changed-buffers)
+ (let ((document (buffer-local-value 'rudel-buffer-document
+ buffer)))
+ (rudel-attach-to-buffer document buffer)))
+ )
+
+
+;;; Interactive functions
+;;
+
+;;;###autoload
+(defun rudel-join-session (info)
+ "Join the collaborative editing session described by INFO.
+INFO is a property list that describes the collaborative editing
+session in terms of properties like :host, :port
+and :encryption. The particular properties and their respective
+meanings depend on the used backend.
+
+When called interactively, all data required to join a session
+will be prompted for."
+ (interactive
+ ;; Try the discover method of session initiation backends to find
+ ;; available sessions.
+ (list
+ (let ((info)
+ (session-initiation-backend))
+ (while (not info)
+ (message "Discovering Sessions ...")
+ (let* ((sessions (rudel-session-initiation-discover
+ session-initiation-backend))
+ (maybe-info (if (= (length sessions) 1)
+ (car sessions)
+ (rudel-read-session
+ sessions "Choose Session: " 'object))))
+ (if (rudel-backend-cons-p maybe-info)
+ (setq session-initiation-backend (car maybe-info))
+ (setq info maybe-info))))
+ info)))
+
+ ;; First, create the session object.
+ (let* ((backend (cdr (plist-get info :backend)))
+ (session (rudel-client-session
+ (plist-get info :name)
+ :backend backend))
+ (connection))
+ ;; Give the backend a chance to collect remaining connect
+ ;; info. For session initiation methods like Zeroconf, we have the
+ ;; _connection_ info, but are still missing the username and
+ ;; stuff.
+ (setq info (rudel-ask-connect-info backend info))
+
+ ;; Add the session object to the connect information.
+ (plist-put info :session session)
+
+ ;; Ask BACKEND to connect using INFO. Do not catch errors since
+ ;; the error messages are probably the best feedback we can give.
+ (setq connection (rudel-connect backend info))
+
+ ;; Set the connection slot of the session object and store it
+ ;; globally.
+ (oset session :connection connection)
+ (setq rudel-current-session session)
+
+ ;; Reset the global session variable when the session ends.
+ (object-add-hook session 'end-hook
+ (lambda (session)
+ (setq rudel-current-session nil)))
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-start-hook session))
+ )
+
+;;;###autoload
+(defun rudel-host-session ()
+ "Host a collaborative editing session.
+All data required to host a session will be prompted for
+interactively."
+ (interactive)
+ ;; If necessary, ask the user for the backend we should use.
+ (let* ((backend (cdr (rudel-backend-choose
+ 'protocol
+ (lambda (backend)
+ (rudel-capable-of-p backend 'host)))))
+ (info (rudel-ask-host-info backend))
+ (server))
+
+ ;; Try to create the server
+ (condition-case error-data
+ (setq server (rudel-host backend info))
+ ('error
+ (error "Could not host session using backend `%s' with %s: %s"
+ (object-name-string backend)
+ info
+ (car error-data))))
+ server))
+
+;;;###autoload
+(defun rudel-end-session ()
+ "End the current collaborative editing session."
+ (interactive)
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ ;; Actually end the session.
+ (rudel-end rudel-current-session)
+ )
+
+;;;###autoload
+(defun rudel-change-color ()
+ "Change the color associated with the local user.
+Not all backends support this operation."
+ (interactive)
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (backend connection self) rudel-current-session
+ ;; Make sure the backend can change colors.
+ (unless (rudel-capable-of-p backend 'change-color)
+ (error "Backend `%s' cannot change colors"
+ (object-name-string backend)))
+
+ (with-slots ((name :object-name) color) self
+ ;; Ask the user for a new color.
+ (setq color (read-color "New Color: " t))
+
+ ;; Tell the connection to announce the change and change it in
+ ;; our user object.
+ (rudel-change-color- connection color)
+
+ ;; Run the change hook.
+ (object-run-hook-with-args self 'change-hook)
+
+ ;; Update overlay color.
+ (rudel-overlay-set-face-attributes
+ (rudel-overlay-make-face-symbol 'author name)
+ color)))
+ )
+
+;;;###autoload
+(defun rudel-subscribe (document)
+ "Subscribe to DOCUMENT offered by a peer in a collaborative editing session.
+When called interactively, DOCUMENT is prompted for interactively."
+ (interactive
+ (list (progn
+ ;; We have to retrieve the document list from an active
+ ;; session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+ ;; Select unsubscribed documents.
+ (let ((documents (rudel-unsubscribed-documents
+ rudel-current-session)))
+ ;; Already subscribed to all documents. This is an error.
+ (when (null documents)
+ (error "No unsubscribed documents"))
+ ;; Read an unsubscribed document.
+ (rudel-read-document documents nil 'object)))))
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ ;; Create a new buffer and attach the document to it.
+ (let* ((name (rudel-suggested-buffer-name document))
+ (buffer (funcall rudel-allocate-buffer-function name)))
+ (rudel-attach-to-buffer document buffer)
+
+ (let ((connection (oref (oref document :session) :connection)))
+ (rudel-subscribe-to connection document))
+
+ ;; Show the new buffer.
+ (set-window-buffer nil buffer))
+ )
+
+;;;###autoload
+(defun rudel-publish-buffer (&optional buffer)
+ "Make the BUFFER available for subscription to peers in a collaborative editing session.
+If BUFFER is nil, the current buffer is used."
+ (interactive (list nil))
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (when (rudel-buffer-has-document-p)
+ (error "Buffer already published or subscribed"))) ; TODO keep this?
+
+ ;;
+ (with-slots (backend connection self) rudel-current-session
+ (let ((document (rudel-make-document backend
+ (buffer-name buffer)
+ rudel-current-session)))
+ (rudel-add-document rudel-current-session document)
+
+ (rudel-attach-to-buffer document buffer)
+ (object-add-to-list document :subscribed self)
+
+ (rudel-publish connection document)))
+ )
+
+;;;###autoload
+(defun rudel-unpublish-buffer (&optional buffer)
+ "Deny peers access to BUFFER in a collaborative editing session.
+If BUFFER is nil, the current is used."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (unless (rudel-buffer-has-document-p)
+ (error "Buffer is not published")))
+
+ ;;
+ (with-slots (connection) rudel-current-session
+ (let ((document (rudel-buffer-document buffer)))
+ (rudel-detach-from-buffer document)
+
+ (rudel-unsubscribe-from connection document)))
+ )
+
+(provide 'rudel)
+;;; rudel.el ends here
diff --git a/emacs.d/lisp/rudel/ChangeLog b/emacs.d/lisp/rudel/ChangeLog
new file mode 100644
index 0000000..03c4fab
--- /dev/null
+++ b/emacs.d/lisp/rudel/ChangeLog
@@ -0,0 +1,2403 @@
+2009-10-22 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * TODO (Future): added BEEP and SubEthaEdit tasks
+
+2009-10-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-version): bumped to 0.3
+ * Project.ede (project rudel): bumped version to 0.3
+
+ * TODO: whitespace fixes
+ (Milestone rudel-0.4): new; focus on telepathy transport
+ (Milestone rudel-0.3): added infinote, document trees
+
+2009-10-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * TODO: new file; TODO items for future development and releases
+
+2009-10-12 Phil Hagelberg <phil@enigma>
+
+ * rudel-mode.el
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line):
+ Replace reference to mode-line indicator that was not present in
+ Emacs 22.
+
+ * rudel-compat.el: add rudel-get-coding-system wrapper function.
+ * rudel-obby-util.el (with-parsed-args): Replace call to
+ Emacs23-specific coding-system-from-name function with
+ rudel-get-coding-system.
+
+ rudel-compat.el: Add string-match-p if not present. (< Emacs 23)
+
+ * rudel-mode.el, rudel-overlay.el: Move use of :safe flag from
+ defcustom to a separate put. Required for Emacs 22 compatibility.
+
+ * rudel-loaddefs.el: Only require rudel-zeroconf if zeroconf is
+ available.
+
+2009-10-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ fixed error message
+
+2009-10-08 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter.el (header): downcased keywords
+ (object-print): new method; add revisions and log length to string
+ * jupiter/jupiter-nop.el (header): downcased keywords; cosmetic
+ representation changes to "commentary" section
+ * jupiter/jupiter-insert.el (header): downcased keywords; cosmetic
+ changes to "commentary" section
+ (object-print): new method; add start, end, length and data to
+ string representation
+ * jupiter/jupiter-delete.el (header): downcased keywords; cosmetic
+ changes to "commentary" section
+ (jupiter-transform): cosmetic changes
+ (object-print): new method; add position and length to string
+ representation
+ * jupiter/jupiter-compound.el (header): downcased keywords;
+ cosmetic changes to "commentary" section
+ (object-print): new method; add number of children to string
+ representation
+
+2009-10-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * doc/card.tex (Session Initiation): mention configured sessions;
+ explain Zeroconf-advertised session in more detail
+
+2009-10-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * doc/card.tex (Joining a Session ...): added global and user
+ passwords
+
+ * rudel.el (rudel-version): use list representation instead of
+ float
+ (rudel-allocate-buffer-function): added documentation string
+
+ * INSTALL (COMPILING): fixed typo
+
+2009-10-06 Phil Hagelberg <phil@enigma>
+
+ * README (JOINING): Mention `rudel-configured-sessions'
+ customization.
+
+ * README (INTRODUCTION): emphasize obby backend being the only
+ supported one so far
+ (JOINING): update example session with passwords.
+
+ * rudel-loaddefs.el: Add autoloads for rudel-host-session and
+ rudel-speedbar
+
+2009-10-05 Phil Hagelberg <phil@enigma>
+
+ * README: Mention Eshell issue and license.
+
+2009-10-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el (make-pulsing-progress-reporter): removed;
+ `make-progress-reporter' is sufficient
+ (progress-reporter-pulse): store index in the car of the reporter;
+ set last update time of the reporter
+ * obby/rudel-obby.el (rudel-connect): use `make-progress-reporter'
+ instead of `make-pulsing-progress-reporter'
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-subscribe-to): cosmetic changes in
+ status messages
+
+ * ChangeLog: updated
+
+2009-10-02 Phil Hagelberg <phil@enigma>
+
+ * INSTALL: Mention CEDET's inclusion in Emacs
+
+ * rudel-state-machine.el (rudel-state-wait): update progress
+ reporter usage to match rudel-compat.el
+
+ * rudel-compat.el: Use updated progress reporters
+ (progress-reporter-update): may be used by pulsing reporters too
+ (make-progress-reporter): nil max value returns pulsing reporter
+ (progress-reporter-force-update): may be used by pulsing reporters
+ too
+ (progress-reporter-pulsing-p): added
+ (progress-reporter-pulse): removed message change option
+
+2009-10-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (rudel-state-wait): accept callback
+ function instead of message; adjusted documentation string
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): when
+ calling `rudel-state-wait', provide a callback; the callback
+ controls a progress reporter
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-subscribe-to): when calling
+ `rudel-state-wait', provide a callback; the callback controls a
+ progress reporter
+
+ * rudel-compat.el (progress-reporter-pulse): store index as float
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_create):
+ cosmetic changes of printed messages
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ cosmetic changes of printed messages
+
+ * rudel.el (rudel-session::rudel-remove-document): when necessary,
+ detach document first; added documentation string
+ (rudel-document::rudel-attached-p): new method; return non-nil
+ when document is attached to a buffer
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part):
+ promoted warning severity to :warning
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ fixed lookup of document; added warning message in case it is not
+ found
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/rename):
+ promoted warning severity to :warning
+ (rudel-obby-connection::rudel-unpublish): new method; ask server
+ to remove a document
+
+2009-10-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (rudel-state-wait): fixed progress range
+ [0, 100] -> [0, 1]; fixed reference to reporter object
+ * obby/rudel-obby.el (rudel-obby-send): removed remnants of calls
+ to `working-*' functions; call `progress-reporter-pulse' just
+ before `progress-reporter-done'
+
+2009-09-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el: only define pulsing progress reporter when
+ Emacs does not have one itself
+ (header): downcased keywords
+ (make-pulsing-progress-reporter): renamed
+ `make-progress-reporter-pulse' ->
+ `make-pulsing-progress-reporter'; cosmetic changes; explanatory
+ comment
+ (progress-reporter-pulse): added documentation string
+ Suggested by Phil Hagelberg
+
+ * rudel-compat.el (progress-pulse-values): new variable; indicator
+ strings used by pulsing progress reporter
+ (make-progress-reporter-pulse): new function; creates pulsing
+ progress reporter
+ (progress-reporter-pulse): new function; updates pulsing progress
+ reporter
+ Suggested by Phil Hagelberg
+
+2009-09-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-server-state-before-join::rudel-obby/net6_client_login):
+ accept two additional arguments: global-password and user-password
+
+ * rudel-session-initiation.el (rudel-configured-sessions):
+ improved documentation string
+
+2009-09-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): wording
+ (INSTALLING): mention other things that cause rudel to be
+ autoloaded; minor cosmetic changes
+ (COMPILING): fixed filename compile.el -> rudel-compile.el
+
+ * rudel-compile.el (header): added copyright and meta data
+ (code): let-bind rudel-dir; call `byte-recompile-directory' just
+ once since it operates recursively
+
+2009-09-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el (header): better documentation
+ (require rudel-state-machine): now required for state machine
+ style handling of client connections
+ (require rudel-obby-state): now required; provides base class for
+ states
+ (rudel-obby-server-state-new): new class; client connection state
+ new
+ (rudel-obby-server-state-encryption-negotiate): new class; client connection state
+ for negotiating encryption
+ (rudel-obby-server-state-before-join): new class; client connection state
+ for waiting for login request
+ (rudel-obby-server-state-new): new class; client connection state
+ entered after session setup and joining is complete
+ (rudel-obby-server-connection-states): new variable; list of
+ states and their symbolic names
+ (rudel-obby-client): now derived from rudel-state-machine
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info):
+ check for :global-password and :user-password correctly; do not
+ put them into the list when they are ""
+ (rudel-obby-backend::rudel-connect): comment
+
+ * rudel-session-initiation.el
+ (rudel-configured-sessions-backend::rudel-discover): let
+ `rudel-session-initiation-adjust-info' do the heavy lifting
+ (rudel-session-initiation-adjust-info): new function; adjust
+ arguments that need adjusting in a session information property
+ list
+
+ * rudel-session-initiation.el (rudel-configured-sessions): more
+ precise specification of the customization type
+
+2009-09-27 Phil Hagelberg <technomancy@gmail.com>
+
+ * compile.el: renamed compile.el -> rudel-compile.el
+
+ * INSTALL: Mention new install process using compile.el and
+ rudel-loaddefs.el.
+
+ * rudel-loaddefs.el: Autoload rudel as one unit instead of
+ piece-by-piece. Remove eieio dependency from autoloads.
+
+ * compile.el: Perform compilation from Elisp
+
+ * Makefile: Remove error-prone CEDET-autogenerated build scripts.
+
+2009-09-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-session-initiation.el
+ (rudel-configured-sessions-backend::rudel-discover): fixed a bug
+ that dropped the last option in each configured session
+
+ * rudel-session-initiation.el (rudel-configured-sessions): new
+ customization option; contains a list of session information lists
+ (rudel-ask-protocol-backend::initialize-instance): maybe call next
+ method
+ (rudel-configured-sessions-version): new constant; version of the
+ configured-sessions backend
+ (rudel-configured-sessions-backend): new class;
+ configured-sessions backend
+ (rudel-configured-sessions-backend::initialize-instance): new
+ method; set version slot
+ (rudel-configured-sessions-backend::rudel-discover): new method;
+ "discover" configured sessions
+ (autoload rudel-add-backend): register
+ rudel-configured-sessions-backend as a protocol backend
+
+ * rudel-chat.el (rudel-chat-buffer-name): new constant; name chat
+ log buffer
+ (rudel-chat-handle-buffer): raise buffer when logging a chat
+ message
+
+ * rudel-debug.el (header): fixed meta-data and license
+ (rudel-debug-sent-data-face): added documentation string
+ (rudel-debug-received-data-face): added documentation string
+ (rudel-debug-received-processed-data-face): added documentation
+ string
+ (rudel-debug-state-face): added documentation string
+ (rudel-debug-special-face): added documentation string
+ (rudel-suspend-session-socket): added documentation string
+ (rudel-resume-session-socket): added documentation string
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): use
+ `display-warning' instead of `warn'
+ * obby/rudel-obby-state.el (rudel-obby-state::rudel-accept): use
+ `display-warning' instead of `warn'
+ (rudel-obby-document-handler::rudel-obby/obby_document): use
+ `display-warning' instead of `warn'
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part): use
+ `display-warning' instead of `warn'
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/record):
+ use `display-warning' instead of `warn'
+ * rudel-backend.el (rudel-backend-factory::rudel-load-backends):
+ use `display-warning' instead of `warn'
+
+ * obby/rudel-obby-client.el (require rudel-chat): used when
+ handling chat messages
+ (rudel-obby-client-state-idle::rudel-obby/obby_message): new
+ method; handles obby 'message' messages by dispatching to
+ `rudel-chat-dispatch-message'
+ * rudel-chat.el (whole file): new file; handling of incoming chat
+ messages
+ * Project.ede (target rudel): added rudel-chat.el
+ * Makefile (target rudel_LISP): added rudel-chat.el
+
+2009-09-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-state.el (rudel-obby-server-connection-state):
+ new class; base class for server connection states
+ (rudel-obby-server-connection-state::rudel-broadcast): new method;
+ broadcast message to a set of receivers
+
+2009-09-25 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): new
+ error state they-finalized; handle join-failed error specially
+ * obby/rudel-obby-client.el (rudel-obby-client-state-join-failed):
+ improved comments
+ (rudel-obby-client-state-they-finalized): new state class; used to
+ indicate that the connection was closed by the peer
+ (rudel-obby-client-connection-states): added they-finalized
+ (rudel-obby-connection::rudel-close): switch state machine to
+ they-finalized
+ (rudel-obby-connection::rudel-subscribe-to): new error state
+ they-finalized
+
+ * rudel.el (rudel-client-session::connection): allow nil value
+ (rudel-client-session::rudel-end): only try to disconnect the
+ connection if it is non-nil; ignore errors during disconnect
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-encryption-start::rudel-obby/net6_encryption_begin):
+ do not require rudel-tls; do not try to start TLS encryption if
+ the connection does not support it
+ * rudel-tls.el (rudel-tls-make-process): mark process as
+ supporting TLS encryption
+
+ * obby/rudel-obby-state.el (rudel-obby/net6_ping): return nil to
+ prevent erratic behavior of the state machine
+
+ * rudel-interactive.el (rudel-allocate-buffer-clear-existing):
+ added missing whitespace in prompt string
+
+2009-09-24 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-tls.el (rudel-tls-start-tls): changed displayed message
+ (rudel-tls-wait-init): ignore all lines until "- Simple Client
+ Mode.*" is received; then switch back old filter
+ (rudel-tls-wait-handshake): ignore all lines until "-
+ Compression.*" is received; then switch to established filter
+ (rudel-tls-established): do not ignore any lines other than
+ "- Peer has closed the GNUTLS connection"
+
+ * obby/rudel-obby.el (rudel-ask-connect-info): ask for global and
+ user passwords
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-enter): transmit global
+ and user passwords when available
+
+ * obby/rudel-obby-errors.el
+ (rudel-obby-error-wrong-global-password): fixed error code
+ (rudel-obby-error-wrong-user-password): fixed error code
+ (rudel-obby-error-protocol-version-mismatch): fixed error code
+ (rudel-obby-error-not-encrypted): fixed error code
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-obby/net6_login_failed):
+ recognize wrong global/user password error codes
+
+ * obby/rudel-obby-debug.el (whole file): new file; debugging
+ functions for the obby backend
+ * rudel-debug.el (whole file): new file; debugging functions
+
+ * obby/rudel-obby-errors.el
+ (rudel-obby-error-wrong-global-password): new constant; error code
+ for wrong global password
+ (rudel-obby-error-wrong-user-password): new constant; error code
+ for wrong user password
+ (rudel-obby-error-protocol-version-mismatch): new constant; error
+ code for protocol version mismatch
+ (rudel-obby-error-not-encrypted): new constant; error code for not
+ encrypted
+
+ * Project.ede (target rudel): added rudel-transport.el
+ * Makefile (target rudel_LISP): added rudel-transport.el
+ * rudel-transport.el (whole file): new file; interface for
+ transport backends
+
+2009-09-20 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-remote-operation): added byte -> char
+ conversion before the operation is applied to the server-side
+ document; updated comments
+
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-broadcast):
+ cosmetic changes
+ (rudel-obby-client::rudel-obby/net6_client_login): cosmetic
+ changes; improved comments
+ (rudel-obby-client::rudel-obby/obby_document): changed
+ documentation string; cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/record): added a
+ comment
+ (rudel-obby-client::rudel-remote-operation): improved comments
+
+ * obby/rudel-obby-server.el (header): added header comment
+ (rudel-obby-client::rudel-obby/obby_document_create): changed
+ documentation comment
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): changed
+ documentation comment; cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe):
+ cosmetic changes
+ (rudel-obby-server::initialize-instance): do not run :after; call
+ next method
+ (rudel-obby-server::rudel-broadcast): signal wrong-type-argument
+ instead of just error; cosmetic changes
+ (rudel-obby-server::rudel-check-username-and-color): changed
+ comments
+ (rudel-obby-server::object-print): new method; generate string
+ representation with number of clients
+
+2009-09-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ construct the operation and use `rudel-remote-operation'
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ construct the operation and use `rudel-remote-operation'
+ (rudel-obby-client::rudel-remote-operation): new method; transform
+ and apply an operation object to the server-side document; send
+ operation to all other clients
+ (rudel-obby-server::rudel-broadcast): cosmetic changes
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/del): swapped
+ local and remote revisions in the operation name to be consistent
+ with record/ins; does not affect behavior
+
+2009-09-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions--update-from-document):
+ force mode line update
+ (rudel-header-subscriptions--update-from-buffer): force mode line
+ update
+ (rudel-header-subscriptions-minor-mode): force mode line update
+
+ * rudel-mode.el
+ (rudel-mode-line-publish-state-unpublished-string): new
+ customization option; string used to indicate that a buffer is not
+ published
+ (rudel-mode-line-publish-state-published-string): new
+ customization option; string used to indicate that a buffer is
+ published
+ (rudel-mode-line-publish-state--update-string): use
+ `rudel-mode-line-publish-state-unpublished-string' and
+ `rudel-mode-line-publish-state-unpublished-string'
+
+ * rudel.el (rudel-session::end-hook): new slot; stores handlers of
+ the end hook
+ (rudel-session::rudel-end): run end hook
+ (rudel-session::rudel-join-session): install handler on session
+ end hook to set `rudel-current-session' to nil
+ (rudel-session::rudel-end-session): no need to run
+ rudel-session-end-hook or reset `rudel-current-session'
+ * rudel-hooks.el (rudel-hooks--session-start): add handler for the
+ end hook of the session
+ (rudel-hooks--session-end): remove the handler from end hook of
+ the session; run the rudel-session-end hook
+ (rudel-hooks--install-handlers): do install handler for
+ rudel-session-end hook; this is now done by installing the in the
+ session object
+ (rudel-hooks--uninstall-handlers): no need to remove
+ rudel-session-end hook
+
+ * rudel-util.el (rudel-socket-owner::rudel-state-change): cover
+ more states
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document_remove):
+ implemented, was stub; untested though
+
+2009-09-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_join): check
+ whether we have a user object for the specified user id; modify
+ the existing object if there is one
+
+2009-09-09 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * zeroconf/Makefile (whole file): regenerated
+ * wave/Makefile (whole file): regenerated
+ * Makefile (target all): build target doc
+ (target doc): new target; build documentation
+ (target tags): build target tags in doc directory
+ (target dist): build target dist in doc directory
+
+2009-09-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * telepathy/rudel-telepathy.el (header): fixes
+ (require rudel-backend): required, since we define a backend
+ (require rudel-transport): it is a transport backend
+ (class rudel-telepathy-backend): derived from
+ rudel-transport-backend
+ (rudel-telepathy-backend::initialize-instance): new method; set
+ version slot
+ (autoloading): upgraded to new backend registration style
+
+ * INSTALL (REQUIREMENTS): mention Avahi
+
+2009-09-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (require rudel-util): required for `rudel-hook-object'
+
+ * rudel-util.el (property svn:executable): removed property
+ * rudel-overlay.el (property svn:executable): removed property
+
+ * doc/Project.ede (whole file): new file; project file for the
+ documentation directory
+ * doc/Makefile (whole file): new file; generated Makefile for the
+ documentation directory
+ * doc/card.tex (whole file): new file; reference card for Rudel;
+ source
+ * doc/card.pdf (whole file): new file; reference card for Rudel;
+ PDF
+
+2009-09-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-document): added comment
+ (rudel-allocate-buffer-clear-existing): handle the case in which
+ case a buffer with the desired name exists and is attached to a
+ different document; added some comments
+
+ * rudel-mode.el (header): list all provided modes; bump version
+ (require rudel-hooks): required for global hooks
+ (rudel-mode-line-publish-state-string): new variable; buffer
+ local, holds publish state string for buffer
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line): new
+ function; add publish state indicator to mode line
+ (rudel-mode-line-publish-state--remove-indicator-from-mode-line):
+ new function; remove publish state indicator from mode line
+ (rudel-mode-line-publish-state--update-string): new function;
+ update publish state indicator according to buffer state
+ (rudel-mode-line-publish-state--document-attach): new function;
+ handle document attaching to buffer
+ (rudel-mode-line-publish-state--document-detach): new function;
+ handle document detaching from buffer
+ (rudel-mode-line-publish-state-minor-mode): new minor mode;
+ displays publish state of buffer in mode line
+ (global-rudel-mode-line-publish-state-mode): new minor mode;
+ globalization of `rudel-mode-line-publish-state-minor-mode'
+ (rudel-minor-keymap): menu entries for buffer local and global
+ mode line publish state mode
+
+ * rudel.el (require rudel-hooks): required or hook variables
+ (rudel-session-start-hook): moved to rudel-hooks.el
+ (rudel-session-end-hook): moved to rudel-hooks.el
+ * rudel-hooks.el (whole file): new file; contains hook variables
+ and mapping from object hooks to global hooks
+ * Project.ede (target rudel): added file rudel-hooks.el
+ * Makefile (target rudel_LISP): added file rudel-hooks.el
+
+2009-09-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions-minor-mode): improved
+ documentation string
+
+2009-08-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * zeroconf/Makefile (whole file): new file; generated Makefile for
+ the zeroconf subproject
+
+ * wave/rudel-wave.el (whole file): new file; main class of the
+ wave backend
+ * wave/Project.ede (whole file): new file; project file for the
+ wave subproject
+ * wave/Makefile (whole file): new file; generated Makefile for the
+ wave subproject
+ * Project.ede (target autoloads): added wave directory
+ * Makefile (LOADDIRS): added wave and zeroconf directories
+ (VERSION): bumped to 0.2
+ (target all): added wave and zeroconf
+ (tags): descend into zeroconf and wave directories
+ (dist): descend into zeroconf and wave directories
+
+2009-08-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-change-color): run the change hook of the self
+ user
+
+ * rudel-overlay.el (rudel-overlay-set-face-attributes): check the
+ face actually exists
+
+2009-08-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (rudel-header-subscriptions-use-images): new
+ variable; controls whether images are used when formatting user
+ names
+ (rudel-header-subscriptions-separator): new variable; separator
+ used when formatting user names
+ (rudel-header-subscriptions--make-format): new function; make a
+ format object for header line
+ (rudel-header-subscriptions--update-from-document): new function;
+ update header line from document
+ (rudel-header-subscriptions--update-from-buffer): new function;
+ update header line from buffer
+ (rudel-header-subscriptions--options-changed): new function;
+ update header line in all buffers that have
+ rudel-header-subscriptions-minor-mode enabled after customization
+ option change
+ (rudel-header-subscriptions--user-change): new function; update
+ header line after a user object change
+ (rudel-header-subscriptions--add-user): new function; watch newly
+ subscribed user and update header line
+ (rudel-header-subscriptions--remove-user): new function; stop
+ watching user and update header line
+ (minor mode rudel-header-subscriptions-minor-mode): new minor
+ mode; display subscribed users in buffer's header line
+ (rudel-header-subscriptions--attach): new function; enable header
+ subscription minor mode when attaching
+ (rudel-header-subscriptions--detach): new function; disable header
+ subscription minor mode when detaching
+ (rudel-header-subscriptions--add-document): new function; monitor
+ attaching/detaching of new document
+ (rudel-header-subscriptions--remove-document): new function; stop
+ monitoring attaching/detaching of new document
+ (rudel-header-subscriptions--session-start): new function; watch
+ documents being added/removed to/from the session
+ (rudel-header-subscriptions--session-end): new function; stop
+ watching documents being added/removed to/from the session
+ (minor mode global-rudel-header-subscriptions-mode): global minor
+ mode that controls `rudel-header-subscriptions-minor-mode' in
+ buffers
+ (advice global-rudel-header-subscriptions-mode): controls
+ adding/removing watches for added/removed documents when the
+ global mode is enabled/disabled
+ (rudel-minor-keymap): Added entries for
+ `rudel-header-subscriptions-minor-mode' and
+ `global-rudel-header-subscriptions-mode'
+
+2009-08-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * . (property svn:ignore): added patterns
+ * jupiter (property svn:ignore): added patterns
+ * obby (property svn:ignore): added patterns
+
+ * rudel.el (rudel-session::add-user-hook): new slot; add user hook
+ function list
+ (rudel-session::remove-user-hook): new slot; remove user hook
+ function list
+ (rudel-session::add-document-hook): updated documentation string
+ (rudel-session::remove-document-hook): updated documentation
+ string
+ (rudel-session::rudel-add-user): run add user hook
+ (rudel-session::rudel-remove-user): run remove user hook
+
+ * rudel.el (rudel-session-start-hook): new variable; session start
+ hook function list
+ (rudel-session-end-hook): new variable; session end hook function
+ list
+ (rudel-join-session): run session start hook
+ (rudel-end-session): run session end hook
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document_create): call
+ `generate-new-buffer-name' on complete buffer name; not just name
+ part
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): send
+ number of bytes instead of number of characters
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-document-synching::remaining-bytes):
+ fixed initarg num-bytes -> remaining-bytes
+
+ * rudel.el (rudel-session::add-document-hook): new slot; run when
+ a document gets added to the session
+ (rudel-session::remove-document-hook): new slot; run when a
+ document gets removed from the session
+ (rudel-session::rudel-add-document): run add document hook
+ (rudel-session::rudel-remove-document): run remove document hook
+ (rudel-document::unsubscribe-hook): fixed initarg subscribe-hook
+ -> unsubscribe-hook
+
+2009-08-25 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * www/index.html (Download): link to http://bazaar-vcs.org;
+ improved wording
+
+ * www/index.html (Download): changed link to source; add browse
+ source link for bzr
+
+ * INSTALL (REQUIREMENTS): precise CEDET release version
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_user_colour): run change hook
+ after setting slot
+ (rudel-obby-server::rudel-remove-client): run change hook after
+ setting slot
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/net6_client_part): run
+ change hook after setting slots
+ (rudel-obby-client-state-idle::rudel-obby/obby_user_colour): run
+ change hook after setting slot
+ * rudel.el (class rudel-user): derive from `rudel-hook-object'
+ (rudel-user::change-hook): new slot; stores change hook functions
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_user_colour): cosmetic changes
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): use
+ `rudel-add-user'
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): use
+ `rudel-remove-user'
+ (rudel-obby-server::rudel-check-username-and-color): whitespace
+ fixes
+
+2009-08-23 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::attach-hook): new slot; attach hook
+ function list
+ (rudel-document::detach-hook): new slot; detach hook function list
+ (rudel-document::rudel-attach-to-buffer): run hook `attach-hook'
+ (rudel-document::rudel-detach-from-buffer): run hook `detach-hook'
+ (rudel-document::rudel-add-user): improved documentation string
+ (rudel-document::rudel-remove-user): improved documentation string
+
+ * obby/rudel-obby.el
+ (rudel-obby-user::eieio-speedbar-object-buttonname): fixed typo
+
+2009-08-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/subscribe):
+ call `rudel-add-user'
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/unsubscribe):
+ call `rudel-remove-user'
+ * rudel.el (class rudel-document): mixin rudel-hook-object
+ (rudel-document::subscribe-hook): new slot; subscribe-hook
+ function list
+ (rudel-document::unsubscribe-hook): new slot; unsubscribe-hook
+ function list
+ (rudel-document::rudel-add-user): new method; add user to list of
+ subscribed users and run subscribe-hook
+ (rudel-document::rudel-remove-user): new method; remove user from
+ list of subscribed users and run unsubscribe-hook
+
+ * obby/rudel-obby.el (header): cosmetic changes
+ (include rudel-icons): `rudel-display-string' uses icons
+ (rudel-obby-user::eieio-speedbar-object-buttonname): use
+ `rudel-display-string'
+ (rudel-obby-user::rudel-display-string): new method; textual
+ representation of user object
+ (rudel-obby-parse-message): cosmetic changes
+ * rudel.el (include rudel-icons): `rudel-display-string' uses
+ icons
+ (rudel-user::rudel-display-string): new method; textual
+ representation of user object
+
+ * rudel-util.el (rudel-hook-object): new class; abstract mixin for
+ classes that offer hooks
+ (rudel-hook-object::object-add-hook): new method; add function to
+ hook list
+ (rudel-hook-object::object-remove-hook): new method; remove
+ function from hook list
+ (rudel-hook-object::object-run-hook-with-args): new method; run
+ hook functions
+
+2009-08-20 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * icons/plaintext.svg (new file): plaintext icon
+ * icons/person.svg (new file): person icon
+ * icons/encrypted.svg (new file): encrypted icon
+ * icons/document.svg (new file): document icon
+ * icons/disconnected.svg (new file): disconnected icon
+ * icons/connected.svg (new file): connected icon
+ * rudel-icons.el (new file): loading icons
+ * Project.ede (target rudel): added rudel-icons.el
+
+2009-08-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-join-session): renamed local variable backend to
+ session-initiation-backend
+
+2009-08-17 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-state.el (rudel-obby-state::rudel-accept): fixed
+ format of warning message
+
+ * rudel-state-machine.el (require working): needed by
+ `rudel-state-wait'
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_user_colour): set
+ face attributes
+ * rudel.el (rudel-change-color): set face attributes
+ * rudel-overlay.el (rudel-overlay-make-face): use
+ `rudel-overlay-set-face-attributes'
+ (rudel-overlay-set-face-attributes): new function; set face
+ attributes
+
+ * rudel-overlay.el (rudel-overlay-author-set-properties): call
+ `rudel-overlay-make-face-symbol'
+ (rudel-overlay-make-face-symbol): new function; return face symbol
+
+2009-08-16 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-overlay.el (rudel-overlay-author-display): option that
+ controls display of author overlays
+ (rudel-make-author-overlay): call
+ `rudel-overlay-author-set-properties' to set the overlay
+ properties
+ (rudel-overlay-author-set-properties): new function; set overlay
+ properties; respects rudel-overlay-author-display
+ (rudel-overlay-author-update): new function; update overlay
+ properties based on associated user object
+ (rudel-overlay-options-changed): new function; call
+ `rudel-overlay-author-update' on all Rudel overlays in all buffers
+ * rudel-mode.el (header): cosmetic changes
+ (rudel-minor-menu): added menu entry to toggle display of author
+ overlays
+
+ * rudel-overlay.el (rudel-make-author-overlay): use `intern'
+ instead of `make-symbol' when allocating the face name; this way,
+ faces can actually be created lazily
+ (rudel-overlay-make-face): call `make-face' for the new face
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-document-synching::object-print): fixed
+ slot name remaining-bytes
+
+ * rudel.el (rudel-host-session): the backend object is the cdr of
+ the result of `rudel-backend-choose'
+
+2009-08-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * telepathy/rudel-telepathy.el (header): added file comment
+ * obby/rudel-obby-state.el (header): fixed email address
+ (whole file): whitespace fixes
+ * jupiter/jupiter.el (header): cosmetic changes
+ (whole file): whitespace fixes
+ * rudel-util.el (header): cosmetic changes
+ * rudel-mode.el (header): cosmetic changes
+ * rudel-errors.el (header): fixed type
+ (whole file): whitespace fixes
+
+ * obby/rudel-obby.el (rudel-ask-connect-info): added optional
+ argument info; do not ask for things that are already specified in
+ info
+ (autoload): register obby service with the Zeroconf backend
+ * zeroconf/rudel-zeroconf.el (new file): Zeroconf session
+ initiation for Rudel
+ * zeroconf/Project.ede (new file): subproject zeroconf
+ * rudel.el (rudel-join-session): call `rudel-ask-info' to augment
+ connect info
+ * Project.ede (target autoloads): added directory zeroconf
+ * INSTALL (INSTALLING): mention zeroconf subdirectory
+ (COMPILING): mention zeroconf target
+
+ * rudel-backend.el (rudel-backend-factory::rudel-get-backend):
+ return backend as a cons
+ (rudel-backend-get): new function; convenience function for
+ getting backends
+
+ * obby/rudel-obby.el (header): extended commentary and history
+ (rudel-obby-version): bumped to 0.2
+ (rudel-obby-backend::initialize-instance): set :version slot in
+ constructor instead of using obsolete lambda expression in
+ initform
+
+2009-08-14 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * Project.ede (project rudel): bumped version to 0.2; added
+ mailing list and path to web files
+
+ * rudel-backend.el (rudel-backend-factory): do not initialize
+ backends with lambda expression
+ (rudel-backend-factory::initialize-instance): new method;
+ initialize backends
+ (rudel-backend-cons-p): use `object-p' instead of `eieio-object-p'
+ (rudel-backend-dump): changed format slightly
+
+2009-08-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (include rudel-session-initiation): required for
+ `rudel-join-session'
+ (rudel-join-session): mostly rewritten; moved user interaction to
+ `interactive' form
+ * rudel-session-initiation.el (new file): session initiation
+ backend interface and high-level programming interface
+ * Project.ede (target rudel): added rudel-session-initiation.el
+ * Makefile (rudel_LISP): added rudel-session-initiation.el
+
+ * rudel-interactive.el (rudel-read-session): discriminate sessions
+ vs. session generating objects using `rudel-backend-cons-p'
+
+ * rudel-backend.el (rudel-backend-cons-p): new function; checks
+ whether a cons consists of a backend name and object
+
+2009-08-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-session): new function; read
+ session by name and return it
+
+ * rudel-interactive.el (rudel-read-backend): argument backends is
+ no longer optional; always return a cons of backend name and
+ object; updated documentation string
+ (whole file): whitespace fixes
+ * rudel-backend.el (rudel-backend-choose): always return a cons of
+ backend name and object; updated documentation string
+
+2009-08-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (file header): added project URL
+ (whole file): improved some comments
+
+2009-08-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (include eieio-base): needed for eieio-named
+
+2009-08-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-state-machine.el (header section commentary): updated
+ (rudel-state-machine::initialize-instance): use
+ `rudel--switch-to-return-value' to allow immediate switch to
+ another state
+ (rudel-state-machine::rudel-switch): use
+ `rudel--switch-to-return-value' to switch to successor state
+ (rudel-state-machine::rudel--switch-to-return-value): new function
+ switch to successor state for different kinds of specifications of
+ the successor state
+
+2009-08-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (require rudel-backend): now necessary
+ (require rudel-protocol): now necessary
+ (class rudel-obby-backend): now derived from `rudel-backend';
+ autoloaded
+ (autoloading): use `rudel-add-backend'
+ * rudel.el (require rudel-backend): backends have their own file
+ (class rudel-backend): moved to rudel-backend.el
+ (rudel-load-backends): moved to rudel-backend.el
+ (rudel-suitable-backends): moved to rudel-backend.el
+ (rudel-choose-backend): moved to rudel-backend.el
+ (rudel-join-session): use `rudel-backend-choose'
+ (rudel-host-session): use `rudel-backend-choose'
+
+ * rudel-protocol.el (new file): interface for Rudel protocol
+ backends
+ * Project.ede (target rudel): added rudel-protocol.el
+ * Makefile (rudel_LISP): added rudel-protocol.el
+
+ * rudel-backend.el (rudel-backend-factory::rudel-get-backend):
+ improved documentation string
+ (rudel-backend-factory::rudel-suitable-backends): improved
+ documentation string
+ (rudel-backend-suitable-backends): improved documentation string
+ (rudel-backend-choose): When only one backend matches, do not
+ check interactivity using `interactive-p', that does not work;
+ call `sit-for' correctly
+
+2009-08-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/Makefile (whole file): regenerated; reflects CEDET
+ changes
+ * rudel-backend.el (new file): generic backend management, query
+ and loading functions
+ * Project.ede (target rudel): added rudel-backend.el to sources
+ * Makefile (rudel_LISP): added rudel-backend.el
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): use slot
+ :object-name instead of calling object-name-string
+ (rudel-obby-server::rudel-add-context): use slot :object-name
+ instead of calling object-name-string
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-idle::rudel-obby/obby_document/rename):
+ use slot :object-name instead of calling object-name-string
+ (rudel-obby-connection::rudel-add-context): use slot :object-name
+ instead of calling object-name-string
+ (rudel-obby-connection::rudel-publish): use slot :object-name
+ instead of calling object-name-string
+ * rudel.el (class rudel-user): added base class eieio-named for
+ virtual slot :object-name; made abstract
+ (class rudel-document): added base class eieio-named for virtual
+ slot :object-name
+ * rudel-overlay.el (rudel-make-author-overlay): use slot
+ :object-name instead of calling object-name-string
+
+ * rudel-state-machine.el
+ (rudel-state-machine::initialize-instance): use &rest slots
+ instead of just slots
+
+2009-07-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::rudel-detach-from-buffer): call
+ `rudel-overlays-remove-all'; remove `rudel-unpublish-buffer' hook
+ early
+ * rudel-overlay.el (rudel-overlays-remove-all): new function;
+ remove all overlays from the current buffer
+ (whole file): cosmetic changes; typo fixes; whitespace fixes
+
+ * obby/rudel-obby.el (rudel-obby-document::rudel-unique-name):
+ Check `next-method-p' before calling the next method
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::initialize-instance): Check
+ `next-method-p' before calling the next method
+ (rudel-obby-connection::rudel-register-state): Check
+ `next-method-p' before calling the next method
+ (rudel-obby-connection::rudel-disconnect): Check
+ `next-method-p' before calling the next method
+ * rudel.el (rudel-client-session::rudel-end): Check
+ `next-method-p' before calling the next method
+
+2009-07-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-connect): only
+ start the network process after everything is ready; wait for the
+ connection state machine to reach a success or error state
+ (rudel-obby-backend::rudel-host): cosmetic changes
+ (class rudel-obby-user): cosmetic changes
+ * rudel.el (rudel-join-session): reversed order of creation for
+ session and connection; do not catch errors to give error messages
+ a chance
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ cosmetic changes
+ (whole file): whitespace fixes
+
+ * rudel.el (rudel-session::rudel-find-user): added documentation
+ string; cosmetic changes
+ (rudel-session::rudel-find-document): added documentation string;
+ cosmetic changes
+ (whole file): whitespace fixes
+
+2009-07-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-speedbar.el (eieio-speedbar-object-buttonname): use
+ `rudel-unique-name' instead of `object-name-string'
+
+ * obby/rudel-obby-state.el (rudel-enter): return nil
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-client-state-joining::rudel-enter): return nil
+ (rudel-obby-client-state-join-failed::rudel-enter): return nil
+ (rudel-obby-client-state-session-synching::rudel-enter): return
+ nil
+ (rudel-obby-client-state-session-synching::object-print): new
+ method; add number of remaining items to string representation
+ (rudel-obby-client-state-subscribing::rudel-enter): nil
+ (rudel-obby-client-state-document-synching::rudel-enter): nil
+ (rudel-obby-client-state-document-synching::object-print): new
+ method; add number of remaining bytes to string representation
+
+2009-07-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (with-parsed-arguments): added debug
+ declaration
+ (whole file): whitespace fixes
+ * rudel-util.el (rudel-assemble-line-fragments): added debug
+ declaration
+ (rudel-loop-lines): added debug declaration
+ (rudel-loop-chunks): fixed documentation string; added debug
+ declaration
+
+ * rudel-state-machine.el (rudel-no-start-state): new error symbol
+ (rudel-state-machine::initialize-instance): try hard to find a
+ suitable start sate; call `rudel-switch' instead of just
+ `rudel-enter'
+ (rudel-state-machine::rudel-switch): always return the new current
+ state; accept successor state from `rudel-enter'
+ (rudel-state-machine::object-print): new method; add current state
+ of state machine to string representation
+ (rudel-state-machine::rudel-state-wait): whitespace fixes
+
+2009-07-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (class rudel-obby-backend): better
+ documentation string
+ (rudel-obby-backend::rudel-ask-connect-info): added documentation
+ string
+ (rudel-obby-backend::rudel-connect): added documentation string
+ (rudel-obby-backend::rudel-ask-host-info): added documentation
+ string
+ (rudel-obby-backend::rudel-host): added documentation string
+ (rudel-obby-backend::rudel-make-document): added documentation
+ string
+ (rudel-obby-send): cosmetic changes
+ (whole file): whitespace fixes
+
+2009-07-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): added Emacs itself and GNUTls
+
+ * rudel-tls.el (rudel-tls-start-tls): added a message
+ (rudel-tls-wait-handshake): switch to filter
+ `rudel-tls-established' instead of restoring the original filter
+ (rudel-tls-established): new function; filters GNUTls messages in
+ encrypted connections
+ (whole file): whitespace fixes
+
+2009-07-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * README (INTRODUCTION): extended a bit
+ (JOINING A SESSION): added prompt/input example and an explanation
+ of encryption issues in the obby backend
+ (KNOWN BUGS): new section; no known bugs yet, though
+
+2009-06-17 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el (require rudel-state-machine): the
+ connection now is a state machine
+ (require rudel-obby-errors): used when analyzing login failures
+ (require rudel-obby-state): useful base classes for states
+ (rudel-obby-client-state-new): new class; initial state of new
+ connections
+ (rudel-obby-client-state-encryption-negotiate): new class;
+ first encryption state
+ (rudel-obby-client-state-encryption-start): new class; second
+ encryption state
+ (rudel-obby-client-state-joining): new class
+ (rudel-obby-client-state-join-failed): new class; entered after
+ failed login attempt
+ (rudel-obby-client-state idle): new class; default state of
+ established connections
+ (rudel-obby-client-state-session-synching): new class;
+ synchronizing session state to client
+ (rudel-obby-client-state-subscribing): new class; first state of
+ document subscription
+ (rudel-obby-client-state-document-synching): new class;
+ synchronizing document state to client
+ (rudel-obby-client-connection-states): new variable; alist of
+ name symbols and associated state classes
+ (rudel-obby-connection::initialize-instance): register states
+ (rudel-obby-connection::rudel-register-state): new method; set
+ connection slot of state to its connection
+ (rudel-obby-connection::rudel-add-context): cleanup
+ (rudel-obby-connection::rudel-message): dispatch message using
+ `rudel-accept'
+ (rudel-obby-connection::rudel-subscribe-to): initiate subscription
+ by switching to state 'subscribing'
+
+ * obby/rudel-obby-state.el (rudel-obby-document-handler): new
+ class; mixin class that provides handling of obby 'document'
+ messages
+
+ * rudel-state-machine.el
+ (rudel-state-machine::initialize-instance): find start state in
+ slots and switch into it
+ (while-file): whitespace fixes
+
+2009-06-15 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * www/index.html (section download): fixed link to download area
+ (whole file): whitespace cleanup
+
+ * obby/rudel-obby-state.el (new file): finite state machine states
+ for the rudel backend
+ * obby/Project.ede (target rudel/obby): added rudel-obby-state.el
+ * obby/Makefile (target obby_LISP): added rudel-obby-state.el
+
+ * rudel-util.el (require rudel-errors): required for dispatch
+ errors
+ (symbol rudel-dispatch-error): new condition symbol for dispatch
+ errors
+ (rudel-dispatch): new function; dispatch to method based on method
+ name
+ (whole file): whitespace fixes
+
+2009-06-14 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-mode.el (global-rudel-minor-mode): removed; the variable
+ is created by `define-minor-mode'
+ (minor-mode-alist): managed by `define-minor-mode'
+
+ * rudel-mode.el (require easy-mmode): used to define global rudel
+ minor mode
+ (rudel-minor-keymap): cosmetic changes
+ (global-rudel-minor-mode): use `define-minor-mode' to define the
+ mode
+ (whole file): whitespace cleanup
+
+ * rudel-telepathy.el (whole file): moved to
+ telepathy/rudel-telepathy.el
+ * telepathy/rudel-telepathy.el (whole file): moved from
+ rudel-telepathy.el
+
+ * obby/rudel-obby-server.el (whole file): whitespace cleanup
+ * obby/rudel-obby-client.el (require rudel-obby): removed;
+ unnecessary
+ (rudel-obby-connection::initialize-instance): use &rest for `slots'
+ argument; cosmetic changes
+ (rudel-obby-connection::rudel-change-color-): use own `rudel-send'
+ method instead of the socket's
+ (rudel-obby-connection::rudel-subscribe-to): cosmetic changes
+ (rudel-obby-connection::rudel-unsubscribe-from): cosmetic changes
+ (rudel-obby-connection::rudel-local-operation): cosmetic changes
+ (whole file): whitespace cleanup
+
+2009-06-13 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-errors.el (new file): error data
+ * rudel-state-machine.el (new file): a simple finite state machine
+ implementation
+ * Project.ede (target rudel): added rudel-errors.el and
+ rudel-state-machine.el
+ * Makefile (target rudel_LISP): added rudel-errors.el and
+ rudel-state-machine.el
+
+2009-06-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el (require rudel-obby-errors): now
+ required
+ (rudel-obby-client::rudel-obby/net6_client_login): check username
+ and color before adding the client
+ (rudel-obby-server::rudel-check-username-and-color): new method;
+ make sure username and color are valid and there are no duplicates
+ * obby/rudel-obby-errors.el (new file): error data for the obby
+ backend
+ * obby/Project.ede (rudel/obby): added rudel-obby-errors.el
+ * obby/Makefile (obby_LISP): added rudel-obby-errors.el
+
+ * rudel.el (rudel-user::rudel-color): added accessor `rudel-color'
+
+ * obby/rudel-obby-server.el (require cl): required
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): send suffices
+ of synchronized documents
+
+2009-06-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document_create): send
+ document/rename message to client when the document suffix changes
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_user_colour): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document_create): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): use
+ `with-parsed-arguments'
+ (rudel-obby-client::rudel-obby/obby_document/record/del): use
+ `with-parsed-arguments'
+
+ * obby/rudel-obby-server.el (header): fixed version
+
+2009-06-10 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-operation): fixed wording in
+ comment
+
+ * www/images/development.png (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/development.svg (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/download.png (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/download.svg (whole file): changed size 48x48 ->
+ 64x64
+ * www/images/info.png (whole file): changed size 48x48 -> 64x64
+ * www/images/info.svg (whole file): changed size 48x48 -> 64x64
+
+ * index.html (section introduction): wording fixes; link to Gobby
+ (whole file): removed external link class for sourceforge links
+ (section download): added link to INSTALL file in svn code browser
+ (section footer): fixed copyright
+
+ * compatibility.html (section footer): fixed copyright
+
+2009-06-09 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (section REQUIREMENTS): removed ERT which is not
+ currently used
+ (section INSTALL): some wording and file name fixes
+ (section COMPILING): precise make command
+
+ * www/index.html (section development): fixed mailing list and
+ issue tracker links; removed email address
+
+ * www/compatibility.html (head): fixed charset
+ (section semantic): added missing <p> tag
+
+ * www/compatibility.html (new file): compatibility information
+ * www/index.html (new file): start page
+ * www/style.css (new file): stylesheet
+ * www/images/development.png (new file): development icon
+ * www/images/development.svg (new file): development icon
+ * www/images/download.png (new file): download icon
+ * www/images/download.svg (new file): download icon
+ * www/images/email-link.png (new file): icon for email links
+ * www/images/external-link.png (new file): icon for external links
+ * www/images/info.png (new file): info icon
+ * www/images/info.svg (new file): info icon
+ * www/images/screenshot.png (new file): screenshot for the start
+ page
+
+ * obby/rudel-obby-serverl.el
+ (rudel-obby-client::rudel-obby/obby_document_create): find unique
+ suffix for the new document; send suffix to clients
+
+ * obby/rudel-obby.el (header): fixed license text
+ * obby/rudel-obby-util.el (header): fixed license text
+ * obby/rudel-obby-server.el (header): fixed license text
+ * obby/rudel-obby-client.el (header): fixed license text
+ * jupiter/jupiter.el (header): fixed license text
+ * jupiter/jupiter-operation.el (header): fixed license text
+ * jupiter/jupiter-nop.el (header): fixed license text
+ * jupiter/jupiter-insert.el (header): fixed license text
+ * jupiter/jupiter-delete.el (header): fixed license text
+ * jupiter/jupiter-compound.el (header): fixed license text
+ * rudel.el (header): fixed license text
+ * rudel-util.el (header): fixed license text
+ * rudel-tls.el (header): fixed license text
+ * rudel-telepathy.e (header): fixed license text
+ * rudel-speedbar.el (header): fixed license text
+ * rudel-overlay.el (header): fixed license text
+ * rudel-operators.el (header): fixed license text
+ * rudel-operations.el (header): fixed license text
+ * rudel-mode.el (header): fixed license text
+ * rudel-interactive.el (header): fixed license text
+ * rudel-compat.el (header): fixed license text
+
+ * obby/rudel-obby-util.el (require cl): now required
+ (generic rudel-obby-char->byte): new generic; char positions ->
+ byte positions
+ (jupiter-insert::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-delete::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-compound::rudel-obby-char->byte): new method; char
+ positions -> byte positions
+ (jupiter-nop::rudel-obby-char->byte): new method; char positions
+ -> byte positions
+ (generic rudel-obby-byte->char): new generic; byte positions ->
+ char positions
+ (jupiter-insert::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-delete::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-compound::rudel-obby-byte->char): new method; byte
+ positions -> char positions
+ (jupiter-nop::rudel-obby-byte->char): new method; byte positions
+ -> char positions
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-operation): call
+ `rudel-obby-char->byte' before processing
+ (rudel-obby-connection::rudel-remote-operation): call
+ `rudel-obby-byte->char' before processing
+ * rudel.el (rudel-buffer-change-workaround-data): new variable;
+ holds change data for later use
+ (rudel-document::rudel-attach-to-buffer): add
+ `rudel-buffer-change-workaround' to 'before-change-functions'
+ (rudel-document::rudel-detach-from-buffer): remove
+ `rudel-buffer-change-workaround' from 'before-change-functions'
+ (rudel-buffer-change-workaround): new function; stores change data
+ for later use
+
+2009-06-07 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_join): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/net6_client_part): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_welcome): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_init): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_usertable_user): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_user_colour): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document):
+ use `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document_create): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document_remove): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document): use
+ `with-parsed-arguments'; cleanup
+ (rudel-obby-connection::rudel-obby/obby_document/rename): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/subscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/unsubscribe): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): use
+ `with-parsed-arguments'
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): use
+ `with-parsed-arguments'
+
+2009-06-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): use `eql',
+ not `=' when calling `rudel-find-user' since the client id can be
+ nil
+
+ * obby/rudel-obby-util.el (require jupiter): silence byte compiler
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): moved inside file
+ (with-parsed-arguments): new macro; executed forms with variables
+ bound to parsed arguments
+
+2009-06-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (require rudel-interactive): interactive functions use
+ `rudel-read-backend' and `rudel-read-document'
+
+ * rudel.el (rudel-buffer-document): mark as permanent local
+ variable to prevent deletion in the event of a major-mode change
+ (rudel-document::rudel-attach-to-buffer): add (buffer-locally)
+ `rudel-handle-major-mode-change' to 'change-major-mode-hook' such
+ that it can repair damage caused by major-mode changes
+ (rudel-document::rudel-detach-from-buffer): remove
+ `rudel-handle-major-mode-change' from 'change-major-mode-hook'
+ (rudel-mode-changed-buffers) new variable; temporarily stores
+ buffers that underwent major-mode changes
+ (rudel-handle-major-mode-change): new function; schedules buffers
+ for repair after major-mode changes
+ (rudel-after-major-mode-change): new function; repairs buffer
+ objects after major-mode changes
+
+2009-06-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-buffer-has-document-p): use `buffer-local-value'
+ (rudel-buffer-document): use `buffer-local-value'
+ (rudel-set-buffer-document): added documentation string
+
+2009-06-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-handle-buffer-change): There are three cases
+ now: insert, delete and arbitrary changes; arbitrary changes
+ generate a delete and insert operation
+
+ * rudel-mode.el (rudel-minor-keymap): added some comments
+ (global-rudel-minor-mode): extended documentation string; cleaned
+ up code; added comments
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): fixed typo
+ in variable name client-id-numeric
+
+2009-05-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (header): Fixed version (1.0 -> 0.1)
+
+ * obby/rudel-obby-client.el (header): Fixed version (1.0 -> 0.1)
+ (rudel-obby-connection::rudel-obby/obby_document/record/split):
+ introduced temporary variable
+
+2009-??-?? Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-buffer-document): removed; replaced by
+ rudel-buffer-documents hash-table
+ (rudel-buffer-documents): new variable; a hash-table, which
+ associates documents to buffers
+ (rudel-buffer-has-document-p):
+ (rudel-buffer-document):
+ (rudel-set-buffer-document):
+
+2009-03-16 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_part): do not crash
+ if the client id cannot be found
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-make-document):
+ specify value 1 for slot suffix
+ (rudel-obby-document::suffix): new slot; contains the suffix
+ number of the document
+ (rudel-obby-document::rudel-unique-name): new method; return
+ unique name based on document name and suffix
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document): do
+ not ignore the suffix when creating the document object
+ (rudel-obby-connection::rudel-obby/obby_document_create): do not
+ ignore the suffix when creating the document object
+ (rudel-obby-connection::rudel-obby/obby_document/rename): change
+ document name and suffix as requested
+ * rudel.el (rudel-document::rudel-unique-name): new method;
+ returns a unique name for the document
+ (rudel-document::rudel-suggested-buffer-name): new method; returns
+ a suggested name for the buffer attached to the document
+ (rudel-subscribe): use `rudel-suggested-buffer-name' instead of
+ the object name
+ * rudel-interactive.el (rudel-read-document): use the unique names
+ of the documents instead of the object names
+
+2009-02-27 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): add hook to
+ detach document from the buffer when the buffer is killed
+ (rudel-document::rudel-detach-from-buffer): remove unpublish
+ function kill buffer hook
+
+2009-02-23 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-document): minor cleanup
+ (rudel-document::rudel-attach-to-buffer): stylistic changes
+ (rudel-document::rudel-detach-from-buffer): fixed argument order in
+ call to `rudel-set-buffer-document'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-server::rudel-remove-client): Make sure there is a
+ user object before setting the status to offline
+
+ * obby/rudel-obby-client.el (rudel-obby/net6_encryption_failed):
+ only fail if encryption has been requested in the first
+ place. otherwise, just carry on
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): use
+ `rudel-set-buffer-document'
+ (rudel-document::rudel-detach-from-buffer): use
+ `rudel-set-buffer-document'
+ (rudel-buffer-has-document-p): new function; test whether a buffer
+ has an associated document object
+ (rudel-buffer-document): new function; returns associated document
+ object of a buffer
+ (rudel-set-buffer-document): new functions; sets associated
+ document object of a buffer
+ (rudel-handle-buffer-change): use `rudel-buffer-has-document-p'
+ (rudel-publish-buffer): use `rudel-buffer-has-document-p'
+ (rudel-unpublish-buffer): use `rudel-buffer-has-document-p' and
+ `rudel-buffer-document'
+ * rudel-mode.el (rudel-minor-keymap): use
+ `rudel-buffer-has-document-p'
+
+ * obby/rudel-obby-client.el (rudel-obby/obby_document/rename):
+ new method; dummy implementation
+
+ * obby/rudel-obby-client.el (rudel-obby/net6_client_join):
+ stylistic change
+
+2009-02-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-util.el (generic rudel-operation->message): new
+ generic function; serializes an operation
+ (jupiter-insert::rudel-operation->message): new method
+ (jupiter-delete::rudel-operation->message): new method
+ (jupiter-compound::rudel-operation->message): new method
+ (jupiter-nop::rudel-operation->message): new method
+ (rudel-message->operation): new function; deserializes an
+ operation from a received message
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-insert): do not construct
+ message string; use `rudel-operation->message'
+ (rudel-obby-connection::rudel-local-delete): do not construct
+ message string; use `rudel-operation->message'
+ (rudel-obby-connection::rudel-local-operation): new method;
+ handles operation objects that represent local operations
+ (rudel-obby-connection::rudel-remote-operation): new method;
+ handles operation objects that represent remote operations
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins):
+ construct operation name correctly; do not call jupiter context to
+ transform operation
+ (rudel-obby-connection::rudel-obby/obby_document/record/del):
+ construct operation name correctly; do not call jupiter context to
+ transform operation
+ (rudel-obby-connection::rudel-obby/obby_document/record/split):
+ new method; handles split operation messages
+ (rudel-obby-connection::rudel-obby/obby_document/record/noop): new
+ method; handles nop messages
+
+2009-02-12 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info):
+ ask whether to encrypt the connection
+ (rudel-obby-backend::rudel-connect): create connection object
+ capable of StartTLS encryption when encryption was requested
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_encryption): do not fail
+ when the server requests encryption
+ (rudel-obby-connection::rudel-obby/net6_encryption_begin): start
+ TLS encryption for the connection
+ (rudel-obby-connection::rudel-obby/net6_encryption_failed): new
+ method; stub
+ * rudel-tls.el (new file): StartTLS encryption for Rudel
+ * Project.ede ("rudel"): added rudel-tls.el
+ * Makefile (rudel_LISP): added rudel-tls.el
+
+2009-02-06 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-compat.el (header): fixed email address, keywords, legal
+ notice and file commentary
+
+2009-02-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-compat): require rudel-compat for
+ `read-color'
+ * rudel.el (rudel-compat): require rudel-compat for `read-color'
+ * rudel-interactive.el (rudel-compat): require rudel-compat for
+ `read-color'
+ * rudel-compat.el (new file): compatibility code
+ * Project.ede (rudel): added rudel-compat.el
+ * Makefile (rudel_LISP): regenerated: added rudel-compat.el
+
+2009-02-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (require rudel)
+ * obby/rudel-obby-util.el (require rudel)
+ * obby/rudel-obby-client.el (require rudel-obby): make compilation
+ succeed
+
+ * rudel.el (include eieio-speedbar): I need it for now; I should
+ get rid of it later
+
+ * INSTALL (REQUIREMENTS): added note that CVS version of cedet is
+ required
+ (INSTALLING): added subdirectories jupiter and obby in load path
+ listing; fixed name of autoload file
+
+2009-02-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-connect-info)
+ (rudel-obby-backend::rudel-host, rudel-obby-replace-in-string)
+ * obby/rudel-obby-util.el (rudel-obby-dispatch)
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-obby/obby_document)
+ (rudel-obby-server::rudel-broadcast, rudel-obby-server::rudel-make-user)
+ * obby/rudel-obby-client.el (rudel-obby-connection::rudel-obby/net6_client_join)
+ (rudel-obby-connection::rudel-obby/obby_document)
+ * jupiter/jupiter-operation.el (jupiter-operation)
+ * rudel.el (rudel-backend, rudel-session, rudel-server-session)
+ (rudel-connection, rudel-document)
+ (rudel-document::rudel-attach-to-buffer)
+ (rudel-document::rudel-detach-from-buffer)
+ (rudel-document::rudel-insert, rudel-document::rudel-delete)
+ (rudel-change-color)
+ * rudel-util.el (rudel-assemble-line-fragments, rudel-loop-lines)
+ * rudel-overlay.el (rudel-make-author-overlay)
+ * rudel-interactive.el (rudel-read-backend, rudel-read-user-color)
+ (rudel-read-user, rudel-read-document): replaced 't by t
+
+ * rudel-operators.el (rudel-overlay-operators::rudel-insert):
+ Fixed computation of insertion offset when appending to the end of
+ the buffer string
+
+ * rudel.el (rudel-document::rudel-chunks): fixed invalid access to
+ last chunk for empty buffer
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): fixed
+ incorrect slot reference
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): minor
+ rearrangement of expressions
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): minor
+ rearrangement of expressions
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): added
+ documentation string
+ (rudel-obby-client::rudel-obby/obby_document/record/del): added
+ documentation string
+ (rudel-obby-server): cosmetic change
+
+ * jupiter/jupiter.el (jupiter-context::jupiter-remote-operation):
+ improved documentation string; cosmetic changes
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ improved some comments
+
+ * rudel.el (rudel-document::rudel-attach-to-buffer): renamed
+ some variables; added documentation string
+ (rudel-document::rudel-insert): improved documentation string
+ (rudel-document::rudel-chunks): do not create chunks when buffer
+ string is empty; improved comments
+ (rudel-choose-backend): compare number using `=' not `eq'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins): use
+ `rudel-remote-operation' instead of `rudel-remote-insert'
+ (rudel-obby-client::rudel-obby/obby_document/record/del): use
+ `rudel-remote-operation' instead of `rudel-remote-delete'
+ * obby/rudel-obby-client.el (include rudel-operations): for
+ rudel-insert-op and rudel-delete-op
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `rudel-remote-operation' with rudel-insert-op to insert chunks
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): use
+ `rudel-remote-operation' instead of `rudel-remote-insert'
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): use
+ `rudel-remote-operation' instead of `rudel-remote-delete'
+ * jupiter/jupiter-operation.el (include rudel-operations): for
+ rudel-operation
+ (jupiter-operation): derived from rudel-operation
+ (jupiter-operation::jupiter-apply): removed; replaced by generic
+ `rudel-apply'
+ * jupiter/jupiter-nop.el (jupiter-nop::jupiter-apply): removed;
+ replaced by `rudel-apply'
+ (jupiter-nop::rudel-apply): new method; implements generic
+ `rudel-apply'
+ * jupiter/jupiter-insert.el (include rudel-operations): for
+ jupiter-insert-op
+ (jupiter-insert): derived from jupiter-insert-op
+ (jupiter-insert::jupiter-apply): removed; inherited from
+ jupiter-insert-op
+ (jupiter-insert::slot-missing): removed; inherited from
+ jupiter-insert-op
+ * jupiter/jupiter-delete.el (include rudel-operations): for
+ jupiter-delete-op
+ (jupiter-delete): derived from jupiter-delete-op
+ (jupiter-delete::jupiter-apply): removed; inherited from
+ jupiter-delete-op
+ (jupiter-delete::slot-missing): removed; inherited from
+ jupiter-delete-op
+ * jupiter/jupiter-compound.el (jupiter-compound::jupiter-apply):
+ removed; replaced by `rudel-apply'
+ (jupiter-compound::rudel-apply): new method; implements generic
+ `rudel-apply'
+ * rudel.el (include rudel-operations): everything is represented
+ in terms of operations
+ (include rudel-operators): operations apply changes to objects
+ through operators
+ (rudel-document::rudel-insert): new method; performs insert
+ operation
+ (rudel-document::rudel-delete): new method; performs delete
+ operation
+ (rudel-document::rudel-local-insert): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-local-delete): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-remote-insert): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-remote-delete): removed; document does not
+ deal with aspects other than the actual insert and delete
+ (rudel-document::rudel-local-operation): new method; apply
+ operation using overlay and connection operators
+ (rudel-document::rudel-remote-operation): new method; apply
+ operation using document and overlay operators
+ (rudel-handle-buffer-change): realize buffer changes using
+ operations
+ * rudel-operators.el (new file): collections of operations on
+ Rudel data types
+ * rudel-operations.el (new file): operation classes
+
+2009-02-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ handle jupiter-nop
+
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ in inner cond, use matching pattern but empty body for
+ no-operation cases; in outer cond, handle jupiter-nop
+
+ * jupiter/jupiter-compound.el (jupiter-compound): now derived from
+ jupiter-operation; should have been right from the start
+
+2009-01-31 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-default-username): Default name used when
+ prompting for user name; required by rudel-interactive
+
+ * rudel-interactive.el (rudel-read-backend): fixed typo
+
+2009-01-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * jupiter/jupiter-insert.el (jupiter-insert::jupiter-transform):
+ fixed two offset calculations
+ * jupiter/jupiter-delete.el (jupiter-delete::jupiter-transform):
+ fixed offset calculation
+
+ * rudel.el (rudel-backend::rudel-ask-connect-info): changed from
+ method to generic
+ (rudel-backend::rudel-connect): changed from method to generic
+ (rudel-backend::rudel-ask-host-info): changed from method to
+ generic
+ (rudel-backend::rudel-host): changed from method to generic
+ (rudel-backend::rudel-make-document): changed from method to
+ generic
+ (rudel-session::rudel-disconnect): changed from method to generic
+ (rudel-session::rudel-change-color-): changed from method to
+ generic
+ (rudel-session::rudel-publish): changed from method to generic
+ (rudel-session::rudel-subscribe-to): changed from method to
+ generic
+ (rudel-session::rudel-unsubscribe-from): changed from method to
+ generic
+ (rudel-session::rudel-local-insert): changed from method to
+ generic
+ (rudel-session::rudel-local-delete): changed from method to
+ generic
+ (rudel-session::rudel-remote-insert): changed from method to
+ generic
+ (rudel-session::rudel-remote-delete): changed from method to
+ generic
+
+2009-01-28 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-overlay.el (header): fixed version
+ (whole file): cosmetic changes
+ (rudel-author-overlay-p): added documentation string
+ (rudel-author-overlays): added documentation string
+
+ * rudel-mode.el (rudel-minor-keymap): cosmetic changes
+
+ * rudel-mode.el (rudel-minor-keymap): Separated session
+ participation and hosting items
+
+ * obby/rudel-obby.el (rudel-obby-long-message-threshold): Added
+ documentation string
+ (rudel-obby-long-message-chunk-size): Added documentation string
+ (rudel-obby-backend::rudel-connect): Do not set process object;
+ this is done in the `initialize-instance' method of the base class
+ (rudel-obby-format-color): retrieve color components with
+ `color-values'
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-remove-context): improved
+ documentation string
+ (rudel-obby-connection::rudel-publish): added a comment
+ (rudel-obby-connection::rudel-subscribe-to): added some comments;
+ cleaned up code
+ (rudel-obby-connection::rudel-unsubscribe-from): added a comment
+ (rudel-obby-connection::rudel-obby/net6_ping): added documentation
+ string
+ (rudel-obby-connection::rudel-obby/net6_encryption): added
+ documentation string
+ (rudel-obby-connection::rudel-obby/net6_login_failed): added
+ documentation string
+ (rudel-obby-connection::rudel-obby/net6_client_part): use `='
+ instead of `eq' to compare client ids; fixed documentation string;
+ improved comments
+ (rudel-obby-connection::rudel-obby/obby_user_colour): use `='
+ instead of `eq' to compare user ids
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk): use
+ `=' instead of `eq' to compare user ids; use accessor
+ `user-id-numeric'
+
+ * obby/rudel-obby-util.el (rudel-obby-dispatch): new functions;
+ dispatches to class methods based on message name; handles errors
+ properly
+ * obby/rudel-obby-server.el (rudel-obby-client::rudel-message):
+ use `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-client::rudel-obby/obby_document): use
+ `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-client::rudel-obby/obby_document/record): use
+ `rudel-obby-dispatch' to dispatch message
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-message): use `rudel-obby-dispatch'
+ to dispatch message; moved to a different location
+ (rudel-obby-connection::rudel-obby/obby_document): use
+ `rudel-obby-dispatch' to dispatch message
+ (rudel-obby-connection::rudel-obby/obby_document/record): use
+ `rudel-obby-dispatch' to dispatch message
+
+ * obby/rudel-obby-util.el (generic rudel-message): made the method
+ a generic function and updated the documentation string
+
+2009-01-26 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-document::revision): removed; The
+ slot is no longer needed
+ * obby/rudel-obby-server.el (require jupiter): uses jupiter
+ algorithm
+ (rudel-obby-client::rudel-obby/obby_document_create): add a
+ jupiter context for the document
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): add a
+ jupiter context for the document
+ (rudel-obby-client::rudel-obby/obby_document/unsubscribe): remove
+ the jupiter context associated to the document
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ transformed the operation before applying it to the buffer; use
+ the respective jupiter contexts of the receivers when sending the
+ operation
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ transformed the operation before applying it to the buffer; use
+ the respective jupiter contexts of the receivers when sending the
+ operation
+ (rudel-obby-server::contexts): new slot; stores jupiter contexts
+ for pairs of clients and documents
+ (rudel-obby-server::initialize-instance): new method; store an
+ empty hash-table in the `contexts' slot
+ (rudel-obby-server::rudel-find-context): find the jupiter context
+ for a pair of a client and a document
+ (rudel-obby-server::rudel-add-context): add a jupiter context for
+ a pair of a client and a document
+ (rudel-obby-server::rudel-remove-context): remove the jupiter
+ context for a pair of a client and a document
+ (rudel-obby-context-key): return a list of client id and document
+ id
+ * obby/rudel-obby-client.el (require jupiter): uses jupiter
+ algorithm
+ (rudel-obby-connection::contexts): new slot; stores jupiter
+ contexts for documents
+ (rudel-obby-connection::initialize-instance): new method; store an
+ empty hash-table in the `contexts' slot
+ (rudel-obby-connection::rudel-find-context): new method; return
+ the jupiter context for a document
+ (rudel-obby-connection::rudel-add-context): new method; add a
+ jupiter context for a document
+ (rudel-obby-connection::rudel-remove-context): new method; remove
+ the jupiter context for a document
+ (rudel-obby-connection::rudel-publish): add a jupiter context for
+ the new document
+ (rudel-obby-connection::rudel-subscribe-to): add a jupiter context
+ for the new document
+ (rudel-obby-connection::rudel-unsubscribe-from): remove the
+ jupiter context associated to the document
+ (rudel-obby-connection::rudel-local-insert): use revision
+ information from the jupiter context instead of the document;
+ supply the operation to the jupiter context
+ (rudel-obby-connection::rudel-local-delete): use revision
+ information from the jupiter context instead of the document;
+ supply the operation to the jupiter context
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins):
+ transform the operation using the jupiter context instead of using
+ it unmodified
+ (rudel-obby-connection::rudel-obby/obby_document/record/del):
+ transform the operation using the jupiter context instead of using
+ it unmodified
+
+2009-01-22 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby-client.el (rudel-obby-connection): removed
+ redundant slot `socket' (inherited from base class)
+
+2009-01-21 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (rudel-read-user): added comments
+ (rudel-allocate-buffer-clear-existing): added documentation string
+ (rudel-allocate-buffer-make-unique): added documentation string
+
+2009-01-19 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el, rudel-util.el, rudel-telepathy.el, rudel-speedbar.el,
+ rudel-overlay.el, rudel-mode.el, jupiter/jupiter.el,
+ jupiter/jupiter-operation.el, jupiter/jupiter-nop.el,
+ jupiter/jupiter-insert.el, jupiter/jupiter-delete.el,
+ jupiter/jupiter-compound.el, obby/rudel-obby.el,
+ obby/rudel-obby-util.el, obby/rudel-obby-server.el,
+ obby/rudel-obby-client.el (header): changed email address
+ <scymtym@users.sourceforge.net> ->
+ <scymtym@users.sourceforge.net>
+
+ * rudel-interactive.el (header): added keywords to file header
+ comment
+
+ * jupiter/jupiter.el (new file): core Jupiter algorithm
+ * jupiter/jupiter-operation.el (new file): base class for Jupiter
+ operations
+ * jupiter/jupiter-insert.el (new file): insert operation for
+ Jupiter algorithm
+ * jupiter/jupiter-delete.el (new file): delete operation for
+ Jupiter algorithm
+ * jupiter/jupiter-nop.el (new file): no-operation for Jupiter
+ algorithm
+ * jupiter/jupiter-compound.el (new file): compound operation for
+ Jupiter algorithm
+
+2009-01-11 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-user::client-id): added rationale
+ for type (or null integer)
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-obby/net6_client_join): added
+ documentation string; cosmetic changes
+ (rudel-obby-connection::rudel-obby/net6_client_part): use accessor
+ `rudel-client-id' when searching for the user object; set
+ client-id to nil in the user object; added documentation string
+ (rudel-obby-connection::rudel-obby/obby_sync_usertable_user):
+ store parsed user-id and color in temporaries
+ (rudel-obby-connection::rudel-obby/obby_user_colour):store parsed
+ color in a temporary; use accessor `rudel-id' when finding the
+ user object
+
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-change-color-): new function;
+ implements changing the color
+
+ * obby/rudel-obby-util.el
+ (rudel-obby-socket-owner::rudel-receive): improved documentation
+ string
+
+2009-01-05 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * INSTALL (REQUIREMENTS): proper list of requirements and sources
+ from which they can be obtained
+ (INSTALLING): initial version of installation instructions
+ (COMPLETING): some notes about compiling
+ * README (INTRODUCTION): short introduction
+ (GETTING STARTED): some notes about enabling Rudel, joining and
+ hosting sessions
+
+2009-01-04 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-long-message-threshold): new
+ variable; threshold for message size, above which messages are
+ sent in multiple chunks
+ (rudel-obby-long-message-chunk-size): Chunk size used, when
+ chunking long messages.
+ (rudel-obby-user::client-id): allow value nil; added accessor;
+ added documentation string
+ (rudel-obby-send): new function; handles low-level aspects of
+ sending obby protocol messages
+ * obby/rudel-obby-util.el: new file; contains helper
+ functionality, mainly the class `rudel-obby-socket-owner', which
+ handles sending and receiving message
+ * obby/rudel-obby-server.el (includes): replaced rudel-obby with
+ rudel-obby-util, since it contains `rudel-obby-socket-owner'
+ (class rudel-obby-client): added base class
+ `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-receive): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-send): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-client::rudel-message): new method; called by base
+ class when a message is received; dispatches to appropriate
+ handler method
+ (rudel-obby-client::rudel-obby/obby_user_colour): minor change in
+ documentation string
+ * obby/rudel-obby-client.el (includes): replaced rudel-obby with
+ rudel-obby-util, since it contains `rudel-obby-socket-owner'
+ (class rudel-obby-connection): added base class
+ `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-disconnect): just call next method;
+ it does what this method formerly did
+ (rudel-obby-connection::rudel-close): new method; end the session,
+ when the connection is closed
+ (rudel-obby-connection::rudel-receive): deleted, the functionality
+ is provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-send): deleted, the functionality is
+ provided by the base class `rudel-obby-socket-owner'
+ (rudel-obby-connection::rudel-message): new method; called by
+ base class when a message is received; dispatches to appropriate
+ handler method
+
+ * rudel.el (rudel-document::rudel-detach-from-buffer): do nothing,
+ if the document is not attached to any buffer
+
+ * obby/rudel-obby.el (rudel-obby-user): added missing accessor
+ `rudel-connected'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/net6_client_login): transmit number
+ of synchronization items; transmit list of disconnected users
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/record/ins):
+ broadcast only to clients, which are subscribed to the document;
+ send user id of author instead of client id
+ (rudel-obby-client::rudel-obby/obby_document/record/del):
+ broadcast only to clients, which are subscribed to the document;
+ send user id of author instead of client id
+ (rudel-obby-client::rudel-subscribed-clients-not-self): new
+ method; return a list of clients subscribed to a document
+ excluding the client itself.
+
+ * obby/rudel-obby-server.el (rudel-obby-server::next-client-id):
+ first id should be 1, not 0; fixed initform accordingly
+ (rudel-obby-server::next-user-id):
+ first id should be 1, not 0; fixed initform accordingly
+
+ * rudel.el (rudel-document::rudel-chunks): fixed void variable
+ `chunks-' -> `augmented-chunks'
+
+ * obby/rudel-obby-server.el
+ (rudel-obby-client::rudel-obby/obby_document/subscribe): send
+ individual buffer chunks with their respective authors instead of
+ one large string without author information
+ * rudel.el (rudel-document::rudel-chunks): new method; return a
+ list of buffer position ranges and the respective authors, that
+ wrote the text
+
+2009-01-03 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-host): cleanup
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-local-insert): accept arguments
+ `position' and `data' instead of `from', `to' and `what'; since
+ position is zero-based, transmit it literally
+ (rudel-obby-connection::rudel-local-delete): instead of `from' and
+ `to' accept argument `position'; since position is
+ zero-based. transmit it literally
+ (rudel-obby-connection::rudel-obby/obby_document/record):
+ identified remaining arguments; dispatch actions to appropriate
+ methods; identify methods by interning their symbols
+ (rudel-obby-connection::rudel-obby/obby_document/record/ins): new
+ method; handle remote insert actions
+ (rudel-obby-connection::rudel-obby/obby_document/record/del): new
+ method; handle remote delete actions
+ * rudel.el (includes): include rudel-overlay
+ (rudel-document::rudel-detach-from-buffer): improved readability
+ (rudel-document::rudel-local-insert): instead of redundant
+ arguments `from', `to' and `what' accept only `position' and
+ `data'; update overlays
+ (rudel-document::rudel-local-delete): instead of redundant
+ arguments `from', `to' and `length' accept only `position' and
+ `length'; update overlays
+ (rudel-document::rudel-remote-insert): renamed arguments `from' ->
+ `position', `what' -> `data'; update overlays
+ (rudel-document::rudel-remote-delete): replaced arguments `from'
+ and `to' by `position'; update overlays
+ (rudel-handle-buffer-change): call rudel-local-{insert, delete}
+ with changed arguments
+
+2009-01-01 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-session::rudel-unsubscribed-documents): new
+ method; returns documents, to which the user associated with the
+ session is not yet subscribed
+ (rudel-subscribe): when called interactively, use
+ `rudel-unsubscribed-documents' to offer only unsubscribed
+ documents in completing read
+
+ * rudel-interactive.el (rudel-read-user-name): new function; read
+ a user name; could be used to enforce certain constraints on the
+ name
+ (rudel-read-user-color): new function; read a user color; could be
+ used to enforce certain constraints on the color
+
+ * obby/rudel-obby.el (rudel-obby-backend::rudel-ask-host-info):
+ new method; ask user for port number
+ (rudel-obby-backend::rudel-host): new method; require obby server
+ component, make the network process and construct the server
+ * obby/rudel-obby-server.el (new file): initial revision of obby
+ server for rudel
+ * obby/rudel-obby-client.el (header section): added keyword and
+ x-rcs
+ (rudel-obby-connection::rudel-publish): new method; send document
+ to server
+ (rudel-obby-connection::rudel-unsubscribe-from): send unsubscribe
+ notification to server
+ (rudel-obby-connection::rudel-local-insert): cleanup
+ (rudel-obby-connection::rudel-local-delete): new method; send
+ delete record to server and increase local revision
+ (rudel-obby-connection::rudel-obby/obby_document/sync_chunk):
+ improved user locating code; do not complain, when the user is not
+ found
+ (rudel-obby-connection::rudel-obby/obby_document/record): removed
+ useless debug message
+ * rudel.el (class rudel-session): update documentation string
+ (class rudel-server-session): new class; base class for server
+ sessions
+ (rudel-choose-backend): fixed void-variable when called
+ interactively
+ (rudel-host-session): provided initial implementation, which uses
+ the selected backend to create a server
+ (rudel-subscribe): call `set-window-buffer' instead of
+ `show-buffer'
+
+ * obby/rudel-obby.el (header section): fixed history
+ (rudel-obby-version): new constant; holds version of the obby
+ backend
+ (rudel-obby-protocol-version): new constant; holds the obby
+ protocol version understood by the backend
+ (rudel-obby-document::rudel-both-ids): new method; useful when
+ locating documents by means of owner and document id
+
+ * rudel-mode.el (header section): added keywords
+
+ * rudel-interactive.el (header section): added file comment
+
+2008-12-30 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (class rudel-session): converted to base class for
+ other session classes; removed slots `connection' and `self' which
+ are specific for client sessions
+ (rudel-session::rudel-end): empty now; derived classes do the work
+ (rudel-session::rudel-add-user): use `object-add-to-list'
+ (rudel-session::rudel-remove-user): use `object-remove-from-list'
+ (rudel-session::rudel-add-document): use `object-add-to-list'
+ (rudel-session::rudel-remove-document): use
+ `object-remove-from-list'
+ (class rudel-client-session): derived from `rudel-session';
+ additional slots `connection' and `self'
+ (rudel-client-session::rudel-end): detach buffers from documents
+ and call `rudel-disconnect' on connection
+ (class rudel-connection): documentation string
+ (rudel-connection::rudel-disconnect): remove hook
+ `after-change-functions' only locally
+ (rudel-join-session): construct a proper session name; store
+ backend object in the session; some comments
+
+ * obby/rudel-obby.el (rudel-obby-document): cleanup; improved
+ documentation strings
+
+ * rudel-overlay.el (new file): functions for managing overlays,
+ which indicate the authors of contributions in collaborative
+ buffers
+
+ * rudel.el (rudel-allocate-buffer-function): customization option
+ for buffer allocation function
+ (rudel-subscribe): call buffer allocation function instead of just
+ using the provided name
+ * rudel-interactive.el (rudel-allocate-buffer-clear-existing): new
+ function; in case of a conflict, allocate buffer for subscription
+ by clearing the existing buffer
+ (rudel-allocate-buffer-make-unique): new function; in case of a
+ conflict, allocate buffer for subscription by producing a unique
+ name
+
+ * rudel.el (customization): added customization group definition
+ for `rudel'
+
+ * obby/rudel-obby.el (includes): require `rudel-util' instead of
+ `rudel'
+ (rudel-connect): attach connection to socket object
+ (rudel-obby-document): removed slot `subscribed' as it is now
+ contained in the base class `rudel-document'
+ (rudel-obby-escape-string): call `rudel-obby-replace-in-string'
+ instead of `obby-replace-in-string'
+ (rudel-obby-unescape-string): call `rudel-obby-replace-in-string'
+ instead of `obby-replace-in-string'
+ * obby/rudel-obby-client.el
+ (rudel-obby-connection::rudel-state-change): required by
+ `rudel-sentinel-dispatch'
+ (rudel-obby-connection::rudel-subscribe-to): do not touch slot
+ `subscribed'
+ (rudel-obby-connection::rudel-obby/obby_sync_doclist_document):
+ retrieve subscribed users and add to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document_create): add
+ document owner to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document/subscribe): add
+ user to `subscribed' slot
+ (rudel-obby-connection::rudel-obby/obby_document/unsubscribe):
+ remove user from `subscribed' slot
+ * rudel.el (rudel-document): added slot `subscribed' which
+ contains a list of subscribed users
+ (rudel-subscribe): do not use `rudel-unsubscribed-documents';
+ instead list all documents for now
+ (rudel-publish-buffer): add self to `subscribed' slot
+
+ * rudel-util.el (rudel-state-change): cleanup; added comments
+
+ * rudel-mode.el (rudel-minor-keymap): Fixed invalid menu
+ definition
+
+ * obby/rudel-obby.el (whole file): moved class
+ `rudel-obby-connection' and related methods into file
+ `rudel-obby-client.el'
+ (rudel-obby-backend): added capability `track-subscriptions'
+ (rudel-obby-backend::rudel-connect): require `rudel-obby-client'
+ before constructing the connection object
+ * obby/rudel-obby-client.el (new file): moved class
+ `rudel-obby-connection' and related methods into this file
+
+2008-12-29 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * rudel.el (rudel-connection::rudel-change-color-): new method
+ handles color changes
+ (rudel-change-color): added basic implementation, which checks the
+ backend, asks the user for a new color and calls the connection
+ object
+
+ * rudel-util.el (rudel-socket-owner::rudel-state-change): called
+ when the state of the connection changes
+ (rudel-socket-owner::rudel-close): called when the connection is
+ closed
+ (rudel-sentinel-dispatch): the argument is a message, not the
+ actual state, the state is retrieved with `process-state'
+
+ * rudel-speedbar.el (whole file): cleanup; improved comments
+
+ * rudel-mode.el (whole file): improved comments
+ (rudel-read-{backend, document}): moved to rudel-interactive.el
+ (rudel-minor-keymap): added key binding for `rudel-change-color';
+ added `options' menu item
+
+ * rudel-interactive.el (whole file): user interaction functions
+ used by all Rudel components
+
+ * rudel-util.el (whole file): utility functions used by all Rudel
+ components
+
+ * rudel.el (whole file): improved comments
+ (rudel-backend::make-document): new function create an appropriate
+ document object for the backend
+ (rudel-session::rudel-end): added documentation string
+ (rudel-session::rudel-add-user): added documentation string
+ (rudel-session::rudel-remove-user): added documentation string
+ (rudel-session::rudel-remove-document): new method; remove
+ document from session
+ (rudel-connection::rudel-publish): new function; called when a
+ buffer is published
+ (rudel-connection::rudel-unsubscribe-from): new function; called
+ when a subscription is canceled
+ (class rudel-user): added documentation strings
+ (class rudel-document): added documentation strings
+ (rudel-document::rudel-attach-to-buffer): add to
+ `after-change-functions' hook only for the buffer in question;
+ added some comments
+ (rudel-document::rudel-detach-from-buffer): cleanup
+ (rudel-document::rudel-remote-insert): added comments
+ (rudel-document::rudel-remote-delete): added comments
+ (rudel-handle-buffer-change): added comments
+ (rudel-choose-backend): added comments
+ (rudel-end-session): additional error check
+ (rudel-subscribe): call `rudel-unsubscribed-documents' when
+ completing document name; added comments
+ (rudel-unpublish-buffer): call `rudel-detach-from-buffer' and
+ `rudel-unsubscribe-from'; added comments
+
+ * obby/rudel-obby.el (whole file): improved comments
+ (rudel-obby-backend::rudel-ask-connect-info): removed :override
+ tag; added comments
+ (rudel-obby-backend::rudel-connect): removed :override tag; use
+ `make-network-process' instead of `open-network-stream' and attach
+ filter and sentinel right away; removed some debug code
+ (rudel-obby-backend::rudel-disconnect): removed :override tag
+ (rudel-obby-backend::rudel-subscribe-to): removed :override tag
+ (rudel-obby-backend::rudel-local-insert): removed :override tag
+ (rudel-obby-backend::rudel-local-delete): removed :override tag
+ (rudel-obby-backend::rudel-make-document): new method; creates a
+ new rudel-obby-document object
+ (rudel-obby-backend::rudel-available-document-id): obtains an
+ unused document id, which can be assigned to a new document
+ (class rudel-obby-connection): removed useless `host' and `port'
+ slots
+ (rudel-obby-connection::rudel-receive): removed some debug code
+ (rudel-obby-connection::rudel-send): removed some debug code
+ (rudel-obby-connection::rudel-obby/net6_client_join): fixed syntax
+ error
+ (class rudel-obby-user): added accessors for slots `client-id' and
+ `user-id'
+ (rudel-obby-user::eieio-speedbar-description): removed :override
+ tag
+ (rudel-obby-user::eieio-speedbar-object-buttonname): removed
+ :override tag
+ (class rudel-obby-document): added accessors and documentation for
+ slot `id'
+ (rudel-obby-document::eieio-speedbar-object-buttonname): removed
+ :override tag
+ (rudel-obby-replace-in-string): new function; replace a set of
+ patterns in a string
+ (rudel-obby-escape-string): new function; replace obby control
+ characters with their escape sequences
+ (rudel-obby-unescape-string): new function; inverse of
+ `rudel-obby-escape-string'
+ (rudel-obby-parse-color): added documentation
+ (rudel-obby-format-color): added documentation
+ (rudel-obby-assemble-message): properly escape message components
+ (rudel-obby-parse-message): properly unescape message components
+
+ * README (whole file): some initial notes
+ * INSTALL (whole file): some initial notes
+
+2008-12-02 Jan Moringen <scymtym@users.sourceforge.net>
+
+ * obby (directory): new directory for files belonging to the obby
+ backend
+ * rudel-obby.el (whole file): moved to `obby' directory
+ * obby/rudel-obby.el (whole file): moved here from parent
+ directory
+
+ * Changelog (whole file): renamed to `ChangeLog?'
+ * ChangeLog? (whole file): fixed name
+
+ * INSTALL (whole file): added
+
+ * rudel.el (whole file): fixed some comments, removed some test
+ code
+ (rudel-version): new variable; global Rudel version
+ (rudel-sessions): removed; we only allow one session for now
+ (rudel-session): cleaned up
+ (rudel-session::rudel-end): cleaned up; added some comments
+ (rudel-session::rudel-add-user): cosmetic changes
+ (rudel-session::rudel-remove-user): cosmetic changes
+ (rudel-session::rudel-find-user): cosmetic changes
+ (rudel-session::rudel-add-document): cosmetic changes
+ (rudel-session::rudel-find-document): cosmetic changes
+ (rudel-backend::rudel-connect): improved documentation string
+ (rudel-backend::rudel-ask-host-info): renamed from
+ `rudel-ask-listen-info'
+ (rudel-backend::rudel-host): renamed from `rudel-listen'
+ (rudel-document::rudel-attach-to-buffer): cosmetic changes
+ (rudel-document::rudel-remote-insert): cleaned up
+ (rudel-document::rudel-remote-delete): cleaned up
+ (rudel-load-backends): cosmetic changes
+ (rudel-choose-backend): fixed message display
+ (rudel-host-session): improved documentation string
+ (rudel-change-color): raise an error since this is not yet
+ implemented
+ (rudel-subscribe): added comments
+ (rudel-unpublish-buffer): raise an error if the buffer has not
+ been published
+
+ * rudel.el (whole file): cleanup up some obsolete code
diff --git a/emacs.d/lisp/rudel/INSTALL b/emacs.d/lisp/rudel/INSTALL
new file mode 100644
index 0000000..2555d09
--- /dev/null
+++ b/emacs.d/lisp/rudel/INSTALL
@@ -0,0 +1,58 @@
+* REQUIREMENTS
+
+ Rudel is developed and tested only with GNU Emacs and therefore
+ unlikely to run on other Emacs variants like XEmacs.
+
+ To use Rudel, the following software is required:
+
+** GNU Emacs 22 or above
+ Rudel should work with recent versions of GNU Emacs starting from
+ version 22. Older versions of GNU Emacs or XEmacs may or not work
+ but are not actively tested.
+
+** Collection of Emacs Development Environment Tools (CEDET)
+ Cedet contains the object system Eieio, which is used in Rudel's
+ object-oriented implementation. Cedet can be obtained from
+ http://cedet.sourceforge.net/
+
+ IMPORTANT: It is necessary to use at least the 1.0pre6 version of
+ CEDET since it fixes a serious problem in the object system Eieio.
+
+ As of October 2009, Eieio is included in GNU Emacs. If you are
+ using a version built since then, you do not have to install it
+ yourself.
+
+** GnuTLS (optional)
+ Connections to Gobby servers require the gnutls-cli program.
+
+** Avahi (optional)
+ The Avahi daemon (http://avahi.org) is required for automatic
+ session discovery and advertising.
+
+ A version of GNU Emacs with Zeroconf support (GNU Emacs 23 or
+ above) is required to talk to the Avahi daemon.
+
+* INSTALLING
+
+ To install Rudel, download a released version or the current
+ development version from http://sourceforge.net/projects/rudel/ and
+ place the code in any directory you like.
+
+ Once Eieio (see CEDET in the REQUIREMENTS section above) is
+ installed, add the following to your personal Emacs configuration:
+
+ (load-file "/PATH/TO/RUDEL/rudel-loaddefs.el")
+
+ This will set Rudel up to be loaded on demand when one of the
+ commands `rudel-join-session', `rudel-host-session' or
+ `global-rudel-minor-mode' is invoked.
+
+* COMPILING
+
+ In order to achieve better performance, Emacs can byte-compile the
+ Rudel code. This can be done by opening rudel-compile.el in Emacs
+ and invoking M-x eval-buffer.
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/Project.ede b/emacs.d/lisp/rudel/Project.ede
new file mode 100644
index 0000000..ff3a264
--- /dev/null
+++ b/emacs.d/lisp/rudel/Project.ede
@@ -0,0 +1,24 @@
+;; Object rudel
+;; EDE project file.
+(ede-proj-project "rudel"
+ :name "rudel"
+ :version "0.3"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp-autoloads "autoloads"
+ :name "autoloads"
+ :path ""
+ :autoload-file "rudel-loaddefs.el"
+ :autoload-dirs '("." "jupiter" "obby" "wave" "zeroconf")
+ )
+ (ede-proj-target-elisp "compile"
+ :name "rudel"
+ :path ""
+ :source '("rudel.el" "rudel-util.el" "rudel-mode.el" "rudel-interactive.el" "rudel-overlay.el" "rudel-speedbar.el" "rudel-operators.el" "rudel-operations.el" "rudel-compat.el" "rudel-tls.el" "rudel-errors.el" "rudel-state-machine.el" "rudel-backend.el" "rudel-protocol.el" "rudel-session-initiation.el" "rudel-icons.el" "rudel-hooks.el" "rudel-transport.el" "rudel-chat.el")
+ )
+ )
+ :mailinglist "rudel-devel@lists.sourceforge.net"
+ :web-site-url "http://rudel.sourceforge.net/"
+ :web-site-directory "/scymtym,rudel@web.sourceforge.net:/home/groups/r/ru/rudel/htdocs"
+ :configuration-variables 'nil
+ )
diff --git a/emacs.d/lisp/rudel/README b/emacs.d/lisp/rudel/README
new file mode 100644
index 0000000..aeacba7
--- /dev/null
+++ b/emacs.d/lisp/rudel/README
@@ -0,0 +1,88 @@
+* INTRODUCTION
+
+ Rudel is collaborative editing environment for GNU Emacs. Its
+ purpose is to share buffers with other users in order to edit the
+ contents of those buffers collaboratively. Rudel supports multiple
+ backends to enable communication with other collaborative editors
+ using different protocols, though currently Obby (for use with the
+ Gobby editor) is the only fully-functional one.
+
+ Since Rudel is not an application, but an extension to Emacs, it is
+ not started and used like most applications (not even Emacs
+ applications like Gnus). Rudel mostly works in the background to
+ change the behavior of the set of Emacs buffers for which it has
+ been activated.
+
+ The user interface consists of a set of key bindings, a menu entry
+ and some visual status indicators, which are added to the text and
+ mode line of buffers for which Rudel has been activated.
+
+* GETTING STARTED
+
+ Assuming Rudel has already been installed and auto loading has been
+ set up, a global Rudel mode can be enabled as follows:
+
+ : M-x global-rudel-minor-mode
+
+ This will enabled Rudel's key bindings and menu entry.
+
+** JOINING A SESSION
+
+ : M-x rudel-join-session [ C-c c j ]
+
+ Depending on the installed Rudel backends, system environment and
+ configuration, a number of questions will be asked, followed by an
+ attempt to join session described by your answers.
+
+ A typical example of the questions asked when joining a session may
+ look like this:
+
+ Server: localhost RET
+ Port (default 6522): RET
+ Username: jan RET
+ Color: light sky blue RET
+ Use Encryption (y or n): n RET
+ Global Password: RET
+ User Password: RET
+
+ IMPORTANT: For sessions using the obby backend (like in the example
+ above), the following restriction has to be taken into account:
+ + When the server is Rudel inside an Emacs process:
+ Encryption cannot be used currently in this case. Consequently
+ the answer to the `Use Encryption (y or n):' prompt above has to
+ be `n RET'.
+ + When the server is a Gobby process:
+ Gobby only supports encrypted connections. So the answer has to
+ be `y RET' is this case.
+
+ It is possible to configure frequently used sessions using the
+ customization options `rudel-configured-sessions'. When one or more
+ sessions are configured, `rudel-join-session' will provide choices
+ like "my-configured-session", ... and "ask-protocol". Selecting
+ "ask-protocol" invokes the behavior described above. Selecting one
+ of the configured sessions connects to that session without asking
+ for all the data.
+
+** HOSTING A SESSION
+
+ : M-x rudel-host-session [ C-c c h ]
+
+ Note that the session starts out without any participating users
+ (This is sometimes referred to as being a dedicated server). If you
+ want to participate in the session you host, you have to join it as
+ described above.
+
+* KNOWN ISSUES
+
+ + Publishing eshell buffers will cause your session to be
+ disconnected since eshell disables the hooks that Rudel uses to
+ catch changes to the buffer. As a workaround, you can use M-x
+ ansi-term or another terminal emulator.
+
+* LICENSE
+
+ Rudel is licensed under the same terms as GNU Emacs.
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/TODO b/emacs.d/lisp/rudel/TODO
new file mode 100644
index 0000000..e5e4bf4
--- /dev/null
+++ b/emacs.d/lisp/rudel/TODO
@@ -0,0 +1,436 @@
+* Future
+** NEW Handle messages spanning multiple frames
+ + Component :: beep-transport
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** NEW Operation log can grow beyond all bounds (#37)
+ + Component :: obby-general
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ When no remote operations are received, the log of local operation
+ is not reset and therefore grows beyond all bounds.
+** NEW Terminating sessions does not work (#47)
+ + Component :: rudel-general
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ There is a menu entry for terminating sessions which are hosted by
+ Rudel, but it does not do anything.
+** NEW Rename document message is not understood (#7)
+ + Component :: obby-client
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** NEW Rename document message is not understood (#8)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** TODO Notification mechanism
+ + Component :: user-interface
+ + Type :: task
+ + Reporter :: jan
+ + Type :: task
+ + Assigned ::
+** TODO SubEthaEdit client functionality
+ + Component :: subethaedit-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Show cursor positions of other users (#5)
+ + Component :: rudel-user-interface
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Some kind of server log buffer (#11)
+ + Component :: rudel-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ It would be nice to log server events. This could be done in a
+ separate buffer or using a dedicated mechanism like
+ rudel-notification.
+** TODO Backends should be able to offer additional menu items (#14)
+ + Component :: rudel-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Obby session can be protected by passwords (#15)
+ + Component :: obby-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+** TODO Obby users can protect their accounts with passwords (#16)
+ + Component :: obby-general
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ The Gobby implementation is in obby/inc/server_buffer.hpp:851
+** TODO Zeroconf session notification (#52)
+ + Component :: zeroconf
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+ Watch interesting Zeroconf services and use `rudel-notify` if new
+ services are discovered
+** TODO State machine diagram (#59)
+ + Component :: obby-client
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO State machine diagram (#60)
+ + Component :: obby-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Send key presses as chat messages (#61)
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: Jan
+ + Assigned ::
+ Sending key presses as chat messages could be really useful for
+ somebody something using rudel.
+** STARTED BEEP transport
+ + Component :: beep-transport
+ + Type :: task
+ + Reporter :: jan
+ + Assigned :: jan
+** STARTED Reference manual (#46)
+ + Component :: documentation
+ + Type :: task
+ + Reporter :: jan
+ + Assigned :: jan
+ In addition to the `README`, a proper reference manual would be
+ nice. At some point, complete info documentation may be
+ desirable. Docbook seems to be the best approach since we get (at
+ least):
+ + Pdf
+ + Html
+ + Info
+
+
+* Milestone rudel-0.4
+** TODO Telepathy transport
+ + Component :: telepathy-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+
+* Milestone rudel-0.3
+** TODO Multiple username/password attempts in one login attempt
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Infinote client functionality
+ + Component :: infinote-backend
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** TODO Support for trees of documents
+ + Component :: rudel-general
+ + Type :: task
+ + Reporter :: jan
+ + Assigned ::
+** NEW Get rid of error calls in the server (#58)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ It makes no sense to call `error` when something goes wrong in
+ server code that is called from the process filter. Instead, we
+ should try to recover.
+** NEW Global mode line publish state mode does not work for all new buffers (#55)
+ + Component :: rudel-user-interface
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+ `global-mode-line-publish-state-mode` is define using
+ `define-globalized-mode`. This seems to only enabled the associated
+ minor mode for buffers create by `find-file` and after major mode
+ changes. The minor mode is not activated for buffers create by
+ `create-buffer`. Since this is used when subscribing to documents,
+ this is a problem.
+** NEW Handle net6_encryption_info messages (#57)
+ + Component :: obby-backend
+ + Type :: defect
+ + Reporter :: jan
+ + Assigned ::
+** TODO Only read color hue, not complete colors (#53)
+ + Component :: rudel-user-interface
+ + Type :: enhancement
+ + Reporter :: jan
+ + Assigned ::
+ Taking control over saturation and value away from the user makes
+ it impossible to choose unreadable colors.
+
+
+* Milestone rudel-0.2
+** DONE Use state pattern (#18)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Server buffers go out of sync when multi-byte characters are used (#56)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Terminate connections properly when something goes wrong (#51)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Removing documents does not work (#45)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Search list of offline users when new users log in (#44)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Reference card (#2)
+ + Component :: documentation
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE ode-line indicator of buffer status (#6)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Author overlay face may not exist (#54)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Visualization of user status (#9)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Update overlays when users change colors (#23)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Allow to toggle display of author overlays (#33)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Update file headers (#50)
+ + Component :: documentation
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: trivial
+ + Reporter :: jan
+** DONE Proper Zeroconf support (#21)
+ + Component :: zeroconf
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Add discovery component (#22)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Define initialize-instance with slots or &rest slots? (#49)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** DONE Use oref to get object names (#24)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Overlays should be removed when a buffer is detached from its document (#39)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Unsafe use of (call-next-method) (#48)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Handle `net6_login_failed' message (#10)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Add debug hints to macros (#43)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Use state pattern (#17)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Use with-parsed-arguments (#40)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+
+
+* Milestone rudel-0.1
+** FIXED User names and colors are not checked for conflicts (#12)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Write some html for rudel.sourceforge.net (#27)
+ + Component :: www
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** INVALID Repeated publishing leads to multiple document instances (#30)
+ + Component :: obby-backend
+ + Resolution :: invalid
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Document suffixes are not handled properly (#42)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Fix license texts (#32)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: trivial
+ + Reporter :: jan
+** WONTFIX Overlays break on last character (#29)
+ + Component :: rudel-user-interface
+ + Resolution :: worksforme
+ + Type :: defect
+ + Priority :: minor
+ + Reporter :: jan
+** FIXED Encodings are not handled in obby backend (#1)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Major mode changes break subscribed buffers (#19)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Editing in overwrite mode breaks synchronization (#35)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Yanking produces insertion and immediate deletion of the region (#36)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Documents with identical names but distinct suffixes map to same buffer (#41)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Killing a buffer does not detach it from its document (#38)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** INVALID Rudel client crashes Gobby (#25)
+ + Component :: obby-general
+ + Resolution :: invalid
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Add screenshot of session with Gobby (#20)
+ + Component :: www
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: trivial
+ + Reporter :: jan
+** DONE Replace 't with t (#34)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Operations of type jupiter-compound cannot be applied to buffers
+ (#31)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+** DONE Do not sync any chunks when buffer is empty (#28)
+ + Component :: obby-backend
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: minor
+ + Reporter :: jan
+** DONE Implement Jupiter algorithm (#13)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: major
+ + Reporter :: jan
+** DONE Replace email address (#26)
+ + Component :: rudel-general
+ + Resolution :: fixed
+ + Type :: task
+ + Priority :: major
+ + Reporter :: jan
+** FIXED Mark contributions using overlays (#4)
+ + Component :: rudel-user-interface
+ + Resolution :: fixed
+ + Type :: enhancement
+ + Priority :: major
+ + Reporter :: jan
+** FIXED When a user leaves and joins a second user object is created (#3)
+ + Component :: obby-general
+ + Resolution :: fixed
+ + Type :: defect
+ + Priority :: major
+ + Reporter :: jan
+
+Local variables:
+mode: org
+end:
diff --git a/emacs.d/lisp/rudel/doc/.svn/all-wcprops b/emacs.d/lisp/rudel/doc/.svn/all-wcprops
new file mode 100644
index 0000000..28e96e7
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/.svn/all-wcprops
@@ -0,0 +1,23 @@
+K 25
+svn:wc:ra_dav:version-url
+V 37
+/svnroot/rudel/!svn/ver/399/trunk/doc
+END
+card.pdf
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svnroot/rudel/!svn/ver/396/trunk/doc/card.pdf
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 49
+/svnroot/rudel/!svn/ver/297/trunk/doc/Project.ede
+END
+card.tex
+K 25
+svn:wc:ra_dav:version-url
+V 46
+/svnroot/rudel/!svn/ver/399/trunk/doc/card.tex
+END
diff --git a/emacs.d/lisp/rudel/doc/.svn/entries b/emacs.d/lisp/rudel/doc/.svn/entries
new file mode 100644
index 0000000..5128808
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/.svn/entries
@@ -0,0 +1,130 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/doc
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-10T00:39:48.026786Z
+399
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+card.pdf
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+2df6dba381ea9728a9850132f09a68af
+2009-10-10T00:38:34.122289Z
+396
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+68211
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+7b9a11f15f24e39437250456cd11bae7
+2009-10-03T01:25:19.588187Z
+297
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+408
+
+card.tex
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+be52a552897987dec702a9a2eee7d347
+2009-10-10T00:39:48.026786Z
+399
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9459
+
diff --git a/emacs.d/lisp/rudel/doc/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/doc/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..0348d84
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,20 @@
+;; Object doc
+;; EDE project file.
+(ede-proj-project "rudel/doc"
+ :name "doc"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-makefile-miscelaneous "card.pdf"
+ :name "card.pdf"
+ :path ""
+ :source '("card.tex")
+ :rules (list
+ (ede-makefile-rule "pdftex"
+ :target "card.pdf"
+ :dependencies "card.tex"
+ :rules '("pdftex -t landscape $<")
+ )
+ )
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/doc/.svn/text-base/card.pdf.svn-base b/emacs.d/lisp/rudel/doc/.svn/text-base/card.pdf.svn-base
new file mode 100644
index 0000000..60ddf36
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/.svn/text-base/card.pdf.svn-base
Binary files differ
diff --git a/emacs.d/lisp/rudel/doc/.svn/text-base/card.tex.svn-base b/emacs.d/lisp/rudel/doc/.svn/text-base/card.tex.svn-base
new file mode 100644
index 0000000..8be513d
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/.svn/text-base/card.tex.svn-base
@@ -0,0 +1,329 @@
+%% card.tex --- Reference Card for Rudel 0.2
+%
+% Copyright (c) 1987, 1992 Free Software Foundation, Inc.
+% Copyright (c) 2009 Jan Moringen
+%
+% Author: Stephen Gildea <gildea@erl.mit.edu> (refcard.tex format)
+% Dave Gillespie <daveg@synaptics.com> (Calc reference card)
+% Jan Moringen <scymtym@users.sourceforge.net> (Rudel)
+%
+% This file is part of Rudel.
+%
+% Rudel 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 3 of the License, or
+% (at your option) any later version.
+%
+% Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+%% Commentary:
+%
+% The format for this file is adapted from the GNU Emacs reference
+% card version 1.9, by Stephen Gildea and the GNU Calc reference card
+% by Dave Gillespie.
+%
+% This file is intended to be processed by plain TeX.
+% Typical command to format: pdftex -t landscape card.tex
+% Typical command to print: tex card.tex
+% dvips -t landscape card.dvi
+
+
+%% Constants
+%
+
+\def\versionnumber{0.2}
+\def\versiondate{September 2009}
+\def\year{2009}
+
+\def\copyrightnotice{
+\vskip 1ex plus 2 fill\begingroup\small
+\centerline{Copyright \copyright\ \year\ Jan Moringen}
+\centerline{written by Jan Moringen}
+\centerline{for Rudel version \versionnumber\ (\versiondate)}
+
+Permission is granted to make and distribute copies of
+this card provided the copyright notice and this permission notice
+are preserved on all copies.
+
+%For copies of the GNU Emacs Calc manual, write to the Free Software
+%Foundation, Inc., 675 Massachusetts Ave, Cambridge MA 02139.
+
+\endgroup}
+
+
+
+%% Header
+%
+
+% make \bye not \outer so that the \def\bye in the \else clause below
+% can be scanned without complaint.
+\def\bye{\par\vfill\supereject\end}
+
+\newdimen\intercolumnskip
+\newbox\columna
+\newbox\columnb
+
+\def\scaledmag#1{ scaled \magstep #1}
+
+% This format was designed by Stephen Gildea in October 1986.
+\hsize 3.2in
+\vsize 7.95in
+\hoffset -.75in
+\voffset -.745in
+\font\titlefont=cmbx10 \scaledmag2
+\font\headingfont=cmbx10 \scaledmag1
+\font\subheadingfont=cmbx10 \scaledmag0
+\font\smallfont=cmr6
+\font\smallsy=cmsy6
+\font\eightrm=cmr8
+\font\eightbf=cmbx8
+\font\eightit=cmti8
+\font\eighttt=cmtt8
+\font\eightsy=cmsy8
+\textfont0=\eightrm
+\textfont2=\eightsy
+\font\notefont=cmti7
+\def\rm{\eightrm}
+\def\bf{\eightbf}
+\def\it{\eightit}
+\def\tt{\eighttt}
+\normalbaselineskip=.8\normalbaselineskip
+\normallineskip=.8\normallineskip
+\normallineskiplimit=.8\normallineskiplimit
+\normalbaselines\rm %make definitions take effect
+
+\let\maxcolumn=c
+\nopagenumbers
+
+\intercolumnskip=.46in
+\def\abc{a}
+\output={%
+ % This next line is useful when designing the layout.
+ %\immediate\write16{Column \folio\abc\space starts with \firstmark}
+ \if \maxcolumn\abc \multicolumnformat \global\def\abc{a}
+ \else\if a\abc
+ \global\setbox\columna\columnbox \global\def\abc{b}
+ %% in case we never use \columnb (two-column mode)
+ \global\setbox\columnb\hbox to -\intercolumnskip{}
+ \else
+ \global\setbox\columnb\columnbox \global\def\abc{c}\fi\fi}
+
+\def\multicolumnformat{\shipout\vbox{\makeheadline
+ \hbox{\box\columna\hskip\intercolumnskip
+ \box\columnb\hskip\intercolumnskip\columnbox}
+ \makefootline}\advancepageno}
+\def\columnbox{\leftline{\pagebody}}
+
+\def\bye{\par\vfill\supereject
+ \if a\abc \else\null\vfill\eject\fi
+ \if a\abc \else\null\vfill\eject\fi
+ \end}
+
+% we won't be using math mode much, so redefine some of the characters
+% we might want to talk about
+\catcode`\^=12
+\catcode`\_=12
+
+\chardef\\=`\\
+\chardef\{=`\{
+\chardef\}=`\}
+
+\parindent 0pt
+\parskip 1ex plus .5ex minus .5ex
+
+\def\small{\smallfont\textfont2=\smallsy\baselineskip=.8\baselineskip}
+
+\outer\def\newcolumn{\vfill\eject}
+
+\outer\def\title#1{{\titlefont\centerline{#1}}\vskip 1ex plus .5ex}
+
+\outer\def\section#1{\par\filbreak
+ \vskip 3ex plus 2ex minus 2ex {\headingfont #1}\mark{#1}%
+ \vskip 2ex plus 1ex minus 1.5ex}
+
+\outer\def\subsection#1{\par\filbreak
+ \vskip 3ex plus 2ex minus 2ex {\subheadingfont #1}\mark{#1}%
+ \vskip 2ex plus 1ex minus 1.5ex}
+
+\newdimen\keyindent
+
+\def\beginindentedkeys{\keyindent=1em}
+\def\endindentedkeys{\keyindent=0em}
+\endindentedkeys
+
+\def\paralign{\vskip\parskip\halign}
+
+\def\<#1>{$\langle${\rm #1}$\rangle$}
+
+\def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows
+
+\def\key#1#2{\leavevmode\hbox to \hsize{\vtop
+ {\hsize=.75\hsize\rightskip=1em
+ \hskip\keyindent\relax#1}\kbd{#2}\hfil}}
+
+\newbox\metaxbox
+\setbox\metaxbox\hbox{\kbd{M-x }}
+\newdimen\metaxwidth
+\metaxwidth=\wd\metaxbox
+
+% Redefine to make spaces a bit smaller
+\let\wkbd=\kbd
+\def\kbd#1{{\spaceskip=.37em\tt#1}\null}
+
+\def\wkey#1#2{\leavevmode\hbox to \hsize{\vtop
+ {\hsize=.75\hsize\rightskip=1em
+ \hskip\keyindent\relax#1}\wkbd{#2}\hfil}}
+
+\def\ccc{C-c\ c\ }
+\def\,{{\rm ,\hskip.55em}\ignorespaces}
+\def\lesssectionskip{\vskip-1.5ex}
+
+\def\iline#1{\par\line{\hskip1em\relax #1\hfill}\par}
+
+\font\eighti=cmmi8
+\textfont1=\eighti
+
+
+%% Document
+%
+
+\title{Rudel Reference Card}\vskip-1ex
+\centerline{\tt http://rudel.sourceforge.net}\vskip1ex
+\centerline{(for Rudel version \versionnumber\ of \versiondate)}
+
+\section{Key Bindings}
+
+\lesssectionskip
+{\notefont All key bindings are only available when the global Rudel
+minor mode is active. See ``Minor Modes'' below.}
+
+\subsection{Hosting and Joining}
+
+\wkey{Join a Rudel session}{\ccc j}
+\wkey{Leave a Rudel session}{\ccc e}
+
+\wkey{Host a Rudel session}{\ccc h}
+
+\subsection{In a Session}
+
+The following commands are available once a Rudel session has been
+joined:
+
+\key{Change color}{\ccc c}
+
+\key{Create and publish document for buffer}{\ccc p}
+\key{Subscribe to a document}{\ccc s}
+
+The following commands are only available if the current buffer has an
+associated document (achieved by publishing or subscribing):
+
+\key{Detach buffer from document (unsubscribe)}{\ccc u}
+
+\section{Minor Modes}
+
+\subsection{Global Rudel Minor Mode}
+
+The global Rudel minor mode global-rudel-minor-mode is responsible for
+installing the Rudel menu and keymap.
+
+\subsection{Participants in Header Line}
+
+The mode ({\tt rudel-header-subscriptions-minor-mode}) shows
+subscribed users in the header line of the buffer.
+
+The associated global mode ({\tt global-rudel-header-subscriptions
+mode}) turns the mode on or off in all suitable buffers.
+
+\subsection{Buffer Status in Mode Line}
+
+The mode ({\tt rudel-mode-line-publish-state-minor-mode}) shows the
+publication state of the buffer in its mode line ({\tt P}: published,
+{\tt -}: not published)
+
+The associated global mode ({\tt
+global-rudel-mode-line-publish-state-mode}) turns the mode on or off
+in all suitable buffers.
+
+\eject
+
+\section{Backends}
+
+\lesssectionskip
+In Rudel, various kinds of backends are used to provide multiple
+pluggable implementations of functionalities like communication
+protocols, network transport, session initiation and parts of the user
+interface.
+
+\subsection{Protocol}
+
+{\bf Obby}
+
+This backend implements the obby protocol used by the Gobby
+collaborative editor until (including) version 4.9.
+
+\subsection{Session Initiation}
+
+{\bf Configured Sessions}
+
+Frequently used sessions can be configured permanently using the {\tt
+rudel-configured-sessions} customization variable. When there are
+configured sessions, connecting to one of these session is offered
+when joining a session using \kbd{\ccc j}.
+
+{\bf Zeroconf}
+
+The Zeroconf backends discovers collaboration sessions which are
+advertised using, well Zeroconf. Currently, it works for Rudel (obby
+backend) and Obby servers. When there are Zeroconf-advertised
+sessions, using \kbd{\ccc j} to join a session will display these
+sessions.
+
+\section{Examples}
+
+\subsection{Joining a Session with the obby backend}
+
+{\bf Without Zeroconf Discovery}
+
+\kbd{\ccc j}\hfil\break
+{\tt Server: }{\it SERVER} \kbd{RET}\hfil\break
+{\tt Port (default 6522): } \kbd{RET}\hfil\break
+{\tt Username: }{\it NAME} \kbd{RET}\hfil\break
+{\tt Color: }{\it COLOR} \kbd{RET}\hfil\break
+{\notefont (use bright colors like yellow)}\hfil\break
+{\it When connecting to a Rudel server:}\hfil\break
+-\hskip2ex {\tt Use Encryption (yes or no): }{\it NO} \kbd{RET}\hfil\break
+{\it When connecting to a Gobby server:}\hfil\break
+-\hskip2ex {\tt Use Encryption (yes or no): }{\it YES} \kbd{RET}\hfil\break
+{\tt Global Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\it This password controls access to the session; just \kbd{RET} for
+none}\hfil\break
+{\tt User Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\it This password prevents name stealing; just \kbd{RET} for
+none}\hfil\break
+
+{\bf With Zeroconf Discovery}
+
+\kbd{\ccc j}\hfil\break
+{\tt Choose Session: }Zeroconf advertised session {\it
+"NAME"}\kbd{RET}\hfil\break
+{\notefont (Note: by choosing "ask-protocol" here, you can still get the
+above behavior)}\hfil\break
+{\tt Username: }{\it NAME} \kbd{RET}\hfil\break
+{\tt Color: }{\it COLOR} \kbd{RET}\hfil\break
+{\tt Global Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\tt User Password: }{\it PASSWORD} \kbd{RET}\hfil
+
+\copyrightnotice
+
+\bye
+
+% Local variables:
+% mode: plain-TeX; eval: (tex-pdf-mode);
+% End:
diff --git a/emacs.d/lisp/rudel/doc/Project.ede b/emacs.d/lisp/rudel/doc/Project.ede
new file mode 100644
index 0000000..0348d84
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/Project.ede
@@ -0,0 +1,20 @@
+;; Object doc
+;; EDE project file.
+(ede-proj-project "rudel/doc"
+ :name "doc"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-makefile-miscelaneous "card.pdf"
+ :name "card.pdf"
+ :path ""
+ :source '("card.tex")
+ :rules (list
+ (ede-makefile-rule "pdftex"
+ :target "card.pdf"
+ :dependencies "card.tex"
+ :rules '("pdftex -t landscape $<")
+ )
+ )
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/doc/card.pdf b/emacs.d/lisp/rudel/doc/card.pdf
new file mode 100644
index 0000000..60ddf36
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/card.pdf
Binary files differ
diff --git a/emacs.d/lisp/rudel/doc/card.tex b/emacs.d/lisp/rudel/doc/card.tex
new file mode 100644
index 0000000..8be513d
--- /dev/null
+++ b/emacs.d/lisp/rudel/doc/card.tex
@@ -0,0 +1,329 @@
+%% card.tex --- Reference Card for Rudel 0.2
+%
+% Copyright (c) 1987, 1992 Free Software Foundation, Inc.
+% Copyright (c) 2009 Jan Moringen
+%
+% Author: Stephen Gildea <gildea@erl.mit.edu> (refcard.tex format)
+% Dave Gillespie <daveg@synaptics.com> (Calc reference card)
+% Jan Moringen <scymtym@users.sourceforge.net> (Rudel)
+%
+% This file is part of Rudel.
+%
+% Rudel 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 3 of the License, or
+% (at your option) any later version.
+%
+% Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+%% Commentary:
+%
+% The format for this file is adapted from the GNU Emacs reference
+% card version 1.9, by Stephen Gildea and the GNU Calc reference card
+% by Dave Gillespie.
+%
+% This file is intended to be processed by plain TeX.
+% Typical command to format: pdftex -t landscape card.tex
+% Typical command to print: tex card.tex
+% dvips -t landscape card.dvi
+
+
+%% Constants
+%
+
+\def\versionnumber{0.2}
+\def\versiondate{September 2009}
+\def\year{2009}
+
+\def\copyrightnotice{
+\vskip 1ex plus 2 fill\begingroup\small
+\centerline{Copyright \copyright\ \year\ Jan Moringen}
+\centerline{written by Jan Moringen}
+\centerline{for Rudel version \versionnumber\ (\versiondate)}
+
+Permission is granted to make and distribute copies of
+this card provided the copyright notice and this permission notice
+are preserved on all copies.
+
+%For copies of the GNU Emacs Calc manual, write to the Free Software
+%Foundation, Inc., 675 Massachusetts Ave, Cambridge MA 02139.
+
+\endgroup}
+
+
+
+%% Header
+%
+
+% make \bye not \outer so that the \def\bye in the \else clause below
+% can be scanned without complaint.
+\def\bye{\par\vfill\supereject\end}
+
+\newdimen\intercolumnskip
+\newbox\columna
+\newbox\columnb
+
+\def\scaledmag#1{ scaled \magstep #1}
+
+% This format was designed by Stephen Gildea in October 1986.
+\hsize 3.2in
+\vsize 7.95in
+\hoffset -.75in
+\voffset -.745in
+\font\titlefont=cmbx10 \scaledmag2
+\font\headingfont=cmbx10 \scaledmag1
+\font\subheadingfont=cmbx10 \scaledmag0
+\font\smallfont=cmr6
+\font\smallsy=cmsy6
+\font\eightrm=cmr8
+\font\eightbf=cmbx8
+\font\eightit=cmti8
+\font\eighttt=cmtt8
+\font\eightsy=cmsy8
+\textfont0=\eightrm
+\textfont2=\eightsy
+\font\notefont=cmti7
+\def\rm{\eightrm}
+\def\bf{\eightbf}
+\def\it{\eightit}
+\def\tt{\eighttt}
+\normalbaselineskip=.8\normalbaselineskip
+\normallineskip=.8\normallineskip
+\normallineskiplimit=.8\normallineskiplimit
+\normalbaselines\rm %make definitions take effect
+
+\let\maxcolumn=c
+\nopagenumbers
+
+\intercolumnskip=.46in
+\def\abc{a}
+\output={%
+ % This next line is useful when designing the layout.
+ %\immediate\write16{Column \folio\abc\space starts with \firstmark}
+ \if \maxcolumn\abc \multicolumnformat \global\def\abc{a}
+ \else\if a\abc
+ \global\setbox\columna\columnbox \global\def\abc{b}
+ %% in case we never use \columnb (two-column mode)
+ \global\setbox\columnb\hbox to -\intercolumnskip{}
+ \else
+ \global\setbox\columnb\columnbox \global\def\abc{c}\fi\fi}
+
+\def\multicolumnformat{\shipout\vbox{\makeheadline
+ \hbox{\box\columna\hskip\intercolumnskip
+ \box\columnb\hskip\intercolumnskip\columnbox}
+ \makefootline}\advancepageno}
+\def\columnbox{\leftline{\pagebody}}
+
+\def\bye{\par\vfill\supereject
+ \if a\abc \else\null\vfill\eject\fi
+ \if a\abc \else\null\vfill\eject\fi
+ \end}
+
+% we won't be using math mode much, so redefine some of the characters
+% we might want to talk about
+\catcode`\^=12
+\catcode`\_=12
+
+\chardef\\=`\\
+\chardef\{=`\{
+\chardef\}=`\}
+
+\parindent 0pt
+\parskip 1ex plus .5ex minus .5ex
+
+\def\small{\smallfont\textfont2=\smallsy\baselineskip=.8\baselineskip}
+
+\outer\def\newcolumn{\vfill\eject}
+
+\outer\def\title#1{{\titlefont\centerline{#1}}\vskip 1ex plus .5ex}
+
+\outer\def\section#1{\par\filbreak
+ \vskip 3ex plus 2ex minus 2ex {\headingfont #1}\mark{#1}%
+ \vskip 2ex plus 1ex minus 1.5ex}
+
+\outer\def\subsection#1{\par\filbreak
+ \vskip 3ex plus 2ex minus 2ex {\subheadingfont #1}\mark{#1}%
+ \vskip 2ex plus 1ex minus 1.5ex}
+
+\newdimen\keyindent
+
+\def\beginindentedkeys{\keyindent=1em}
+\def\endindentedkeys{\keyindent=0em}
+\endindentedkeys
+
+\def\paralign{\vskip\parskip\halign}
+
+\def\<#1>{$\langle${\rm #1}$\rangle$}
+
+\def\kbd#1{{\tt#1}\null} %\null so not an abbrev even if period follows
+
+\def\key#1#2{\leavevmode\hbox to \hsize{\vtop
+ {\hsize=.75\hsize\rightskip=1em
+ \hskip\keyindent\relax#1}\kbd{#2}\hfil}}
+
+\newbox\metaxbox
+\setbox\metaxbox\hbox{\kbd{M-x }}
+\newdimen\metaxwidth
+\metaxwidth=\wd\metaxbox
+
+% Redefine to make spaces a bit smaller
+\let\wkbd=\kbd
+\def\kbd#1{{\spaceskip=.37em\tt#1}\null}
+
+\def\wkey#1#2{\leavevmode\hbox to \hsize{\vtop
+ {\hsize=.75\hsize\rightskip=1em
+ \hskip\keyindent\relax#1}\wkbd{#2}\hfil}}
+
+\def\ccc{C-c\ c\ }
+\def\,{{\rm ,\hskip.55em}\ignorespaces}
+\def\lesssectionskip{\vskip-1.5ex}
+
+\def\iline#1{\par\line{\hskip1em\relax #1\hfill}\par}
+
+\font\eighti=cmmi8
+\textfont1=\eighti
+
+
+%% Document
+%
+
+\title{Rudel Reference Card}\vskip-1ex
+\centerline{\tt http://rudel.sourceforge.net}\vskip1ex
+\centerline{(for Rudel version \versionnumber\ of \versiondate)}
+
+\section{Key Bindings}
+
+\lesssectionskip
+{\notefont All key bindings are only available when the global Rudel
+minor mode is active. See ``Minor Modes'' below.}
+
+\subsection{Hosting and Joining}
+
+\wkey{Join a Rudel session}{\ccc j}
+\wkey{Leave a Rudel session}{\ccc e}
+
+\wkey{Host a Rudel session}{\ccc h}
+
+\subsection{In a Session}
+
+The following commands are available once a Rudel session has been
+joined:
+
+\key{Change color}{\ccc c}
+
+\key{Create and publish document for buffer}{\ccc p}
+\key{Subscribe to a document}{\ccc s}
+
+The following commands are only available if the current buffer has an
+associated document (achieved by publishing or subscribing):
+
+\key{Detach buffer from document (unsubscribe)}{\ccc u}
+
+\section{Minor Modes}
+
+\subsection{Global Rudel Minor Mode}
+
+The global Rudel minor mode global-rudel-minor-mode is responsible for
+installing the Rudel menu and keymap.
+
+\subsection{Participants in Header Line}
+
+The mode ({\tt rudel-header-subscriptions-minor-mode}) shows
+subscribed users in the header line of the buffer.
+
+The associated global mode ({\tt global-rudel-header-subscriptions
+mode}) turns the mode on or off in all suitable buffers.
+
+\subsection{Buffer Status in Mode Line}
+
+The mode ({\tt rudel-mode-line-publish-state-minor-mode}) shows the
+publication state of the buffer in its mode line ({\tt P}: published,
+{\tt -}: not published)
+
+The associated global mode ({\tt
+global-rudel-mode-line-publish-state-mode}) turns the mode on or off
+in all suitable buffers.
+
+\eject
+
+\section{Backends}
+
+\lesssectionskip
+In Rudel, various kinds of backends are used to provide multiple
+pluggable implementations of functionalities like communication
+protocols, network transport, session initiation and parts of the user
+interface.
+
+\subsection{Protocol}
+
+{\bf Obby}
+
+This backend implements the obby protocol used by the Gobby
+collaborative editor until (including) version 4.9.
+
+\subsection{Session Initiation}
+
+{\bf Configured Sessions}
+
+Frequently used sessions can be configured permanently using the {\tt
+rudel-configured-sessions} customization variable. When there are
+configured sessions, connecting to one of these session is offered
+when joining a session using \kbd{\ccc j}.
+
+{\bf Zeroconf}
+
+The Zeroconf backends discovers collaboration sessions which are
+advertised using, well Zeroconf. Currently, it works for Rudel (obby
+backend) and Obby servers. When there are Zeroconf-advertised
+sessions, using \kbd{\ccc j} to join a session will display these
+sessions.
+
+\section{Examples}
+
+\subsection{Joining a Session with the obby backend}
+
+{\bf Without Zeroconf Discovery}
+
+\kbd{\ccc j}\hfil\break
+{\tt Server: }{\it SERVER} \kbd{RET}\hfil\break
+{\tt Port (default 6522): } \kbd{RET}\hfil\break
+{\tt Username: }{\it NAME} \kbd{RET}\hfil\break
+{\tt Color: }{\it COLOR} \kbd{RET}\hfil\break
+{\notefont (use bright colors like yellow)}\hfil\break
+{\it When connecting to a Rudel server:}\hfil\break
+-\hskip2ex {\tt Use Encryption (yes or no): }{\it NO} \kbd{RET}\hfil\break
+{\it When connecting to a Gobby server:}\hfil\break
+-\hskip2ex {\tt Use Encryption (yes or no): }{\it YES} \kbd{RET}\hfil\break
+{\tt Global Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\it This password controls access to the session; just \kbd{RET} for
+none}\hfil\break
+{\tt User Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\it This password prevents name stealing; just \kbd{RET} for
+none}\hfil\break
+
+{\bf With Zeroconf Discovery}
+
+\kbd{\ccc j}\hfil\break
+{\tt Choose Session: }Zeroconf advertised session {\it
+"NAME"}\kbd{RET}\hfil\break
+{\notefont (Note: by choosing "ask-protocol" here, you can still get the
+above behavior)}\hfil\break
+{\tt Username: }{\it NAME} \kbd{RET}\hfil\break
+{\tt Color: }{\it COLOR} \kbd{RET}\hfil\break
+{\tt Global Password: }{\it PASSWORD} \kbd{RET}\hfil\break
+{\tt User Password: }{\it PASSWORD} \kbd{RET}\hfil
+
+\copyrightnotice
+
+\bye
+
+% Local variables:
+% mode: plain-TeX; eval: (tex-pdf-mode);
+% End:
diff --git a/emacs.d/lisp/rudel/icons/.svn/all-wcprops b/emacs.d/lisp/rudel/icons/.svn/all-wcprops
new file mode 100644
index 0000000..74d10a4
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/all-wcprops
@@ -0,0 +1,41 @@
+K 25
+svn:wc:ra_dav:version-url
+V 39
+/svnroot/rudel/!svn/ver/271/trunk/icons
+END
+connected.svg
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svnroot/rudel/!svn/ver/271/trunk/icons/connected.svg
+END
+disconnected.svg
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svnroot/rudel/!svn/ver/271/trunk/icons/disconnected.svg
+END
+person.svg
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/271/trunk/icons/person.svg
+END
+plaintext.svg
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svnroot/rudel/!svn/ver/271/trunk/icons/plaintext.svg
+END
+encrypted.svg
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svnroot/rudel/!svn/ver/271/trunk/icons/encrypted.svg
+END
+document.svg
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/271/trunk/icons/document.svg
+END
diff --git a/emacs.d/lisp/rudel/icons/.svn/entries b/emacs.d/lisp/rudel/icons/.svn/entries
new file mode 100644
index 0000000..066c288
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/entries
@@ -0,0 +1,232 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/icons
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+connected.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+92dabaaee1e0a5aa817a2375f3123ff9
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+120859
+
+disconnected.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+36648b21e2242f6eab978ea2a92a21c7
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+125346
+
+person.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+677399e71aa07204caf1006847c274bf
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+17086
+
+plaintext.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+60734063eebaaa9e5278698aaf162270
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+20965
+
+encrypted.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+4f02b49c101291ffcce34950f135b3fe
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+33798
+
+document.svg
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+d1cba46d3ce1aa5ac2fc9fd04139b131
+2009-10-03T01:13:36.139341Z
+271
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+26034
+
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/connected.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/connected.svg.svn-base
new file mode 100644
index 0000000..3777037
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/connected.svg.svn-base
@@ -0,0 +1,2479 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2327"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/status"
+ sodipodi:docname="connected.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective287" />
+ <linearGradient
+ id="linearGradient7670">
+ <stop
+ style="stop-color:#3465a4;stop-opacity:1"
+ offset="0"
+ id="stop7672" />
+ <stop
+ style="stop-color:#204a87;stop-opacity:1"
+ offset="1"
+ id="stop7674" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2307">
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:1;"
+ offset="0"
+ id="stop2309" />
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:0;"
+ offset="1"
+ id="stop2311" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ id="stop11402"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11404"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6240"
+ inkscape:collect="always">
+ <stop
+ id="stop6242"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop6244"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ id="stop5139"
+ offset="0"
+ style="stop-color:#eeeeec;stop-opacity:1;" />
+ <stop
+ id="stop5141"
+ offset="1"
+ style="stop-color:#e6e6e3;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5225"
+ inkscape:collect="always">
+ <stop
+ id="stop5227"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop5229"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3899"
+ inkscape:collect="always">
+ <stop
+ id="stop3901"
+ offset="0"
+ style="stop-color:#eeeeec" />
+ <stop
+ id="stop3903"
+ offset="1"
+ style="stop-color:#d3d7cf" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3907">
+ <stop
+ id="stop3909"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3911"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4196">
+ <stop
+ id="stop4198"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop4200"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3304"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3302"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3300"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3298"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3296"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3294"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3292"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3276"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3274"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3272"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3270"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3268"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3266"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3264"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3155"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3158"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3161"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3164"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3167"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3170"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3173"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3176"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3182"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3185"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3188"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3191"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3194"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3197"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3200"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3203"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3206"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3209"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3212"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3215"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3218"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3221"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3224"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3230"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3233"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3236"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3239"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3242"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3245"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3248"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ gradientUnits="userSpaceOnUse"
+ y2="37.9375"
+ x2="29.125"
+ y1="46.029419"
+ x1="29.5"
+ id="linearGradient3905"
+ xlink:href="#linearGradient3899"
+ inkscape:collect="always" />
+ <radialGradient
+ r="117.14286"
+ fy="486.64789"
+ fx="605.71429"
+ cy="486.64789"
+ cx="605.71429"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2309"
+ xlink:href="#linearGradient5060"
+ inkscape:collect="always" />
+ <radialGradient
+ r="117.14286"
+ fy="486.64789"
+ fx="605.71429"
+ cy="486.64789"
+ cx="605.71429"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2311"
+ xlink:href="#linearGradient5060"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ gradientUnits="userSpaceOnUse"
+ y2="26.039215"
+ x2="20.156862"
+ y1="5.0996137"
+ x1="20.156862"
+ id="linearGradient6246"
+ xlink:href="#linearGradient6240"
+ inkscape:collect="always" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ r="19.00016"
+ fy="32.997028"
+ fx="24.006104"
+ cy="32.997028"
+ cx="24.006104"
+ id="radialGradient5239"
+ xlink:href="#linearGradient7670"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ y2="38.876041"
+ x2="39.904388"
+ y1="6.3760414"
+ x1="17.247635"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5147"
+ xlink:href="#linearGradient5137"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="43.82579"
+ x2="31.86105"
+ y1="37.842293"
+ x1="31.743324"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2308"
+ xlink:href="#linearGradient5137"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="40.219608"
+ x2="23.529411"
+ y1="34.572548"
+ x1="23.154902"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2310"
+ xlink:href="#linearGradient11400"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ gradientUnits="userSpaceOnUse"
+ y2="33.637787"
+ x2="37.295498"
+ y1="38.267769"
+ x1="37.484837"
+ id="linearGradient4202"
+ xlink:href="#linearGradient4196"
+ inkscape:collect="always" />
+ <radialGradient
+ r="23.75956"
+ fy="42.6875"
+ fx="23.9375"
+ cy="42.6875"
+ cx="23.9375"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2313"
+ xlink:href="#linearGradient5225"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5478"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient5620"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient5622"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5624"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient5626"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5628"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient5630"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient5632"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5634"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5636"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5638"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient5640"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5642"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5644"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5646"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5648"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5650"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5652"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5654"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5656"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5658"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5660"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5662"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5664"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5666"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5668"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5670"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5672"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5674"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5676"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5678"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5680"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5682"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5684"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5686"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5688"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5690"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5692"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5694"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5696"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5698"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5700"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5702"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5704"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5706"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5708"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5712"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5714"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5716"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5718"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5722"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5724"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5726"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5728"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666"
+ borderopacity="1"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="24.875"
+ inkscape:cx="0.95477387"
+ inkscape:cy="6"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false"
+ inkscape:grid-points="false"
+ showborder="true" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Network</dc:title>
+ <dc:date>2005-03-08</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:source />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner, Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(-1.1628734,-1.9999995)">
+ <g
+ id="g2660"
+ transform="matrix(0.3440228,0,0,0.3440228,0.8783092,2.0767243)">
+ <g
+ transform="translate(14.98536,1)"
+ id="g5480">
+ <g
+ id="g5482"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5484"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5486"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5488" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5490" />
+ </g>
+ <g
+ id="g5492"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient5620);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5494"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5496"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5622);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5498"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5500"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient5624);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5502"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5626);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5504"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5506"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5508"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5628);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5510"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5630);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5512"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5632);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5514"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5516"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5518">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5634);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5520"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient5636);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5522"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5524"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient5638);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5640);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5526"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5528"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5530"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5532"
+ style="fill:url(#radialGradient5642);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5534"
+ style="fill:url(#radialGradient5644);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5536"
+ style="fill:url(#radialGradient5646);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5538"
+ style="fill:url(#radialGradient5648);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5540"
+ style="fill:url(#radialGradient5650);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5542"
+ style="fill:url(#radialGradient5652);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5544"
+ style="fill:url(#radialGradient5654);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5546"
+ style="fill:url(#radialGradient5656);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5548"
+ style="fill:url(#radialGradient5658);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5550"
+ style="fill:url(#radialGradient5660);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5552"
+ style="fill:url(#radialGradient5662);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5554"
+ style="fill:url(#radialGradient5664);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5556"
+ style="fill:url(#radialGradient5666);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5558"
+ style="fill:url(#radialGradient5668);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5560"
+ style="fill:url(#radialGradient5670);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5562"
+ style="fill:url(#radialGradient5672);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5564"
+ style="fill:url(#radialGradient5674);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5566"
+ style="fill:url(#radialGradient5676);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5568"
+ style="fill:url(#radialGradient5678);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5570"
+ style="fill:url(#radialGradient5680);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5572"
+ style="fill:url(#radialGradient5682);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5574"
+ style="fill:url(#radialGradient5684);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5576"
+ style="fill:url(#radialGradient5686);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5578"
+ style="fill:url(#radialGradient5688);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5580"
+ style="fill:url(#radialGradient5690);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5582"
+ style="fill:url(#radialGradient5692);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5584"
+ style="fill:url(#radialGradient5694);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5586"
+ style="fill:url(#radialGradient5696);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5588"
+ style="fill:url(#radialGradient5698);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5590"
+ style="fill:url(#radialGradient5700);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5592"
+ style="fill:url(#radialGradient5702);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5594"
+ style="fill:url(#radialGradient5704);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5596"
+ style="fill:url(#radialGradient5706);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5598"
+ style="fill:url(#radialGradient5708);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5600"
+ style="fill:url(#radialGradient5710);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5602"
+ style="fill:url(#radialGradient5712);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5604"
+ style="fill:url(#radialGradient5714);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5606"
+ style="fill:url(#radialGradient5716);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5608"
+ style="fill:url(#radialGradient5718);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5610"
+ style="fill:url(#radialGradient5720);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5612"
+ style="fill:url(#radialGradient5722);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5614"
+ style="fill:url(#radialGradient5724);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5616"
+ style="fill:url(#radialGradient5726);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5618"
+ style="fill:url(#radialGradient5728);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ transform="translate(0.985355,12)"
+ id="g5340">
+ <g
+ id="g5342"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5344"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5346"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5348" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5350" />
+ </g>
+ <g
+ id="layer2"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient2313);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5353"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5355"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4202);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5357"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5359"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient2308);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5361"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient2310);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5363"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5365"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5367"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5147);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5369"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5239);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5371"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient6246);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5373"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5375"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5377">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5478);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect6709"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient2309);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5380"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5382"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient2311);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient3905);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5384"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5386"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5388"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5390"
+ style="fill:url(#radialGradient3248);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5392"
+ style="fill:url(#radialGradient3245);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5394"
+ style="fill:url(#radialGradient3242);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5396"
+ style="fill:url(#radialGradient3239);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5398"
+ style="fill:url(#radialGradient3236);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5400"
+ style="fill:url(#radialGradient3233);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5402"
+ style="fill:url(#radialGradient3230);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5404"
+ style="fill:url(#radialGradient3224);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5406"
+ style="fill:url(#radialGradient3221);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5408"
+ style="fill:url(#radialGradient3218);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5410"
+ style="fill:url(#radialGradient3215);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5412"
+ style="fill:url(#radialGradient3212);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5414"
+ style="fill:url(#radialGradient3209);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5416"
+ style="fill:url(#radialGradient3206);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5418"
+ style="fill:url(#radialGradient3203);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5420"
+ style="fill:url(#radialGradient3200);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5422"
+ style="fill:url(#radialGradient3197);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5424"
+ style="fill:url(#radialGradient3194);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5426"
+ style="fill:url(#radialGradient3191);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5428"
+ style="fill:url(#radialGradient3188);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5430"
+ style="fill:url(#radialGradient3185);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5432"
+ style="fill:url(#radialGradient3182);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5434"
+ style="fill:url(#radialGradient3176);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5436"
+ style="fill:url(#radialGradient3173);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5438"
+ style="fill:url(#radialGradient3170);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5440"
+ style="fill:url(#radialGradient3167);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5442"
+ style="fill:url(#radialGradient3164);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5444"
+ style="fill:url(#radialGradient3161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5446"
+ style="fill:url(#radialGradient3158);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5448"
+ style="fill:url(#radialGradient3155);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5450"
+ style="fill:url(#radialGradient3264);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5452"
+ style="fill:url(#radialGradient3266);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5454"
+ style="fill:url(#radialGradient3268);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5456"
+ style="fill:url(#radialGradient3270);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5458"
+ style="fill:url(#radialGradient3272);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5460"
+ style="fill:url(#radialGradient3274);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5462"
+ style="fill:url(#radialGradient3276);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5464"
+ style="fill:url(#radialGradient3292);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5466"
+ style="fill:url(#radialGradient3294);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5468"
+ style="fill:url(#radialGradient3296);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5470"
+ style="fill:url(#radialGradient3298);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5472"
+ style="fill:url(#radialGradient3300);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5474"
+ style="fill:url(#radialGradient3302);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5476"
+ style="fill:url(#radialGradient3304);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/disconnected.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/disconnected.svg.svn-base
new file mode 100644
index 0000000..5a8de65
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/disconnected.svg.svn-base
@@ -0,0 +1,2600 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2327"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/status"
+ sodipodi:docname="disconnected.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective4721" />
+ <linearGradient
+ id="linearGradient5180">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop5182" />
+ <stop
+ id="stop5188"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5184" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5166">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5168" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5170" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient7670">
+ <stop
+ style="stop-color:#3465a4;stop-opacity:1"
+ offset="0"
+ id="stop7672" />
+ <stop
+ style="stop-color:#204a87;stop-opacity:1"
+ offset="1"
+ id="stop7674" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2307">
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:1;"
+ offset="0"
+ id="stop2309" />
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:0;"
+ offset="1"
+ id="stop2311" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ id="stop11402"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11404"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6240"
+ inkscape:collect="always">
+ <stop
+ id="stop6242"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop6244"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ id="stop5139"
+ offset="0"
+ style="stop-color:#eeeeec;stop-opacity:1;" />
+ <stop
+ id="stop5141"
+ offset="1"
+ style="stop-color:#e6e6e3;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5225"
+ inkscape:collect="always">
+ <stop
+ id="stop5227"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop5229"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3899"
+ inkscape:collect="always">
+ <stop
+ id="stop3901"
+ offset="0"
+ style="stop-color:#eeeeec" />
+ <stop
+ id="stop3903"
+ offset="1"
+ style="stop-color:#d3d7cf" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3907">
+ <stop
+ id="stop3909"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3911"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4196">
+ <stop
+ id="stop4198"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop4200"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient4875"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient4877"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4879"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient4881"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4883"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient4885"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient4887"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient4889"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient4891"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient4893"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient4895"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4897"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4899"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4901"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4903"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4905"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4907"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4909"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4911"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4913"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4915"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4917"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4919"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4921"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4923"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4925"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4927"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4929"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4931"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4933"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4939"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4941"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4943"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4945"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4947"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4949"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4951"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4953"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4955"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4957"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4959"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4961"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4963"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4965"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4967"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4969"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4971"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4973"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4975"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4977"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4979"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4981"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4983"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5166"
+ id="radialGradient4985"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.465649,0,0,1.221374,-3.36641,-10.07252)"
+ cx="33"
+ cy="45.5"
+ fx="33"
+ fy="45.5"
+ r="2.046875" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5166"
+ id="radialGradient4987"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.465649,0,0,1.221374,-84.36641,-101.0725)"
+ cx="33"
+ cy="45.5"
+ fx="33"
+ fy="45.5"
+ r="2.046875" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5180"
+ id="linearGradient4989"
+ gradientUnits="userSpaceOnUse"
+ x1="39"
+ y1="48.000099"
+ x2="39"
+ y2="43" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient4991"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient4993"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4995"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient4997"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4999"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient5001"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient5003"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5005"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5007"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5009"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient5011"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5013"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5015"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5017"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5019"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5021"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5023"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5025"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5027"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5029"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5031"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5033"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5035"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5037"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5039"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5041"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5043"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5045"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5047"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5049"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5051"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5053"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5055"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5057"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5059"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5061"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5063"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5065"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5067"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5069"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5071"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5073"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5075"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5077"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5079"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5081"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5083"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5085"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5087"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5089"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5091"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5093"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5095"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5097"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5099"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666"
+ borderopacity="1"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.383922"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false"
+ inkscape:grid-points="false"
+ showborder="true" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Network Offline</dc:title>
+ <dc:date>2005-03-08</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:source />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner, Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g4723"
+ transform="matrix(0.3375412,0,0,0.3375412,-0.2972476,-0.4385299)">
+ <g
+ transform="translate(14.98536,1)"
+ id="g5480">
+ <g
+ id="g5482"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5484"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5486"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5488" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5490" />
+ </g>
+ <g
+ id="g5492"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient4875);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5494"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5496"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4877);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5498"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5500"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient4879);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5502"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4881);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5504"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5506"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5508"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4883);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5510"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient4885);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5512"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4887);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5514"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5516"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5518">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient4889);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5520"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient4891);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5522"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5524"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient4893);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4895);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5526"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5528"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5530"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5532"
+ style="fill:url(#radialGradient4897);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5534"
+ style="fill:url(#radialGradient4899);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5536"
+ style="fill:url(#radialGradient4901);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5538"
+ style="fill:url(#radialGradient4903);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5540"
+ style="fill:url(#radialGradient4905);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5542"
+ style="fill:url(#radialGradient4907);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5544"
+ style="fill:url(#radialGradient4909);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5546"
+ style="fill:url(#radialGradient4911);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5548"
+ style="fill:url(#radialGradient4913);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5550"
+ style="fill:url(#radialGradient4915);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5552"
+ style="fill:url(#radialGradient4917);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5554"
+ style="fill:url(#radialGradient4919);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5556"
+ style="fill:url(#radialGradient4921);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5558"
+ style="fill:url(#radialGradient4923);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5560"
+ style="fill:url(#radialGradient4925);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5562"
+ style="fill:url(#radialGradient4927);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5564"
+ style="fill:url(#radialGradient4929);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5566"
+ style="fill:url(#radialGradient4931);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5568"
+ style="fill:url(#radialGradient4933);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5570"
+ style="fill:url(#radialGradient4935);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5572"
+ style="fill:url(#radialGradient4937);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5574"
+ style="fill:url(#radialGradient4939);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5576"
+ style="fill:url(#radialGradient4941);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5578"
+ style="fill:url(#radialGradient4943);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5580"
+ style="fill:url(#radialGradient4945);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5582"
+ style="fill:url(#radialGradient4947);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5584"
+ style="fill:url(#radialGradient4949);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5586"
+ style="fill:url(#radialGradient4951);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5588"
+ style="fill:url(#radialGradient4953);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5590"
+ style="fill:url(#radialGradient4955);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5592"
+ style="fill:url(#radialGradient4957);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5594"
+ style="fill:url(#radialGradient4959);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5596"
+ style="fill:url(#radialGradient4961);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5598"
+ style="fill:url(#radialGradient4963);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5600"
+ style="fill:url(#radialGradient4965);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5602"
+ style="fill:url(#radialGradient4967);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5604"
+ style="fill:url(#radialGradient4969);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5606"
+ style="fill:url(#radialGradient4971);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5608"
+ style="fill:url(#radialGradient4973);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5610"
+ style="fill:url(#radialGradient4975);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5612"
+ style="fill:url(#radialGradient4977);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5614"
+ style="fill:url(#radialGradient4979);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5616"
+ style="fill:url(#radialGradient4981);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5618"
+ style="fill:url(#radialGradient4983);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ style="opacity:0.6"
+ id="g5190">
+ <rect
+ style="opacity:1;fill:url(#radialGradient4985);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect4279"
+ width="3"
+ height="5"
+ x="45"
+ y="43" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient4987);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect5174"
+ width="3"
+ height="5"
+ x="-36"
+ y="-48"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient4989);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect5178"
+ width="9"
+ height="5"
+ x="36"
+ y="43" />
+ </g>
+ <g
+ transform="translate(0.985355,12)"
+ id="g5340">
+ <g
+ id="g5342"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5344"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5346"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5348" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5350" />
+ </g>
+ <g
+ id="layer2"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient4991);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5353"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5355"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4993);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5357"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5359"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient4995);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5361"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4997);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5363"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5365"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5367"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4999);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5369"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5001);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5371"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5003);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5373"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5375"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5377">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5005);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect6709"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient5007);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5380"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5382"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient5009);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5011);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5384"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5386"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5388"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5390"
+ style="fill:url(#radialGradient5013);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5392"
+ style="fill:url(#radialGradient5015);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5394"
+ style="fill:url(#radialGradient5017);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5396"
+ style="fill:url(#radialGradient5019);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5398"
+ style="fill:url(#radialGradient5021);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5400"
+ style="fill:url(#radialGradient5023);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5402"
+ style="fill:url(#radialGradient5025);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5404"
+ style="fill:url(#radialGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5406"
+ style="fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5408"
+ style="fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5410"
+ style="fill:url(#radialGradient5033);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5412"
+ style="fill:url(#radialGradient5035);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5414"
+ style="fill:url(#radialGradient5037);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5416"
+ style="fill:url(#radialGradient5039);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5418"
+ style="fill:url(#radialGradient5041);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5420"
+ style="fill:url(#radialGradient5043);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5422"
+ style="fill:url(#radialGradient5045);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5424"
+ style="fill:url(#radialGradient5047);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5426"
+ style="fill:url(#radialGradient5049);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5428"
+ style="fill:url(#radialGradient5051);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5430"
+ style="fill:url(#radialGradient5053);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5432"
+ style="fill:url(#radialGradient5055);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5434"
+ style="fill:url(#radialGradient5057);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5436"
+ style="fill:url(#radialGradient5059);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5438"
+ style="fill:url(#radialGradient5061);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5440"
+ style="fill:url(#radialGradient5063);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5442"
+ style="fill:url(#radialGradient5065);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5444"
+ style="fill:url(#radialGradient5067);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5446"
+ style="fill:url(#radialGradient5069);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5448"
+ style="fill:url(#radialGradient5071);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5450"
+ style="fill:url(#radialGradient5073);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5452"
+ style="fill:url(#radialGradient5075);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5454"
+ style="fill:url(#radialGradient5077);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5456"
+ style="fill:url(#radialGradient5079);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5458"
+ style="fill:url(#radialGradient5081);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5460"
+ style="fill:url(#radialGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5462"
+ style="fill:url(#radialGradient5085);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5464"
+ style="fill:url(#radialGradient5087);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5466"
+ style="fill:url(#radialGradient5089);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5468"
+ style="fill:url(#radialGradient5091);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5470"
+ style="fill:url(#radialGradient5093);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5472"
+ style="fill:url(#radialGradient5095);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5474"
+ style="fill:url(#radialGradient5097);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5476"
+ style="fill:url(#radialGradient5099);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ transform="translate(5,18)"
+ style="display:inline"
+ inkscape:label="Muted"
+ id="layer4">
+ <g
+ transform="translate(-2,0)"
+ id="g4694">
+ <rect
+ style="opacity:1;fill:#ef2929;fill-opacity:1;stroke:#cc0000;stroke-width:0.9964897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;display:inline"
+ id="rect2021"
+ width="12.00351"
+ height="12.00351"
+ x="31.498245"
+ y="16.498245"
+ rx="1.4868355"
+ ry="1.4868355" />
+ <rect
+ style="opacity:0.3;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;display:inline"
+ id="rect3795"
+ width="9.9999962"
+ height="9.9999962"
+ x="32.5"
+ y="17.500002"
+ rx="0.4861359"
+ ry="0.4861359" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 35,20 L 40,25"
+ id="path4682"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 40,20 L 35,25"
+ id="path4684"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/document.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/document.svg.svn-base
new file mode 100644
index 0000000..aa5163c
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/document.svg.svn-base
@@ -0,0 +1,608 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="240.00000"
+ inkscape:export-xdpi="240.00000"
+ inkscape:export-filename="/home/lapo/text.png"
+ sodipodi:docname="document.svg"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/mimetypes"
+ inkscape:version="0.46"
+ sodipodi:version="0.32"
+ id="svg249"
+ height="16"
+ width="16"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 8 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="16 : 8 : 1"
+ inkscape:persp3d-origin="8 : 5.3333333 : 1"
+ id="perspective80" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3656"
+ id="linearGradient5816"
+ gradientUnits="userSpaceOnUse"
+ x1="-26.753757"
+ y1="11.566258"
+ x2="-24.75"
+ y2="9.687501" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3520"
+ id="linearGradient5836"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9223058,0,0,0.9185751,-92.447368,61.3257)"
+ x1="-18.588562"
+ y1="11.052948"
+ x2="-28.789402"
+ y2="14.069944" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3671"
+ id="radialGradient5839"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.4073362,-0.2798276,0.7510293,1.0932492,-115.18484,51.56213)"
+ cx="-26.305403"
+ cy="10.108011"
+ fx="-26.305403"
+ fy="10.108011"
+ r="7.0421038" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6469">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop6471" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop6473" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6469"
+ id="linearGradient6475"
+ x1="58.282169"
+ y1="70.751839"
+ x2="61.181217"
+ y2="67.799171"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-180,0)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3741"
+ id="radialGradient5810"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8860258,0,0,1.1764706,-3.5441033,-4.2352941)"
+ cx="4"
+ cy="5.2999997"
+ fx="4"
+ fy="5.2999997"
+ r="17" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3613"
+ id="linearGradient5845"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-90,60)"
+ x1="-47.5"
+ y1="49.020683"
+ x2="-62.75"
+ y2="-22.502075" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3683"
+ id="radialGradient5843"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.9957492,0,0,1.9350367,0.62141,28.832578)"
+ cx="-30.249996"
+ cy="35.357208"
+ fx="-30.249996"
+ fy="35.357208"
+ r="18.000002" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3702"
+ id="linearGradient5804"
+ gradientUnits="userSpaceOnUse"
+ x1="25.058096"
+ y1="47.027729"
+ x2="25.058096"
+ y2="39.999443" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5802"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5800"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3702"
+ id="linearGradient5798"
+ gradientUnits="userSpaceOnUse"
+ x1="25.058096"
+ y1="47.027729"
+ x2="25.058096"
+ y2="39.999443" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5796"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5794"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3656">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3658" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3660" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3520">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.41295547"
+ offset="0"
+ id="stop3522" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3671">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3673" />
+ <stop
+ id="stop3691"
+ offset="0.47533694"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3675" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3741">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3743" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3745" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3613">
+ <stop
+ style="stop-color:#888a85;stop-opacity:1"
+ offset="0"
+ id="stop3615" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3617" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3683">
+ <stop
+ id="stop3685"
+ offset="0"
+ style="stop-color:#f6f6f5;stop-opacity:1;" />
+ <stop
+ id="stop3689"
+ offset="1"
+ style="stop-color:#d3d7cf;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3688"
+ inkscape:collect="always">
+ <stop
+ id="stop3690"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop3692"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3702">
+ <stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" />
+ <stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ inkscape:window-y="125"
+ inkscape:window-x="60"
+ inkscape:window-height="872"
+ inkscape:window-width="1048"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ showgrid="false"
+ inkscape:current-layer="layer6"
+ inkscape:cy="6.5182375"
+ inkscape:cx="1.1981567"
+ inkscape:zoom="27.125"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="0.25490196"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Generic Text</dc:title>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>text</rdf:li>
+ <rdf:li>plaintext</rdf:li>
+ <rdf:li>regular</rdf:li>
+ <rdf:li>document</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source />
+ <dc:date />
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:publisher>
+ <dc:identifier />
+ <dc:relation />
+ <dc:language />
+ <dc:coverage />
+ <dc:description />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="Shadow">
+ <g
+ style="display:inline"
+ id="g6015"
+ transform="matrix(0.3302612,0,0,0.3302612,49.612911,-19.741941)">
+ <rect
+ y="60"
+ x="-150"
+ height="48"
+ width="48"
+ id="rect5504"
+ style="opacity:0;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;display:inline" />
+ <g
+ transform="matrix(1.0464281,0,0,0.8888889,-151.18572,65.72224)"
+ inkscape:label="Shadow"
+ id="g5508"
+ style="opacity:0.65587045;display:inline">
+ <g
+ transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)"
+ style="opacity:0.4"
+ id="g5511">
+ <rect
+ style="opacity:1;fill:url(#radialGradient5794);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5513"
+ width="5"
+ height="7"
+ x="38"
+ y="40" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient5796);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5515"
+ width="5"
+ height="7"
+ x="-10"
+ y="-47"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient5798);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5517"
+ width="28"
+ height="7.0000005"
+ x="10"
+ y="40" />
+ </g>
+ </g>
+ <g
+ transform="matrix(0.9548466,0,0,0.5555562,-148.98776,79.888875)"
+ inkscape:label="Shadow"
+ id="g5519"
+ style="display:inline">
+ <g
+ transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)"
+ style="opacity:0.4"
+ id="g5521">
+ <rect
+ style="opacity:1;fill:url(#radialGradient5800);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5523"
+ width="5"
+ height="7"
+ x="38"
+ y="40" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient5802);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5525"
+ width="5"
+ height="7"
+ x="-10"
+ y="-47"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient5804);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5527"
+ width="28"
+ height="7.0000005"
+ x="10"
+ y="40" />
+ </g>
+ </g>
+ <path
+ sodipodi:nodetypes="ccsccccccc"
+ id="path5529"
+ d="M -141.47614,63.5 C -141.47614,63.5 -124,63.5 -122.5,63.5 C -118.62295,63.572942 -116,66 -113.5,68.5 C -111,71 -108.89232,73.752625 -108.5,77.5 C -108.5,79 -108.5,102.47614 -108.5,102.47614 C -108.5,103.59736 -109.40264,104.5 -110.52385,104.5 L -141.47614,104.5 C -142.59736,104.5 -143.5,103.59736 -143.5,102.47614 L -143.5,65.523858 C -143.5,64.402641 -142.59736,63.5 -141.47614,63.5 z"
+ style="fill:url(#radialGradient5843);fill-opacity:1;stroke:url(#linearGradient5845);stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ transform="translate(-150,60)"
+ d="M 8.53125,4 C 7.6730803,4 7,4.6730802 7,5.53125 L 7,42.46875 C 7,43.32692 7.6730802,44 8.53125,44 L 39.46875,44 C 40.326919,44 41,43.326918 41,42.46875 C 41,42.46875 41,19 41,17.5 C 41,16.10803 40.513021,13.200521 38.65625,11.34375 C 36.65625,9.34375 35.65625,8.34375 33.65625,6.34375 C 31.799479,4.4869792 28.89197,4 27.5,4 C 26,4 8.53125,4 8.53125,4 z"
+ id="path5531"
+ style="opacity:0.68016196;fill:url(#radialGradient5810);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline"
+ inkscape:original="M 8.53125 3.5 C 7.410033 3.5 6.5 4.4100329 6.5 5.53125 L 6.5 42.46875 C 6.5 43.589967 7.4100329 44.5 8.53125 44.5 L 39.46875 44.5 C 40.589967 44.5 41.5 43.589966 41.5 42.46875 C 41.5 42.46875 41.5 19 41.5 17.5 C 41.5 16 41 13 39 11 C 37 9 36 8 34 6 C 32 4 29 3.5 27.5 3.5 C 26 3.5 8.5312499 3.5 8.53125 3.5 z "
+ inkscape:radius="-0.4861359"
+ sodipodi:type="inkscape:offset" />
+ <path
+ id="rect5857"
+ d="M -138.59375,69.125 C -138.81243,69.125 -139,69.312565 -139,69.53125 C -139,69.749934 -138.81243,69.937499 -138.59375,69.9375 L -117.40625,69.9375 C -117.18757,69.9375 -117,69.749934 -117,69.53125 C -117,69.312566 -117.18757,69.125 -117.40625,69.125 L -138.59375,69.125 z M -138.53125,71.0625 C -138.79094,71.0625 -139,71.271563 -139,71.53125 C -139,71.790937 -138.79094,72 -138.53125,72 L -116.46875,72 C -116.20906,72 -116,71.790937 -116,71.53125 C -116,71.271563 -116.20906,71.0625 -116.46875,71.0625 L -138.53125,71.0625 z M -138.53125,73.0625 C -138.79094,73.0625 -139,73.271563 -139,73.53125 C -139,73.790937 -138.79094,74 -138.53125,74 L -113.34375,74 C -113.08406,74 -112.875,73.790937 -112.875,73.53125 C -112.875,73.271563 -113.08406,73.0625 -113.34375,73.0625 L -138.53125,73.0625 z M -138.53125,75.0625 C -138.79094,75.0625 -139,75.271563 -139,75.53125 C -139,75.790937 -138.79094,76 -138.53125,76 L -113.34375,76 C -113.08406,76 -112.875,75.790937 -112.875,75.53125 C -112.875,75.271563 -113.08406,75.0625 -113.34375,75.0625 L -138.53125,75.0625 z M -138.53125,77.0625 C -138.79094,77.0625 -139,77.271563 -139,77.53125 C -139,77.790937 -138.79094,78 -138.53125,78 L -113.34375,78 C -113.08406,78 -112.875,77.790937 -112.875,77.53125 C -112.875,77.271563 -113.08406,77.0625 -113.34375,77.0625 L -138.53125,77.0625 z"
+ style="opacity:0.15;fill:url(#linearGradient6475);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ sodipodi:nodetypes="ccccczc"
+ id="path5533"
+ d="M -122.5,64 C -123.88889,64 -122.54207,64.497088 -121.15625,65.125 C -119.77043,65.752912 -116.18337,68.340052 -117,72 C -112.67669,71.569417 -110.32087,75.122378 -110,76.28125 C -109.67913,77.440122 -109,78.888889 -109,77.5 C -108.97167,73.694419 -111.84543,71.068299 -113.84375,68.84375 C -115.84207,66.619201 -118.84621,64.476761 -122.5,64 z"
+ style="fill:url(#radialGradient5839);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path5535"
+ d="M -121.39912,65.014353 C -120.47682,65.014353 -118.39068,71.210015 -119.31298,75.343603 C -115.01802,74.915844 -110.4596,75.43178 -110,76.28125 C -110.32087,75.122378 -112.67669,71.569417 -117,72 C -116.13534,68.124761 -120.18657,65.382702 -121.39912,65.014353 z"
+ style="opacity:0.87854249;fill:url(#linearGradient5836);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ transform="translate(-90,60)"
+ d="M -51.46875,4.5 C -52.051916,4.5 -52.5,4.9480842 -52.5,5.53125 L -52.5,42.46875 C -52.5,43.051915 -52.051914,43.5 -51.46875,43.5 L -20.53125,43.5 C -19.948085,43.5 -19.5,43.051914 -19.5,42.46875 C -19.5,42.46875 -19.5,19 -19.5,17.5 C -19.5,16.220971 -19.980469,13.394531 -21.6875,11.6875 C -23.6875,9.6875 -24.6875,8.6875 -26.6875,6.6875 C -28.394531,4.9804687 -31.220971,4.5 -32.5,4.5 C -34,4.5 -51.46875,4.5 -51.46875,4.5 z"
+ id="path5537"
+ style="fill:none;fill-opacity:1;stroke:url(#linearGradient5816);stroke-width:1;stroke-miterlimit:4;display:inline"
+ inkscape:original="M -51.46875 3.5 C -52.589967 3.5 -53.5 4.4100329 -53.5 5.53125 L -53.5 42.46875 C -53.5 43.589967 -52.589966 44.5 -51.46875 44.5 L -20.53125 44.5 C -19.410033 44.5 -18.5 43.589966 -18.5 42.46875 C -18.5 42.46875 -18.5 19 -18.5 17.5 C -18.5 16 -19 13 -21 11 C -23 9 -24 8 -26 6 C -28 4 -31 3.5 -32.5 3.5 C -34 3.5 -51.468749 3.5 -51.46875 3.5 z "
+ inkscape:radius="-0.99436891"
+ sodipodi:type="inkscape:offset" />
+ <g
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ transform="matrix(0.928889,0,0,1,-148.28889,60)"
+ style="opacity:0.15;fill:#000000;display:inline"
+ id="g5539">
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="19.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5549"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5553"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="21.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5555"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="23.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="25.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5557"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="27.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5559"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5561"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="29.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5563"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="31.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="33.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5565"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="35.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5567"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="37.0625"
+ x="10"
+ height="0.9375"
+ width="13.8125"
+ id="rect5569"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ </g>
+ <g
+ style="display:inline"
+ inkscape:groupmode="layer"
+ inkscape:label="Base"
+ id="layer1" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="Text"
+ style="display:inline" />
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/encrypted.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/encrypted.svg.svn-base
new file mode 100644
index 0000000..8c32cc6
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/encrypted.svg.svn-base
@@ -0,0 +1,902 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg12360"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/data/Desktop/icons/scaleable"
+ sodipodi:docname="encrypted.svg"
+ inkscape:export-filename="/data/Desktop/icons/scaleable/seahorse-applet-encrypted.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs12362">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective3757" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2259">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2261" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2263" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2251">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2253" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2255" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2239">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2241" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2243" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2224">
+ <stop
+ style="stop-color:#7c7c7c;stop-opacity:1;"
+ offset="0"
+ id="stop2226" />
+ <stop
+ style="stop-color:#b8b8b8;stop-opacity:1;"
+ offset="1"
+ id="stop2228" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2216">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2218" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2220" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15234">
+ <stop
+ style="stop-color:#97978a;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15236" />
+ <stop
+ id="stop15242"
+ offset="0.50000000"
+ style="stop-color:#c2c2b9;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#7d7d6f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15238" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15218">
+ <stop
+ style="stop-color:#f0f0ef;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15220" />
+ <stop
+ id="stop2269"
+ offset="0.59928656"
+ style="stop-color:#e8e8e8;stop-opacity:1;" />
+ <stop
+ id="stop2267"
+ offset="0.82758623"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d8d8d3;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15222" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14484">
+ <stop
+ style="stop-color:#c68827;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop14486" />
+ <stop
+ style="stop-color:#89601f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop14488" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient13746">
+ <stop
+ style="stop-color:#646459;stop-opacity:1;"
+ offset="0"
+ id="stop13748" />
+ <stop
+ style="stop-color:#646459;stop-opacity:0;"
+ offset="1"
+ id="stop13750" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient13746"
+ id="radialGradient13752"
+ cx="24.647722"
+ cy="45.272587"
+ fx="24.647722"
+ fy="45.272587"
+ r="21.011173"
+ gradientTransform="matrix(1,0,0,0.110577,0,40.26648)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14484"
+ id="linearGradient14490"
+ x1="6.1071744"
+ y1="10.45129"
+ x2="33.857143"
+ y2="37.87986"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15218"
+ id="linearGradient15224"
+ x1="22.308331"
+ y1="18.99214"
+ x2="35.785294"
+ y2="39.498238"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.065698,0,0,0.987595,-1.564439,7.487332e-2)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient15240"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.052632,0,0,1,-1.789474,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2216"
+ id="linearGradient2222"
+ x1="36.8125"
+ y1="39.15625"
+ x2="39.0625"
+ y2="42.0625"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2224"
+ id="linearGradient2230"
+ x1="35.996582"
+ y1="40.458221"
+ x2="33.664921"
+ y2="37.770721"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient2245"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2251"
+ id="linearGradient2257"
+ x1="33.396004"
+ y1="36.921333"
+ x2="34.170048"
+ y2="38.070381"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2259"
+ id="linearGradient2265"
+ x1="26.076092"
+ y1="26.696676"
+ x2="30.811172"
+ y2="42.007351"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient2283"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.538743,0,0,0.511806,10.8008,-0.58264)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.404572"
+ y2="6.481061" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient2287"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.005222,0,0,0.883928,-0.627923,0.84375)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ y2="14.259961"
+ x2="11.779029"
+ y1="20.579729"
+ x1="11.5"
+ gradientTransform="matrix(0.980472,0,0,0.490236,34.67523,22.83397)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1898"
+ xlink:href="#linearGradient12071"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="3.9566603"
+ x2="17.859085"
+ y1="6.8795347"
+ x1="14.217941"
+ gradientTransform="matrix(0.980472,0,0,0.461806,23.89003,23.47875)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1896"
+ xlink:href="#linearGradient12071"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="36.127281"
+ x2="30.875446"
+ y1="25.002281"
+ x1="10.907269"
+ gradientTransform="matrix(0.453445,0,0,0.470026,30.17248,24.3894)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1894"
+ xlink:href="#linearGradient9845"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="25.793524"
+ x2="8.6713638"
+ y1="41.791817"
+ x1="31.630468"
+ gradientTransform="matrix(0.490236,0,0,0.534297,29.28263,22.22637)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1892"
+ xlink:href="#linearGradient11327"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="32.161697"
+ x2="40.938126"
+ y1="32.161697"
+ x1="6.72682"
+ gradientTransform="matrix(0.490236,0,0,0.534297,29.28263,21.67589)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1890"
+ xlink:href="#linearGradient2092"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="6.0396547"
+ x2="16.198252"
+ y1="9.6635771"
+ x1="19.250618"
+ gradientTransform="matrix(0.480246,0,0,0.497322,29.22711,23.01153)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1888"
+ xlink:href="#linearGradient11335"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="18.414022"
+ x2="20.087339"
+ y1="4.3602757"
+ x1="12.88666"
+ gradientTransform="matrix(0.480246,0,0,0.497322,29.22711,23.01153)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1886"
+ xlink:href="#linearGradient10591"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2329"
+ id="linearGradient2337"
+ x1="-35.122688"
+ y1="34.242237"
+ x2="-35.074745"
+ y2="30.962345"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2321"
+ id="linearGradient2327"
+ x1="-35.658386"
+ y1="33.416473"
+ x2="-35.658386"
+ y2="28.205938"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2253"
+ id="linearGradient1561"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.104397,0,0,0.905471,4.5,2.875)"
+ x1="10.390738"
+ y1="5.3817744"
+ x2="32.536823"
+ y2="31.246054" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2733"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2729"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2725"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2721"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2717"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2701"
+ id="linearGradient2707"
+ gradientTransform="matrix(1.816345,0,0,1.278927,2.5,-40.24508)"
+ x1="12.206709"
+ y1="53.535141"
+ x2="12.127711"
+ y2="64.892525"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2683"
+ id="linearGradient2689"
+ gradientTransform="matrix(5.705159,0,0,0.17528,5.5,2.195627)"
+ x1="3.7069976"
+ y1="171.29134"
+ x2="3.7069974"
+ y2="162.45061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2675"
+ id="linearGradient2681"
+ gradientTransform="matrix(1.174139,0,0,0.945431,5.221825,1.543476)"
+ x1="19.150396"
+ y1="32.622238"
+ x2="16.315819"
+ y2="8.8666229"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2667"
+ id="linearGradient2673"
+ gradientTransform="matrix(1.238977,0,0,0.895955,5.090553,1.543476)"
+ x1="11.492236"
+ y1="1.6537577"
+ x2="17.199417"
+ y2="26.729263"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ r="8.7662792"
+ fy="67.501709"
+ fx="12.57571"
+ cy="67.501709"
+ cx="12.57571"
+ gradientTransform="scale(1.925808,0.519262)"
+ id="radialGradient2460"
+ xlink:href="#linearGradient2454"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="55.200756"
+ x2="34.974548"
+ y1="13.004725"
+ x1="17.698339"
+ gradientTransform="matrix(1.108069,0,0,0.902471,5.5,3.875)"
+ id="linearGradient2421"
+ xlink:href="#linearGradient2415"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="33.339787"
+ x2="34.784473"
+ y1="7.2293582"
+ x1="8.6116238"
+ gradientTransform="matrix(1.129863,0,0,0.885063,2.875,1.570628)"
+ id="linearGradient1506"
+ xlink:href="#linearGradient2245"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient1502">
+ <stop
+ id="stop2247"
+ offset="0.0000000"
+ style="stop-color:#dde1d9;stop-opacity:1.0000000;" />
+ <stop
+ id="stop2249"
+ offset="1.0000000"
+ style="stop-color:#cacdc6;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2253">
+ <stop
+ id="stop1499"
+ offset="0.0000000"
+ style="stop-color:#8f8f8f;stop-opacity:1.0000000;" />
+ <stop
+ id="stop2257"
+ offset="1.0000000"
+ style="stop-color:#494949;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2415"
+ inkscape:collect="always">
+ <stop
+ id="stop2417"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop2419"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2454"
+ inkscape:collect="always">
+ <stop
+ id="stop2456"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop2458"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2667">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2669" />
+ <stop
+ style="stop-color:#fcfcff;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2671" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2675">
+ <stop
+ style="stop-color:#5b5b97;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2677" />
+ <stop
+ style="stop-color:#1b1b43;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2679" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2683">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2685" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2687" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2701">
+ <stop
+ style="stop-color:#585956;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2703" />
+ <stop
+ style="stop-color:#bbbeb8;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2705" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2711">
+ <stop
+ style="stop-color:#909090;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2713" />
+ <stop
+ style="stop-color:#bebebe;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2715" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2321">
+ <stop
+ style="stop-color:#7b7f7a;stop-opacity:1;"
+ offset="0"
+ id="stop2323" />
+ <stop
+ style="stop-color:#7b7f7a;stop-opacity:0;"
+ offset="1"
+ id="stop2325" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2329">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2331" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2333" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10591">
+ <stop
+ id="stop10593"
+ offset="0.0000000"
+ style="stop-color:#cad0c6;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#eaece9;stop-opacity:1.0000000;"
+ offset="0.50000000"
+ id="stop10599" />
+ <stop
+ id="stop10595"
+ offset="1.0000000"
+ style="stop-color:#c5cbc0;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11335">
+ <stop
+ id="stop11337"
+ offset="0"
+ style="stop-color:#6f716d;stop-opacity:1;" />
+ <stop
+ id="stop11339"
+ offset="1.0000000"
+ style="stop-color:#9ea09c;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2092">
+ <stop
+ style="stop-color:#fff7b0;stop-opacity:1;"
+ offset="0"
+ id="stop2094" />
+ <stop
+ id="stop2098"
+ offset="0.20999999"
+ style="stop-color:#ffec41;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#e2cc00;stop-opacity:1;"
+ offset="0.83999997"
+ id="stop2293" />
+ <stop
+ style="stop-color:#c3af00;stop-opacity:1;"
+ offset="1"
+ id="stop2100" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11327">
+ <stop
+ id="stop11329"
+ offset="0"
+ style="stop-color:#7d6400;stop-opacity:1;" />
+ <stop
+ id="stop11331"
+ offset="1.0000000"
+ style="stop-color:#be9700;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9845">
+ <stop
+ id="stop9847"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop9849"
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.49484536;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient12071"
+ inkscape:collect="always">
+ <stop
+ id="stop12073"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop12075"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient3781"
+ gradientUnits="userSpaceOnUse"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.61960784"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="6.605754"
+ inkscape:cy="13.296835"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata12365">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Edit Paste</dc:title>
+ <dc:date>2005-10-10</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>paste</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g3759"
+ transform="matrix(0.3282573,0,0,0.3282573,-3.6446223e-2,0.2924263)">
+ <rect
+ ry="1.3879364"
+ rx="1.3879371"
+ y="4.5"
+ x="4.4643173"
+ height="41.045437"
+ width="39.035683"
+ id="rect12368"
+ style="opacity:1;fill:url(#linearGradient14490);fill-opacity:1;fill-rule:evenodd;stroke:#714c16;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.56650835"
+ rx="0.56650835"
+ y="6.5295157"
+ x="8.5323219"
+ height="35.976688"
+ width="30.951559"
+ id="rect12413"
+ style="opacity:1;fill:url(#linearGradient15224);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.98387533"
+ rx="0.98387533"
+ y="0"
+ x="18"
+ height="4"
+ width="12"
+ id="rect13756"
+ style="opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="7.4665856"
+ x="9.5171413"
+ height="34.040764"
+ width="29.014147"
+ id="rect15244"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2265);stroke-width:1.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.47879848"
+ rx="0.47879848"
+ y="5.4307775"
+ x="5.4393425"
+ height="39.092987"
+ width="37.085655"
+ id="rect15974"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c68827;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ style="opacity:0.10795456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2208"
+ width="18.947376"
+ height="7"
+ x="14.791488"
+ y="4.4722719"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient15240);fill-opacity:1;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2285"
+ width="18.947376"
+ height="7"
+ x="14.526322"
+ y="3.5"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient2283);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2281"
+ width="9.6973763"
+ height="3.5826404"
+ x="19.151323"
+ y="1.2086792"
+ rx="0.32543635"
+ ry="0.32543635" />
+ <rect
+ ry="1.0129364"
+ rx="1.0129364"
+ y="3.9375"
+ x="14.953014"
+ height="6.1875"
+ width="18.093992"
+ id="rect13754"
+ style="opacity:1;fill:url(#linearGradient2287);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2212"
+ d="M 39.018306,36.25 L 39.0625,42.0625 L 30.5625,42.018306 L 39.018306,36.25 z"
+ style="opacity:0.48863639;fill:url(#linearGradient2222);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ id="rect2232"
+ d="M 19.46875,1.46875 C 19.466654,1.4708456 19.470414,1.4975336 19.46875,1.5 C 19.46758,1.502776 19.438116,1.4969757 19.4375,1.5 L 19.4375,4.375 C 19.4375,4.3814229 19.46641,4.4006981 19.46875,4.40625 C 19.471216,4.4079135 19.465974,4.4363298 19.46875,4.4375 L 15.9375,4.4375 C 15.91974,4.4375 15.892285,4.4357551 15.875,4.4375 C 15.840968,4.4426713 15.781454,4.4572762 15.75,4.46875 C 15.611832,4.5269964 15.482328,4.6677699 15.4375,4.8125 C 15.426991,4.8535348 15.4375,4.9243489 15.4375,4.96875 L 15.4375,9.125 C 15.4375,9.1427605 15.435755,9.1702147 15.4375,9.1875 C 15.442671,9.2215321 15.457276,9.2810456 15.46875,9.3125 C 15.478458,9.3355281 15.487176,9.3851004 15.5,9.40625 C 15.5046,9.41307 15.526336,9.4309205 15.53125,9.4375 C 15.552124,9.4628138 15.599686,9.5103764 15.625,9.53125 C 15.638159,9.5410789 15.6734,9.5539504 15.6875,9.5625 C 15.702038,9.5703781 15.734648,9.5872782 15.75,9.59375 C 15.781454,9.6052238 15.840968,9.6198287 15.875,9.625 C 15.892285,9.6267449 15.91974,9.625 15.9375,9.625 L 32.0625,9.625 C 32.08026,9.625 32.107715,9.6267449 32.125,9.625 C 32.159032,9.6198287 32.218546,9.6052238 32.25,9.59375 C 32.265352,9.5872782 32.297962,9.5703781 32.3125,9.5625 C 32.3266,9.5539504 32.361841,9.5410789 32.375,9.53125 C 32.400314,9.5103764 32.447876,9.4628138 32.46875,9.4375 C 32.473664,9.4309205 32.4954,9.41307 32.5,9.40625 C 32.512824,9.3851004 32.521542,9.3355281 32.53125,9.3125 C 32.542724,9.2810456 32.557329,9.2215321 32.5625,9.1875 C 32.564245,9.1702147 32.5625,9.1427605 32.5625,9.125 L 32.5625,4.96875 C 32.5625,4.9243489 32.573009,4.8535348 32.5625,4.8125 C 32.517672,4.6677698 32.388168,4.5269964 32.25,4.46875 C 32.218546,4.4572762 32.159032,4.4426713 32.125,4.4375 C 32.107715,4.4357551 32.08026,4.4375 32.0625,4.4375 L 28.53125,4.4375 C 28.534026,4.4363298 28.528784,4.4079135 28.53125,4.40625 C 28.533591,4.4006981 28.5625,4.3814229 28.5625,4.375 L 28.5625,1.5 C 28.561884,1.4969757 28.53242,1.502776 28.53125,1.5 C 28.529586,1.4975336 28.533346,1.4708456 28.53125,1.46875 C 28.528474,1.4675798 28.503024,1.4693657 28.5,1.46875 L 19.5,1.46875 C 19.496976,1.4693657 19.471526,1.4675798 19.46875,1.46875 z"
+ style="opacity:0.31681818;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3781);stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2210"
+ d="M 30.059082,42.086864 C 31.850223,42.254516 39.048809,37.717278 39.539922,33.698855 C 37.97666,36.121952 34.584971,35.667446 30.476213,35.826456 C 30.476213,35.826456 30.871582,41.586864 30.059082,42.086864 z"
+ style="opacity:1;fill:url(#linearGradient2230);fill-opacity:1;fill-rule:evenodd;stroke:#868a84;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.36931817;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2257);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 31.509519,40.68705 C 32.879298,40.003221 36.038783,38.086016 37.338164,36.205012 C 35.545641,36.581496 34.347243,36.794585 31.610576,36.900494 C 31.610576,36.900494 31.697137,39.91208 31.509519,40.68705 z"
+ id="path2247"
+ sodipodi:nodetypes="cccc" />
+ <g
+ transform="matrix(1.631663,0,0,1.631663,-7.203818,2.952894)"
+ id="g1529"
+ inkscape:label="Layer 1">
+ <g
+ id="g1879"
+ transform="matrix(0.844217,0,0,0.844217,-10.3995,-12.36372)">
+ <path
+ sodipodi:nodetypes="cczcccczccc"
+ id="path2086"
+ d="M 34.238513,34.181365 L 34.238513,30.359668 C 34.238513,26.445675 36.861875,24.661287 40.762635,24.710167 C 44.684619,24.759046 47.274012,26.461946 47.274012,30.421985 L 47.267528,34.181365 L 44.874632,34.181365 L 44.874632,31.406199 C 44.810387,30.442875 45.141632,27.216102 40.790111,27.216102 C 36.408575,27.216102 36.666117,30.454534 36.681818,31.425378 L 36.681818,34.181365 L 34.238513,34.181365 z"
+ style="fill:url(#linearGradient1886);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1888);stroke-width:1.1845268;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ ry="2.3033772"
+ rx="2.6473897"
+ y="34.231865"
+ x="32.468109"
+ height="11.769073"
+ width="17.156261"
+ id="rect1314"
+ style="fill:url(#linearGradient1890);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1892);stroke-width:1.18452692;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="1.4387805"
+ rx="1.4387794"
+ y="35.387321"
+ x="33.559612"
+ height="9.4392996"
+ width="14.977587"
+ id="rect6903"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1894);stroke-width:1.18452799;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.60109289" />
+ <path
+ sodipodi:nodetypes="ccsccc"
+ id="rect11343"
+ d="M 34.675226,30.571517 C 34.805219,27.673419 35.610937,25.490973 40.985429,25.305958 C 37.505396,25.7964 35.612515,26.812487 35.612515,29.842371 C 35.612515,29.842371 35.525705,33.597665 35.525705,33.597665 L 34.675226,33.597665 L 34.675226,30.571517 z"
+ style="fill:url(#linearGradient1896);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="28.716803"
+ x="45.460419"
+ height="4.90236"
+ width="0.98047203"
+ id="rect1345"
+ style="fill:url(#linearGradient1898);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/person.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/person.svg.svn-base
new file mode 100644
index 0000000..9abbb02
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/person.svg.svn-base
@@ -0,0 +1,388 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2108"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/stock/generic"
+ sodipodi:docname="person.svg"
+ inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-icon-theme/48x48/stock/generic/stock_person.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective39" />
+ <linearGradient
+ id="linearGradient4562">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop4564" />
+ <stop
+ style="stop-color:#d6d6d2;stop-opacity:1;"
+ offset="1"
+ id="stop4566" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4356">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop4358" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop4360" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3824">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3826" />
+ <stop
+ style="stop-color:#c9c9c9;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop3828" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3816">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3818" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3820" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3816"
+ id="radialGradient3822"
+ cx="31.112698"
+ cy="19.008621"
+ fx="31.112698"
+ fy="19.008621"
+ r="8.6620579"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient4362"
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.329025,6.0757e-2,-6.0757e-2,0.329025,16.100244,13.290312)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient4366"
+ gradientUnits="userSpaceOnUse"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,32.768766,12.999177)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient1366"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,28.188541,10.75574)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3824"
+ id="linearGradient1372"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3345875,0,0,0.3345875,10.045981,12.133792)"
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient4568"
+ cx="24.753788"
+ cy="26.814409"
+ fx="24.753788"
+ fy="26.814409"
+ r="17.986025"
+ gradientTransform="matrix(0.3386292,0,0,0.3415987,16.17891,14.840961)"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3816"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.558489,0,-1.377346e-8,0.563387,14.87134,4.364123)"
+ cx="29.922075"
+ cy="17.727694"
+ fx="29.922075"
+ fy="17.727694"
+ r="17.986025" />
+ <filter
+ inkscape:collect="always"
+ x="-0.076111108"
+ width="1.1522222"
+ y="-0.28344828"
+ height="1.5668966"
+ id="filter5655">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.4531044"
+ id="feGaussianBlur5657" />
+ </filter>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3824"
+ id="linearGradient3196"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3345875,0,0,0.3345875,10.045981,12.133792)"
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3198"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,28.188541,10.75574)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3200"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3386292,0,0,0.3415987,16.17891,14.840961)"
+ cx="24.753788"
+ cy="26.814409"
+ fx="24.753788"
+ fy="26.814409"
+ r="17.986025" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3202"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,32.768766,12.999177)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3204"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.329025,6.0757e-2,-6.0757e-2,0.329025,16.100244,13.290312)"
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3816"
+ id="radialGradient3206"
+ gradientUnits="userSpaceOnUse"
+ cx="31.112698"
+ cy="19.008621"
+ fx="31.112698"
+ fy="19.008621"
+ r="8.6620579" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3208"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.558489,0,-1.377346e-8,0.563387,14.87134,4.364123)"
+ cx="29.922075"
+ cy="17.727694"
+ fx="29.922075"
+ fy="17.727694"
+ r="17.986025" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:showpageshadow="false"
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.16862745"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="25.782205"
+ inkscape:cx="7.1442001"
+ inkscape:cy="7.5126712"
+ inkscape:current-layer="layer2"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ fill="#9db029"
+ stroke="#727e0a"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Person</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://jimmac.musichall.cz</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>user</rdf:li>
+ <rdf:li>person</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="cipek"
+ inkscape:groupmode="layer"
+ style="display:inline"
+ transform="translate(-20.05096,-17.593986)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="dalsi cipek"
+ style="display:inline"
+ transform="translate(-20.05096,-17.593986)">
+ <g
+ id="g3184"
+ transform="matrix(1.4267997,0,0,1.4267997,-6.9832045,-7.3342725)">
+ <path
+ id="path4173"
+ d="M 21.757143,23.52136 L 23.176678,23.52136 L 22.348616,22.752445 L 22.171174,22.989035 L 21.993732,22.811593 L 21.757143,23.52136 z"
+ style="opacity:1;fill:url(#linearGradient3196);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.22784807;fill:url(#linearGradient3198);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 23.386507,25.431438 C 23.798468,25.23705 23.99023,24.761487 23.99023,24.761487 C 23.66932,23.408755 22.65986,22.471964 22.65986,22.471964 C 22.65986,22.471964 23.484482,24.59412 23.386507,25.431438 z"
+ id="path4370"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ transform="matrix(0.2337963,0,0,0.2337963,18.811068,17.877885)"
+ ry="5.126524"
+ rx="5.126524"
+ y="35.448853"
+ x="5.3033009"
+ height="10.253048"
+ width="38.183765"
+ id="rect4608"
+ style="opacity:0.34857142;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.30000001;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible;filter:url(#filter5655);enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cczcczc"
+ id="path4308"
+ d="M 22.895503,28.188054 L 26.444339,28.188054 C 27.449843,28.188054 28.445335,27.819361 28.81023,26.768519 C 29.156742,25.77062 28.869377,23.870303 26.621781,22.332474 L 22.422325,22.332474 C 20.174728,23.752008 19.89385,25.693349 20.411317,26.827666 C 20.938492,27.983261 21.830852,28.188054 22.895503,28.188054 z"
+ style="opacity:1;fill:url(#radialGradient3200);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.24999996px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ style="opacity:0.29120878;fill:url(#linearGradient3202);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 27.966732,27.674875 C 28.378694,27.480487 28.570455,27.004924 28.570455,27.004924 C 28.249546,25.652192 27.240085,24.715401 27.240085,24.715401 C 27.240085,24.715401 28.064708,26.837557 27.966732,27.674875 z"
+ id="path4364"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ sodipodi:nodetypes="cccc"
+ id="path4354"
+ d="M 21.326525,27.820334 C 20.909091,27.637994 20.722261,27.198577 20.722261,27.198577 C 21.003744,25.837095 21.966902,24.841001 21.966902,24.841001 C 21.966902,24.841001 21.20427,26.986214 21.326525,27.820334 z"
+ style="opacity:0.54945056;fill:url(#linearGradient3204);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.64285715;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.24999997px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 22.814062,27.9295 L 26.445984,27.921851 C 27.359628,27.921851 28.264173,27.586842 28.595733,26.632002 C 28.910588,25.725268 28.562948,23.998559 26.520687,22.601222 L 22.531825,22.517093 C 20.489564,23.806942 20.09428,25.570927 20.572121,26.685746 C 21.049963,27.800564 21.747249,27.921851 22.814062,27.9295 z"
+ id="path4314"
+ sodipodi:nodetypes="cczcczc" />
+ <path
+ transform="matrix(0.3345875,0,0,0.3345875,14.159031,15.428212)"
+ sodipodi:type="arc"
+ style="opacity:1;fill:url(#radialGradient3206);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path4318"
+ sodipodi:cx="31.112698"
+ sodipodi:cy="19.008621"
+ sodipodi:rx="8.6620579"
+ sodipodi:ry="8.6620579"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" />
+ <path
+ transform="matrix(0.3345875,0,0,0.3345875,14.200853,14.257155)"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z"
+ sodipodi:ry="8.6620579"
+ sodipodi:rx="8.6620579"
+ sodipodi:cy="19.008621"
+ sodipodi:cx="31.112698"
+ id="path4320"
+ style="opacity:1;fill:url(#radialGradient3208);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.74718857px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.3037807,0,0,0.3037807,15.159341,14.842753)"
+ sodipodi:type="arc"
+ style="opacity:0.19620254;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.82296228px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path4322"
+ sodipodi:cx="31.112698"
+ sodipodi:cy="19.008621"
+ sodipodi:rx="8.6620579"
+ sodipodi:ry="8.6620579"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" />
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/.svn/text-base/plaintext.svg.svn-base b/emacs.d/lisp/rudel/icons/.svn/text-base/plaintext.svg.svn-base
new file mode 100644
index 0000000..1086ba2
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/.svn/text-base/plaintext.svg.svn-base
@@ -0,0 +1,474 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg12360"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/data/Desktop/icons/scaleable"
+ sodipodi:docname="plaintext.svg"
+ inkscape:export-filename="/data/Desktop/icons/scaleable/seahorse-applet-text.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs12362">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective3119" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2259">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2261" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2263" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2251">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2253" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2255" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2239">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2241" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2243" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2224">
+ <stop
+ style="stop-color:#7c7c7c;stop-opacity:1;"
+ offset="0"
+ id="stop2226" />
+ <stop
+ style="stop-color:#b8b8b8;stop-opacity:1;"
+ offset="1"
+ id="stop2228" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2216">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2218" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2220" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15234">
+ <stop
+ style="stop-color:#97978a;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15236" />
+ <stop
+ id="stop15242"
+ offset="0.50000000"
+ style="stop-color:#c2c2b9;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#7d7d6f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15238" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15218">
+ <stop
+ style="stop-color:#f0f0ef;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15220" />
+ <stop
+ id="stop2269"
+ offset="0.59928656"
+ style="stop-color:#e8e8e8;stop-opacity:1;" />
+ <stop
+ id="stop2267"
+ offset="0.82758623"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d8d8d3;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15222" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14484">
+ <stop
+ style="stop-color:#c68827;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop14486" />
+ <stop
+ style="stop-color:#89601f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop14488" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient13746">
+ <stop
+ style="stop-color:#646459;stop-opacity:1;"
+ offset="0"
+ id="stop13748" />
+ <stop
+ style="stop-color:#646459;stop-opacity:0;"
+ offset="1"
+ id="stop13750" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient13746"
+ id="radialGradient3142"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.110577,0,40.26648)"
+ cx="24.647722"
+ cy="45.272587"
+ fx="24.647722"
+ fy="45.272587"
+ r="21.011173" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14484"
+ id="linearGradient3144"
+ gradientUnits="userSpaceOnUse"
+ x1="6.1071744"
+ y1="10.45129"
+ x2="33.857143"
+ y2="37.87986" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15218"
+ id="linearGradient3146"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.065698,0,0,0.987595,-1.564439,7.487332e-2)"
+ x1="22.308331"
+ y1="18.99214"
+ x2="35.785294"
+ y2="39.498238" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2259"
+ id="linearGradient3148"
+ gradientUnits="userSpaceOnUse"
+ x1="26.076092"
+ y1="26.696676"
+ x2="30.811172"
+ y2="42.007351" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3150"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.052632,0,0,1,-1.789474,0)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3152"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.538743,0,0,0.511806,10.8008,-0.58264)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.404572"
+ y2="6.481061" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3154"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.005222,0,0,0.883928,-0.627923,0.84375)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2216"
+ id="linearGradient3156"
+ gradientUnits="userSpaceOnUse"
+ x1="36.8125"
+ y1="39.15625"
+ x2="39.0625"
+ y2="42.0625" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2224"
+ id="linearGradient3158"
+ gradientUnits="userSpaceOnUse"
+ x1="35.996582"
+ y1="40.458221"
+ x2="33.664921"
+ y2="37.770721" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient3160"
+ gradientUnits="userSpaceOnUse"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2251"
+ id="linearGradient3162"
+ gradientUnits="userSpaceOnUse"
+ x1="33.396004"
+ y1="36.921333"
+ x2="34.170048"
+ y2="38.070381" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.15294118"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="10.980754"
+ inkscape:cy="28.267956"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata12365">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Edit Paste</dc:title>
+ <dc:date>2005-10-10</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>paste</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g3121"
+ transform="matrix(0.3298017,0,0,0.3298017,9.0643304e-2,8.4759164e-2)">
+ <path
+ transform="matrix(0.913383,0,0,1.178892,1.920946,-8.11047)"
+ d="M 45.658895,45.272587 A 21.011173,2.3233509 0 1 1 3.636549,45.272587 A 21.011173,2.3233509 0 1 1 45.658895,45.272587 z"
+ sodipodi:ry="2.3233509"
+ sodipodi:rx="21.011173"
+ sodipodi:cy="45.272587"
+ sodipodi:cx="24.647722"
+ id="path13018"
+ style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.90907735;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ ry="1.3879364"
+ rx="1.3879371"
+ y="4.5"
+ x="4.4643173"
+ height="41.045437"
+ width="39.035683"
+ id="rect12368"
+ style="opacity:1;fill:url(#linearGradient3144);fill-opacity:1;fill-rule:evenodd;stroke:#714c16;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.56650835"
+ rx="0.56650835"
+ y="6.5295157"
+ x="8.5323219"
+ height="35.976688"
+ width="30.951559"
+ id="rect12413"
+ style="opacity:1;fill:url(#linearGradient3146);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.98387533"
+ rx="0.98387533"
+ y="0"
+ x="18"
+ height="4"
+ width="12"
+ id="rect13756"
+ style="opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="7.4665856"
+ x="9.5171413"
+ height="34.040764"
+ width="29.014147"
+ id="rect15244"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3148);stroke-width:1.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.47879848"
+ rx="0.47879848"
+ y="5.4307775"
+ x="5.4393425"
+ height="39.092987"
+ width="37.085655"
+ id="rect15974"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c68827;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ style="opacity:0.10795456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2208"
+ width="18.947376"
+ height="7"
+ x="14.791488"
+ y="4.4722719"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient3150);fill-opacity:1;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2285"
+ width="18.947376"
+ height="7"
+ x="14.526322"
+ y="3.5"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient3152);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2281"
+ width="9.6973763"
+ height="3.5826404"
+ x="19.151323"
+ y="1.2086792"
+ rx="0.32543635"
+ ry="0.32543635" />
+ <rect
+ ry="1.0129364"
+ rx="1.0129364"
+ y="3.9375"
+ x="14.953014"
+ height="6.1875"
+ width="18.093992"
+ id="rect13754"
+ style="opacity:1;fill:url(#linearGradient3154);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2212"
+ d="M 39.018306,36.25 L 39.0625,42.0625 L 30.5625,42.018306 L 39.018306,36.25 z"
+ style="opacity:0.48863639;fill:url(#linearGradient3156);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2210"
+ d="M 30.059082,42.086864 C 31.850223,42.254516 39.048809,37.717278 39.539922,33.698855 C 37.97666,36.121952 34.584971,35.667446 30.476213,35.826456 C 30.476213,35.826456 30.871582,41.586864 30.059082,42.086864 z"
+ style="opacity:1;fill:url(#linearGradient3158);fill-opacity:1;fill-rule:evenodd;stroke:#868a84;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ id="rect2232"
+ d="M 19.46875,1.46875 C 19.466654,1.4708456 19.470414,1.4975336 19.46875,1.5 C 19.46758,1.502776 19.438116,1.4969757 19.4375,1.5 L 19.4375,4.375 C 19.4375,4.3814229 19.46641,4.4006981 19.46875,4.40625 C 19.471216,4.4079135 19.465974,4.4363298 19.46875,4.4375 L 15.9375,4.4375 C 15.91974,4.4375 15.892285,4.4357551 15.875,4.4375 C 15.840968,4.4426713 15.781454,4.4572762 15.75,4.46875 C 15.611832,4.5269964 15.482328,4.6677699 15.4375,4.8125 C 15.426991,4.8535348 15.4375,4.9243489 15.4375,4.96875 L 15.4375,9.125 C 15.4375,9.1427605 15.435755,9.1702147 15.4375,9.1875 C 15.442671,9.2215321 15.457276,9.2810456 15.46875,9.3125 C 15.478458,9.3355281 15.487176,9.3851004 15.5,9.40625 C 15.5046,9.41307 15.526336,9.4309205 15.53125,9.4375 C 15.552124,9.4628138 15.599686,9.5103764 15.625,9.53125 C 15.638159,9.5410789 15.6734,9.5539504 15.6875,9.5625 C 15.702038,9.5703781 15.734648,9.5872782 15.75,9.59375 C 15.781454,9.6052238 15.840968,9.6198287 15.875,9.625 C 15.892285,9.6267449 15.91974,9.625 15.9375,9.625 L 32.0625,9.625 C 32.08026,9.625 32.107715,9.6267449 32.125,9.625 C 32.159032,9.6198287 32.218546,9.6052238 32.25,9.59375 C 32.265352,9.5872782 32.297962,9.5703781 32.3125,9.5625 C 32.3266,9.5539504 32.361841,9.5410789 32.375,9.53125 C 32.400314,9.5103764 32.447876,9.4628138 32.46875,9.4375 C 32.473664,9.4309205 32.4954,9.41307 32.5,9.40625 C 32.512824,9.3851004 32.521542,9.3355281 32.53125,9.3125 C 32.542724,9.2810456 32.557329,9.2215321 32.5625,9.1875 C 32.564245,9.1702147 32.5625,9.1427605 32.5625,9.125 L 32.5625,4.96875 C 32.5625,4.9243489 32.573009,4.8535348 32.5625,4.8125 C 32.517672,4.6677698 32.388168,4.5269964 32.25,4.46875 C 32.218546,4.4572762 32.159032,4.4426713 32.125,4.4375 C 32.107715,4.4357551 32.08026,4.4375 32.0625,4.4375 L 28.53125,4.4375 C 28.534026,4.4363298 28.528784,4.4079135 28.53125,4.40625 C 28.533591,4.4006981 28.5625,4.3814229 28.5625,4.375 L 28.5625,1.5 C 28.561884,1.4969757 28.53242,1.502776 28.53125,1.5 C 28.529586,1.4975336 28.533346,1.4708456 28.53125,1.46875 C 28.528474,1.4675798 28.503024,1.4693657 28.5,1.46875 L 19.5,1.46875 C 19.496976,1.4693657 19.471526,1.4675798 19.46875,1.46875 z"
+ style="opacity:0.31681818;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3160);stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ style="opacity:0.36931817;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3162);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 31.509519,40.68705 C 32.879298,40.003221 36.038783,38.086016 37.338164,36.205012 C 35.545641,36.581496 34.347243,36.794585 31.610576,36.900494 C 31.610576,36.900494 31.697137,39.91208 31.509519,40.68705 z"
+ id="path2247"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ y="15"
+ x="14"
+ height="2"
+ width="21"
+ id="rect2271"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2273"
+ width="20"
+ height="2"
+ x="14"
+ y="19" />
+ <rect
+ y="23"
+ x="14"
+ height="2"
+ width="18"
+ id="rect2275"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2277"
+ width="21"
+ height="2"
+ x="14"
+ y="27" />
+ <rect
+ y="31"
+ x="14"
+ height="2"
+ width="13"
+ id="rect2279"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/connected.svg b/emacs.d/lisp/rudel/icons/connected.svg
new file mode 100644
index 0000000..3777037
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/connected.svg
@@ -0,0 +1,2479 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2327"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/status"
+ sodipodi:docname="connected.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective287" />
+ <linearGradient
+ id="linearGradient7670">
+ <stop
+ style="stop-color:#3465a4;stop-opacity:1"
+ offset="0"
+ id="stop7672" />
+ <stop
+ style="stop-color:#204a87;stop-opacity:1"
+ offset="1"
+ id="stop7674" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2307">
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:1;"
+ offset="0"
+ id="stop2309" />
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:0;"
+ offset="1"
+ id="stop2311" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ id="stop11402"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11404"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6240"
+ inkscape:collect="always">
+ <stop
+ id="stop6242"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop6244"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ id="stop5139"
+ offset="0"
+ style="stop-color:#eeeeec;stop-opacity:1;" />
+ <stop
+ id="stop5141"
+ offset="1"
+ style="stop-color:#e6e6e3;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5225"
+ inkscape:collect="always">
+ <stop
+ id="stop5227"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop5229"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3899"
+ inkscape:collect="always">
+ <stop
+ id="stop3901"
+ offset="0"
+ style="stop-color:#eeeeec" />
+ <stop
+ id="stop3903"
+ offset="1"
+ style="stop-color:#d3d7cf" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3907">
+ <stop
+ id="stop3909"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3911"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4196">
+ <stop
+ id="stop4198"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop4200"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3304"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3302"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3300"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3298"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3296"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3294"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3292"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3276"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3274"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3272"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3270"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3268"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3266"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3264"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3155"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3158"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3161"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3164"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3167"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3170"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3173"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3176"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3182"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3185"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3188"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3191"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3194"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3197"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3200"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3203"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3206"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3209"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3212"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3215"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3218"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3221"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3224"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3230"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3233"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3236"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3239"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3242"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3245"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <radialGradient
+ r="19.5"
+ fy="47.045319"
+ fx="20.913568"
+ cy="47.045319"
+ cx="20.913568"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3248"
+ xlink:href="#linearGradient3907"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ gradientUnits="userSpaceOnUse"
+ y2="37.9375"
+ x2="29.125"
+ y1="46.029419"
+ x1="29.5"
+ id="linearGradient3905"
+ xlink:href="#linearGradient3899"
+ inkscape:collect="always" />
+ <radialGradient
+ r="117.14286"
+ fy="486.64789"
+ fx="605.71429"
+ cy="486.64789"
+ cx="605.71429"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2309"
+ xlink:href="#linearGradient5060"
+ inkscape:collect="always" />
+ <radialGradient
+ r="117.14286"
+ fy="486.64789"
+ fx="605.71429"
+ cy="486.64789"
+ cx="605.71429"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2311"
+ xlink:href="#linearGradient5060"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ gradientUnits="userSpaceOnUse"
+ y2="26.039215"
+ x2="20.156862"
+ y1="5.0996137"
+ x1="20.156862"
+ id="linearGradient6246"
+ xlink:href="#linearGradient6240"
+ inkscape:collect="always" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ r="19.00016"
+ fy="32.997028"
+ fx="24.006104"
+ cy="32.997028"
+ cx="24.006104"
+ id="radialGradient5239"
+ xlink:href="#linearGradient7670"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ y2="38.876041"
+ x2="39.904388"
+ y1="6.3760414"
+ x1="17.247635"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5147"
+ xlink:href="#linearGradient5137"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="43.82579"
+ x2="31.86105"
+ y1="37.842293"
+ x1="31.743324"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2308"
+ xlink:href="#linearGradient5137"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="40.219608"
+ x2="23.529411"
+ y1="34.572548"
+ x1="23.154902"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2310"
+ xlink:href="#linearGradient11400"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ gradientUnits="userSpaceOnUse"
+ y2="33.637787"
+ x2="37.295498"
+ y1="38.267769"
+ x1="37.484837"
+ id="linearGradient4202"
+ xlink:href="#linearGradient4196"
+ inkscape:collect="always" />
+ <radialGradient
+ r="23.75956"
+ fy="42.6875"
+ fx="23.9375"
+ cy="42.6875"
+ cx="23.9375"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient2313"
+ xlink:href="#linearGradient5225"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5478"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient5620"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient5622"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5624"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient5626"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient5628"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient5630"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient5632"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5634"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5636"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5638"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient5640"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5642"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5644"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5646"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5648"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5650"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5652"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5654"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5656"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5658"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5660"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5662"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5664"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5666"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5668"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5670"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5672"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5674"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5676"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5678"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5680"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5682"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5684"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5686"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5688"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5690"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5692"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5694"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5696"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5698"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5700"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5702"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5704"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5706"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5708"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5710"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5712"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5714"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5716"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5718"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5720"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5722"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5724"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5726"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5728"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666"
+ borderopacity="1"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="24.875"
+ inkscape:cx="0.95477387"
+ inkscape:cy="6"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false"
+ inkscape:grid-points="false"
+ showborder="true" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Network</dc:title>
+ <dc:date>2005-03-08</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:source />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner, Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(-1.1628734,-1.9999995)">
+ <g
+ id="g2660"
+ transform="matrix(0.3440228,0,0,0.3440228,0.8783092,2.0767243)">
+ <g
+ transform="translate(14.98536,1)"
+ id="g5480">
+ <g
+ id="g5482"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5484"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5486"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5488" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5490" />
+ </g>
+ <g
+ id="g5492"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient5620);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5494"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5496"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5622);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5498"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5500"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient5624);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5502"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5626);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5504"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5506"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5508"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5628);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5510"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5630);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5512"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5632);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5514"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5516"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5518">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5634);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5520"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient5636);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5522"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5524"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient5638);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5640);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5526"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5528"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5530"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5532"
+ style="fill:url(#radialGradient5642);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5534"
+ style="fill:url(#radialGradient5644);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5536"
+ style="fill:url(#radialGradient5646);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5538"
+ style="fill:url(#radialGradient5648);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5540"
+ style="fill:url(#radialGradient5650);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5542"
+ style="fill:url(#radialGradient5652);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5544"
+ style="fill:url(#radialGradient5654);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5546"
+ style="fill:url(#radialGradient5656);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5548"
+ style="fill:url(#radialGradient5658);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5550"
+ style="fill:url(#radialGradient5660);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5552"
+ style="fill:url(#radialGradient5662);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5554"
+ style="fill:url(#radialGradient5664);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5556"
+ style="fill:url(#radialGradient5666);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5558"
+ style="fill:url(#radialGradient5668);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5560"
+ style="fill:url(#radialGradient5670);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5562"
+ style="fill:url(#radialGradient5672);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5564"
+ style="fill:url(#radialGradient5674);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5566"
+ style="fill:url(#radialGradient5676);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5568"
+ style="fill:url(#radialGradient5678);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5570"
+ style="fill:url(#radialGradient5680);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5572"
+ style="fill:url(#radialGradient5682);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5574"
+ style="fill:url(#radialGradient5684);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5576"
+ style="fill:url(#radialGradient5686);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5578"
+ style="fill:url(#radialGradient5688);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5580"
+ style="fill:url(#radialGradient5690);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5582"
+ style="fill:url(#radialGradient5692);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5584"
+ style="fill:url(#radialGradient5694);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5586"
+ style="fill:url(#radialGradient5696);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5588"
+ style="fill:url(#radialGradient5698);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5590"
+ style="fill:url(#radialGradient5700);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5592"
+ style="fill:url(#radialGradient5702);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5594"
+ style="fill:url(#radialGradient5704);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5596"
+ style="fill:url(#radialGradient5706);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5598"
+ style="fill:url(#radialGradient5708);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5600"
+ style="fill:url(#radialGradient5710);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5602"
+ style="fill:url(#radialGradient5712);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5604"
+ style="fill:url(#radialGradient5714);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5606"
+ style="fill:url(#radialGradient5716);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5608"
+ style="fill:url(#radialGradient5718);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5610"
+ style="fill:url(#radialGradient5720);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5612"
+ style="fill:url(#radialGradient5722);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5614"
+ style="fill:url(#radialGradient5724);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5616"
+ style="fill:url(#radialGradient5726);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5618"
+ style="fill:url(#radialGradient5728);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ transform="translate(0.985355,12)"
+ id="g5340">
+ <g
+ id="g5342"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5344"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5346"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5348" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5350" />
+ </g>
+ <g
+ id="layer2"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient2313);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5353"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5355"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4202);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5357"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5359"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient2308);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5361"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient2310);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5363"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5365"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5367"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5147);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5369"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5239);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5371"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient6246);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5373"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5375"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5377">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5478);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect6709"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient2309);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5380"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5382"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient2311);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient3905);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5384"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5386"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5388"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5390"
+ style="fill:url(#radialGradient3248);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5392"
+ style="fill:url(#radialGradient3245);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5394"
+ style="fill:url(#radialGradient3242);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5396"
+ style="fill:url(#radialGradient3239);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5398"
+ style="fill:url(#radialGradient3236);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5400"
+ style="fill:url(#radialGradient3233);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5402"
+ style="fill:url(#radialGradient3230);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5404"
+ style="fill:url(#radialGradient3224);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5406"
+ style="fill:url(#radialGradient3221);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5408"
+ style="fill:url(#radialGradient3218);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5410"
+ style="fill:url(#radialGradient3215);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5412"
+ style="fill:url(#radialGradient3212);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5414"
+ style="fill:url(#radialGradient3209);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5416"
+ style="fill:url(#radialGradient3206);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5418"
+ style="fill:url(#radialGradient3203);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5420"
+ style="fill:url(#radialGradient3200);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5422"
+ style="fill:url(#radialGradient3197);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5424"
+ style="fill:url(#radialGradient3194);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5426"
+ style="fill:url(#radialGradient3191);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5428"
+ style="fill:url(#radialGradient3188);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5430"
+ style="fill:url(#radialGradient3185);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5432"
+ style="fill:url(#radialGradient3182);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5434"
+ style="fill:url(#radialGradient3176);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5436"
+ style="fill:url(#radialGradient3173);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5438"
+ style="fill:url(#radialGradient3170);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5440"
+ style="fill:url(#radialGradient3167);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5442"
+ style="fill:url(#radialGradient3164);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5444"
+ style="fill:url(#radialGradient3161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5446"
+ style="fill:url(#radialGradient3158);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5448"
+ style="fill:url(#radialGradient3155);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5450"
+ style="fill:url(#radialGradient3264);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5452"
+ style="fill:url(#radialGradient3266);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5454"
+ style="fill:url(#radialGradient3268);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5456"
+ style="fill:url(#radialGradient3270);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5458"
+ style="fill:url(#radialGradient3272);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5460"
+ style="fill:url(#radialGradient3274);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5462"
+ style="fill:url(#radialGradient3276);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5464"
+ style="fill:url(#radialGradient3292);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5466"
+ style="fill:url(#radialGradient3294);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5468"
+ style="fill:url(#radialGradient3296);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5470"
+ style="fill:url(#radialGradient3298);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5472"
+ style="fill:url(#radialGradient3300);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5474"
+ style="fill:url(#radialGradient3302);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5476"
+ style="fill:url(#radialGradient3304);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/disconnected.svg b/emacs.d/lisp/rudel/icons/disconnected.svg
new file mode 100644
index 0000000..5a8de65
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/disconnected.svg
@@ -0,0 +1,2600 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2327"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/status"
+ sodipodi:docname="disconnected.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective4721" />
+ <linearGradient
+ id="linearGradient5180">
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="0"
+ id="stop5182" />
+ <stop
+ id="stop5188"
+ offset="0.5"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5184" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5166">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5168" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5170" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient7670">
+ <stop
+ style="stop-color:#3465a4;stop-opacity:1"
+ offset="0"
+ id="stop7672" />
+ <stop
+ style="stop-color:#204a87;stop-opacity:1"
+ offset="1"
+ id="stop7674" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2307">
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:1;"
+ offset="0"
+ id="stop2309" />
+ <stop
+ style="stop-color:#5a7aa4;stop-opacity:0;"
+ offset="1"
+ id="stop2311" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11400">
+ <stop
+ id="stop11402"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop11404"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient6240"
+ inkscape:collect="always">
+ <stop
+ id="stop6242"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop6244"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5137">
+ <stop
+ id="stop5139"
+ offset="0"
+ style="stop-color:#eeeeec;stop-opacity:1;" />
+ <stop
+ id="stop5141"
+ offset="1"
+ style="stop-color:#e6e6e3;stop-opacity:1;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient5225"
+ inkscape:collect="always">
+ <stop
+ id="stop5227"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop5229"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3899"
+ inkscape:collect="always">
+ <stop
+ id="stop3901"
+ offset="0"
+ style="stop-color:#eeeeec" />
+ <stop
+ id="stop3903"
+ offset="1"
+ style="stop-color:#d3d7cf" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3907">
+ <stop
+ id="stop3909"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop3911"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient4196">
+ <stop
+ id="stop4198"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop4200"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5060">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop5062" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop5064" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient4875"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient4877"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4879"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient4881"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4883"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient4885"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient4887"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient4889"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient4891"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient4893"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient4895"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4897"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4899"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4901"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4903"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4905"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4907"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4909"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4911"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4913"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4915"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4917"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4919"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4921"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4923"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4925"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4927"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4929"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4931"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4933"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4935"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4939"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4941"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4943"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4945"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4947"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4949"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4951"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4953"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4955"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4957"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4959"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4961"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4963"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4965"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4967"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4969"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4971"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4973"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4975"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4977"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4979"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4981"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient4983"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5166"
+ id="radialGradient4985"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.465649,0,0,1.221374,-3.36641,-10.07252)"
+ cx="33"
+ cy="45.5"
+ fx="33"
+ fy="45.5"
+ r="2.046875" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5166"
+ id="radialGradient4987"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.465649,0,0,1.221374,-84.36641,-101.0725)"
+ cx="33"
+ cy="45.5"
+ fx="33"
+ fy="45.5"
+ r="2.046875" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5180"
+ id="linearGradient4989"
+ gradientUnits="userSpaceOnUse"
+ x1="39"
+ y1="48.000099"
+ x2="39"
+ y2="43" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5225"
+ id="radialGradient4991"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.24763,0,32.1168)"
+ cx="23.9375"
+ cy="42.6875"
+ fx="23.9375"
+ fy="42.6875"
+ r="23.75956" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4196"
+ id="linearGradient4993"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.654255,0,0,0.654672,-0.481383,0.690637)"
+ x1="37.484837"
+ y1="38.267769"
+ x2="37.295498"
+ y2="33.637787" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4995"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.992781,0,-2.718035)"
+ x1="31.743324"
+ y1="37.842293"
+ x2="31.86105"
+ y2="43.82579" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient11400"
+ id="linearGradient4997"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.004187,0,0,1,-0.12454,-3.011765)"
+ x1="23.154902"
+ y1="34.572548"
+ x2="23.529411"
+ y2="40.219608" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5137"
+ id="linearGradient4999"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.648248,0,0,0.644253,0.433189,-0.740991)"
+ x1="17.247635"
+ y1="6.3760414"
+ x2="39.904388"
+ y2="38.876041" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7670"
+ id="radialGradient5001"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.836315,0,0,0.514216,-4.024721,-3.259613e-2)"
+ cx="24.006104"
+ cy="32.997028"
+ fx="24.006104"
+ fy="32.997028"
+ r="19.00016" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6240"
+ id="linearGradient5003"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.664512,0,0,0.651253,9.569506e-2,-1.210023)"
+ x1="20.156862"
+ y1="5.0996137"
+ x2="20.156862"
+ y2="26.039215" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2307"
+ id="linearGradient5005"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="scale(1.673466,0.597562)"
+ x1="-931.75031"
+ y1="148.07117"
+ x2="-131.23589"
+ y2="148.07117" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5007"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5060"
+ id="radialGradient5009"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
+ cx="605.71429"
+ cy="486.64789"
+ fx="605.71429"
+ fy="486.64789"
+ r="117.14286" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3899"
+ id="linearGradient5011"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.647995,0,0,0.707655,0.734249,-1.447571)"
+ x1="29.5"
+ y1="46.029419"
+ x2="29.125"
+ y2="37.9375" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5013"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5015"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5017"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5019"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5021"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5023"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5025"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5027"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5029"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5031"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5033"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5035"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5037"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5039"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5041"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5043"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5045"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5047"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5049"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5051"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5053"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5055"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5057"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5059"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5061"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5063"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5065"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5067"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5069"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5071"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-8.729684,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5073"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5075"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5077"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5079"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5081"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5083"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5085"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,-0.72968,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5087"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5089"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5091"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5093"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5095"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5097"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3907"
+ id="radialGradient5099"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.382603,3.581398e-5,0,0.171503,4.270316,21.0972)"
+ cx="20.913568"
+ cy="47.045319"
+ fx="20.913568"
+ fy="47.045319"
+ r="19.5" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666"
+ borderopacity="1"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.383922"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false"
+ inkscape:grid-points="false"
+ showborder="true" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Network Offline</dc:title>
+ <dc:date>2005-03-08</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:source />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner, Luca Ferretti</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g4723"
+ transform="matrix(0.3375412,0,0,0.3375412,-0.2972476,-0.4385299)">
+ <g
+ transform="translate(14.98536,1)"
+ id="g5480">
+ <g
+ id="g5482"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5484"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5486"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5488" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5490" />
+ </g>
+ <g
+ id="g5492"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient4875);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5494"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5496"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4877);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5498"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5500"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient4879);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5502"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4881);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5504"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5506"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5508"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4883);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5510"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient4885);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5512"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4887);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5514"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5516"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5518">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient4889);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5520"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient4891);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5522"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5524"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient4893);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4895);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5526"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5528"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5530"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5532"
+ style="fill:url(#radialGradient4897);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5534"
+ style="fill:url(#radialGradient4899);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5536"
+ style="fill:url(#radialGradient4901);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5538"
+ style="fill:url(#radialGradient4903);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5540"
+ style="fill:url(#radialGradient4905);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5542"
+ style="fill:url(#radialGradient4907);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5544"
+ style="fill:url(#radialGradient4909);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5546"
+ style="fill:url(#radialGradient4911);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5548"
+ style="fill:url(#radialGradient4913);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5550"
+ style="fill:url(#radialGradient4915);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5552"
+ style="fill:url(#radialGradient4917);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5554"
+ style="fill:url(#radialGradient4919);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5556"
+ style="fill:url(#radialGradient4921);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5558"
+ style="fill:url(#radialGradient4923);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5560"
+ style="fill:url(#radialGradient4925);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5562"
+ style="fill:url(#radialGradient4927);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5564"
+ style="fill:url(#radialGradient4929);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5566"
+ style="fill:url(#radialGradient4931);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5568"
+ style="fill:url(#radialGradient4933);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5570"
+ style="fill:url(#radialGradient4935);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5572"
+ style="fill:url(#radialGradient4937);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5574"
+ style="fill:url(#radialGradient4939);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5576"
+ style="fill:url(#radialGradient4941);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5578"
+ style="fill:url(#radialGradient4943);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5580"
+ style="fill:url(#radialGradient4945);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5582"
+ style="fill:url(#radialGradient4947);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5584"
+ style="fill:url(#radialGradient4949);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5586"
+ style="fill:url(#radialGradient4951);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5588"
+ style="fill:url(#radialGradient4953);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5590"
+ style="fill:url(#radialGradient4955);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5592"
+ style="fill:url(#radialGradient4957);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5594"
+ style="fill:url(#radialGradient4959);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5596"
+ style="fill:url(#radialGradient4961);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5598"
+ style="fill:url(#radialGradient4963);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5600"
+ style="fill:url(#radialGradient4965);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5602"
+ style="fill:url(#radialGradient4967);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5604"
+ style="fill:url(#radialGradient4969);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5606"
+ style="fill:url(#radialGradient4971);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5608"
+ style="fill:url(#radialGradient4973);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5610"
+ style="fill:url(#radialGradient4975);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5612"
+ style="fill:url(#radialGradient4977);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5614"
+ style="fill:url(#radialGradient4979);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5616"
+ style="fill:url(#radialGradient4981);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5618"
+ style="fill:url(#radialGradient4983);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ style="opacity:0.6"
+ id="g5190">
+ <rect
+ style="opacity:1;fill:url(#radialGradient4985);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect4279"
+ width="3"
+ height="5"
+ x="45"
+ y="43" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient4987);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect5174"
+ width="3"
+ height="5"
+ x="-36"
+ y="-48"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient4989);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1"
+ id="rect5178"
+ width="9"
+ height="5"
+ x="36"
+ y="43" />
+ </g>
+ <g
+ transform="translate(0.985355,12)"
+ id="g5340">
+ <g
+ id="g5342"
+ inkscape:label="Layer 1"
+ style="display:inline" />
+ <g
+ id="g5344"
+ inkscape:label="tastiera"
+ style="display:inline">
+ <g
+ id="g5346"
+ inkscape:label="Shadow"
+ transform="translate(-54,0.18088)" />
+ <g
+ transform="translate(-54,15.24691)"
+ inkscape:label="Shadow"
+ id="g5348" />
+ <g
+ transform="translate(-54,15.24691)"
+ style="display:inline"
+ inkscape:label="Lavoro"
+ id="g5350" />
+ </g>
+ <g
+ id="layer2"
+ inkscape:label="tasti"
+ style="display:inline">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.3;fill:url(#radialGradient4991);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="path5353"
+ sodipodi:cx="23.9375"
+ sodipodi:cy="42.6875"
+ sodipodi:rx="23.75956"
+ sodipodi:ry="5.8835783"
+ d="M 47.69706,42.6875 A 23.75956,5.8835783 0 1 1 0.17794037,42.6875 A 23.75956,5.8835783 0 1 1 47.69706,42.6875 z"
+ transform="matrix(0.633479,0,0,0.565504,1.119993,0.201324)" />
+ <path
+ sodipodi:nodetypes="czz"
+ id="path5355"
+ d="M 27.082936,28.048013 C 21.663366,21.135948 31.947853,26.54939 30.855772,24.153878 C 29.785572,21.806364 17.408039,24.595241 18.709552,20.667209"
+ style="opacity:0.20786516;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4993);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#729fcf;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 26.784723,27.671888 C 21.538638,20.412631 31.520563,26.487432 30.374151,23.604157 C 29.072638,20.330797 18.198646,24.276982 18.806217,20.406815"
+ id="path5357"
+ sodipodi:nodetypes="czz" />
+ <g
+ style="display:inline"
+ id="g5359"
+ transform="matrix(0.530612,0,0,0.53095,3.140616,3.404111)">
+ <path
+ style="opacity:1;fill:url(#linearGradient4995);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.88401449;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 14.375479,32.558794 C 14.375479,32.558794 15.592355,37.45777 10.51915,37.50376 C 8.0888743,37.525507 8.5866723,41.509781 8.5866723,41.509781 L 39.433139,41.478634 C 39.433139,41.478634 39.851577,37.611393 37.410922,37.566053 C 32.423455,37.474579 33.600393,32.496503 33.600393,32.496503 L 14.375479,32.558794 z"
+ id="path5361"
+ sodipodi:nodetypes="csccscc" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient4997);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 13.926195,33.027451 C 14.010206,35.2 13.641655,35.938894 12.285731,36.702682 L 36,38 C 35.047008,36.831372 33.660837,35.066666 34.038883,33.011765 L 13.926195,33.027451 z"
+ id="path5363"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5365"
+ d="M 10.436202,38.661601 C 17.000465,38.66357 37.562637,38.661601 37.562637,38.661601"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#8d8d8f;stroke-width:1.88401508px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.43902438" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.88401532px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 11.134219,39.660187 C 17.146756,39.662156 36.881517,39.660187 36.881517,39.660187"
+ id="path5367"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <path
+ style="fill:url(#linearGradient4999);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000036;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 3.602229,1.4999996 L 28.319154,1.4999996 C 29.631932,1.4999996 30.588653,2.4197694 30.588653,3.8361498 L 30.595753,20.072828 C 30.595753,21.162945 30.253253,21.499994 29.276792,21.499994 L 2.7228402,21.487795 C 1.9583807,21.469246 1.414291,21.169109 1.404027,20.186855 L 1.4138652,3.7151949 C 1.4138652,2.572403 2.4117826,1.4999996 3.602229,1.4999996 z"
+ id="path5369"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="fill:url(#radialGradient5001);fill-opacity:1;fill-rule:evenodd;stroke:#204a87;stroke-width:0.99999958px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ id="rect5371"
+ width="25.103695"
+ height="15.194118"
+ x="3.4999971"
+ y="3.5000005" />
+ <path
+ style="opacity:0.5;fill:url(#linearGradient5003);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 4.0984042,4.0204313 L 4.0984042,15.748091 C 15.025941,14.866132 19.115514,9.1623492 28,8.5664313 L 28,4 L 4.0984042,4.0204313 z"
+ id="path5373"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;display:inline"
+ d="M 4.056094,2.4999991 C 3.2398944,2.4999991 2.4960113,3.2952856 2.4960113,4.0741096 L 2.4960108,19.789734 C 2.4999206,20.160319 2.5869303,20.275382 2.6715202,20.346431 C 2.7561101,20.417479 2.9348114,20.473541 3.2370502,20.480806 L 28.783404,20.500002 C 29.189758,20.500002 29.318189,20.437946 29.368434,20.384824 C 29.418681,20.3317 29.504941,20.138678 29.504941,19.674554 L 29.504942,4.1892884 C 29.504942,3.0791795 28.874178,2.4999991 27.866855,2.4999991 L 4.056094,2.4999991 z"
+ id="path5375"
+ sodipodi:nodetypes="cccsccscccc" />
+ <g
+ style="display:inline"
+ transform="matrix(1.543206e-2,0,0,1.215502e-2,29.57023,28.01728)"
+ id="g5377">
+ <rect
+ style="opacity:0.40206185;fill:url(#linearGradient5005);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect6709"
+ width="1339.6335"
+ height="478.35718"
+ x="-1559.2523"
+ y="-150.69685" />
+ <path
+ style="opacity:0.40206185;fill:url(#radialGradient5007);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z"
+ id="path5380"
+ sodipodi:nodetypes="cccc" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5382"
+ d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z"
+ style="opacity:0.40206185;fill:url(#radialGradient5009);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ <path
+ style="fill:url(#linearGradient5011);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:0.99999976;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 3.643761,26.504783 L 28.921938,26.504783 C 29.226374,26.504783 29.788645,26.492665 30,27 L 31.5,30 C 31.5625,30.406064 31.487026,31.562501 30,31.562501 L 2.5,31.500001 C 1,31.562501 1.0652178,30.281064 1.0652178,30 L 3,27 C 3.2113561,26.492665 3.3393239,26.504783 3.643761,26.504783 z"
+ id="path5384"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.99999964;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.0955909,27.111942 L 28.49679,27.10614 C 28.788541,27.10614 28.820868,27.10614 29.023418,27.449588 L 30.420658,30.150759 C 30.420658,30.341029 30.185782,30.494207 29.894029,30.494207 L 2.6782341,30.500011 C 2.3864818,30.500011 2.1516056,30.346832 2.1516056,30.156562 L 3.5689622,27.45539 C 3.7715117,27.111942 3.8038386,27.111942 4.0955909,27.111942 z"
+ id="path5386"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999923;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 4.9039459,26.500588 C 4.9019723,26.502459 4.9057445,26.514939 4.9039459,26.516406 C 4.89444,26.51889 4.8714034,26.528697 4.8616746,26.532224 C 4.8584281,26.533516 4.8437789,26.530815 4.840539,26.532224 C 4.8373165,26.533749 4.8225981,26.546397 4.8194034,26.548041 C 4.8130911,26.551565 4.8043634,26.559861 4.7982678,26.563859 C 4.7952901,26.565977 4.7800294,26.57744 4.7771322,26.579677 C 4.7743261,26.582033 4.7587013,26.593017 4.7559967,26.595495 C 4.7139608,26.641114 4.6696929,26.720423 4.6080475,26.816941 L 3.1646057,29.221226 C 3.1646057,29.224233 3.1644578,29.234029 3.1646057,29.237043 C 3.1648991,29.240062 3.1641691,29.249843 3.1646057,29.25286 C 3.1651831,29.255877 3.1638899,29.265668 3.1646057,29.268679 C 3.1663094,29.274683 3.1835077,29.294359 3.1857413,29.300313 C 3.1869871,29.303274 3.184369,29.31319 3.1857413,29.316132 C 3.1902312,29.324886 3.2013114,29.339269 3.2068769,29.347766 C 3.2127868,29.356161 3.2211123,29.37137 3.2280125,29.379402 C 3.230418,29.382033 3.2466397,29.392637 3.2491481,29.395219 C 3.2517571,29.39775 3.2675765,29.408562 3.2702837,29.411038 C 3.287102,29.425545 3.313719,29.446427 3.3336905,29.45849 C 3.3370984,29.460423 3.3513413,29.472456 3.3548262,29.474308 C 3.3655167,29.479116 3.3855128,29.485766 3.3970973,29.490126 C 3.4750042,29.516899 3.5780713,29.537579 3.6718601,29.537579 L 18.650036,29.537579 L 18.586629,26.500592 L 5.1153018,26.500588 C 5.0709049,26.500588 5.0221446,26.49941 4.9884883,26.500588 C 4.9806133,26.500623 4.9547729,26.500899 4.9462171,26.500588 C 4.9436075,26.500603 4.9274517,26.500458 4.9250814,26.500588 C 4.9232514,26.502034 4.9059195,26.498718 4.9039459,26.500588 z M 19.83363,26.500592 L 19.897036,27.512921 L 23.553495,27.512921 L 23.38441,26.500592 L 19.83363,26.500592 z M 24.652546,26.500592 L 25.413428,29.537579 L 28.795124,29.537579 C 28.888912,29.537579 28.991979,29.516899 29.069886,29.490126 C 29.081471,29.485766 29.101467,29.479116 29.112157,29.474308 C 29.115641,29.472456 29.129884,29.460423 29.133293,29.45849 C 29.153265,29.446427 29.179882,29.425545 29.1967,29.411038 C 29.199407,29.408562 29.215227,29.39775 29.217835,29.395219 C 29.220344,29.392637 29.236565,29.382033 29.238971,29.379402 C 29.245871,29.37137 29.254196,29.356161 29.260107,29.347766 C 29.265672,29.339269 29.276752,29.324886 29.281242,29.316132 C 29.282614,29.31319 29.279996,29.303274 29.281242,29.300313 C 29.283476,29.294359 29.300674,29.274683 29.302378,29.268679 C 29.303093,29.265668 29.3018,29.255877 29.302378,29.25286 C 29.302814,29.249843 29.302083,29.240062 29.302378,29.237043 C 29.302527,29.234029 29.302378,29.224233 29.302378,29.221226 L 28.119129,26.816941 C 28.057483,26.720424 28.013215,26.641114 27.97118,26.595495 C 27.968475,26.593017 27.95285,26.582033 27.950044,26.579677 C 27.947147,26.57744 27.931886,26.565977 27.928908,26.563859 C 27.922812,26.559861 27.914085,26.551565 27.907773,26.548041 C 27.904579,26.546397 27.88986,26.533749 27.886638,26.532224 C 27.883397,26.530815 27.868747,26.533516 27.865502,26.532224 C 27.855773,26.528697 27.832737,26.51889 27.823231,26.516406 C 27.812787,26.51452 27.796296,26.503902 27.780959,26.500588 C 27.773263,26.49907 27.745738,26.501448 27.738688,26.500588 C 27.705031,26.49941 27.656271,26.500588 27.611875,26.500588 L 24.652546,26.500592 z M 20.679054,28.525249 L 20.002715,29.537579 L 23.891664,29.537579 L 23.04624,28.525249 L 20.679054,28.525249 z"
+ id="path5388"
+ sodipodi:nodetypes="csssssssccssssssssssssccccssscccccccccssssssssssssccsssssssssccccccc" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5390"
+ style="fill:url(#radialGradient5013);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5392"
+ style="fill:url(#radialGradient5015);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5394"
+ style="fill:url(#radialGradient5017);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5396"
+ style="fill:url(#radialGradient5019);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5398"
+ style="fill:url(#radialGradient5021);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5400"
+ style="fill:url(#radialGradient5023);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5402"
+ style="fill:url(#radialGradient5025);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5404"
+ style="fill:url(#radialGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5406"
+ style="fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5408"
+ style="fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5410"
+ style="fill:url(#radialGradient5033);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5412"
+ style="fill:url(#radialGradient5035);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5414"
+ style="fill:url(#radialGradient5037);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5416"
+ style="fill:url(#radialGradient5039);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5418"
+ style="fill:url(#radialGradient5041);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="5"
+ height="1"
+ width="1"
+ id="rect5420"
+ style="fill:url(#radialGradient5043);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="7"
+ height="1"
+ width="1"
+ id="rect5422"
+ style="fill:url(#radialGradient5045);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="9"
+ height="1"
+ width="1"
+ id="rect5424"
+ style="fill:url(#radialGradient5047);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="11"
+ height="1"
+ width="1"
+ id="rect5426"
+ style="fill:url(#radialGradient5049);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="13"
+ height="1"
+ width="1"
+ id="rect5428"
+ style="fill:url(#radialGradient5051);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="15"
+ height="1"
+ width="1"
+ id="rect5430"
+ style="fill:url(#radialGradient5053);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="17"
+ height="1"
+ width="1"
+ id="rect5432"
+ style="fill:url(#radialGradient5055);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="4"
+ height="1"
+ width="1"
+ id="rect5434"
+ style="fill:url(#radialGradient5057);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="6"
+ height="1"
+ width="1"
+ id="rect5436"
+ style="fill:url(#radialGradient5059);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="8"
+ height="1"
+ width="1"
+ id="rect5438"
+ style="fill:url(#radialGradient5061);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="10"
+ height="1"
+ width="1"
+ id="rect5440"
+ style="fill:url(#radialGradient5063);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="12"
+ height="1"
+ width="1"
+ id="rect5442"
+ style="fill:url(#radialGradient5065);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="14"
+ height="1"
+ width="1"
+ id="rect5444"
+ style="fill:url(#radialGradient5067);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="16"
+ height="1"
+ width="1"
+ id="rect5446"
+ style="fill:url(#radialGradient5069);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="18"
+ height="1"
+ width="1"
+ id="rect5448"
+ style="fill:url(#radialGradient5071);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5450"
+ style="fill:url(#radialGradient5073);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5452"
+ style="fill:url(#radialGradient5075);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5454"
+ style="fill:url(#radialGradient5077);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="21"
+ height="1"
+ width="1"
+ id="rect5456"
+ style="fill:url(#radialGradient5079);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="23"
+ height="1"
+ width="1"
+ id="rect5458"
+ style="fill:url(#radialGradient5081);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="20"
+ height="1"
+ width="1"
+ id="rect5460"
+ style="fill:url(#radialGradient5083);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="22"
+ height="1"
+ width="1"
+ id="rect5462"
+ style="fill:url(#radialGradient5085);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="26"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5464"
+ style="fill:url(#radialGradient5087);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5466"
+ style="fill:url(#radialGradient5089);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="27"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5468"
+ style="fill:url(#radialGradient5091);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="26"
+ height="1"
+ width="1"
+ id="rect5470"
+ style="fill:url(#radialGradient5093);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="28"
+ x="28"
+ height="1"
+ width="1"
+ id="rect5472"
+ style="fill:url(#radialGradient5095);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="25"
+ height="1"
+ width="1"
+ id="rect5474"
+ style="fill:url(#radialGradient5097);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.26516503"
+ rx="0.26516503"
+ y="29"
+ x="27"
+ height="1"
+ width="1"
+ id="rect5476"
+ style="fill:url(#radialGradient5099);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ <g
+ transform="translate(5,18)"
+ style="display:inline"
+ inkscape:label="Muted"
+ id="layer4">
+ <g
+ transform="translate(-2,0)"
+ id="g4694">
+ <rect
+ style="opacity:1;fill:#ef2929;fill-opacity:1;stroke:#cc0000;stroke-width:0.9964897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;display:inline"
+ id="rect2021"
+ width="12.00351"
+ height="12.00351"
+ x="31.498245"
+ y="16.498245"
+ rx="1.4868355"
+ ry="1.4868355" />
+ <rect
+ style="opacity:0.3;fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:1.20000057;stroke-opacity:1;display:inline"
+ id="rect3795"
+ width="9.9999962"
+ height="9.9999962"
+ x="32.5"
+ y="17.500002"
+ rx="0.4861359"
+ ry="0.4861359" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 35,20 L 40,25"
+ id="path4682"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline"
+ d="M 40,20 L 35,25"
+ id="path4684"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/document.svg b/emacs.d/lisp/rudel/icons/document.svg
new file mode 100644
index 0000000..aa5163c
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/document.svg
@@ -0,0 +1,608 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ inkscape:export-ydpi="240.00000"
+ inkscape:export-xdpi="240.00000"
+ inkscape:export-filename="/home/lapo/text.png"
+ sodipodi:docname="document.svg"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/mimetypes"
+ inkscape:version="0.46"
+ sodipodi:version="0.32"
+ id="svg249"
+ height="16"
+ width="16"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 8 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="16 : 8 : 1"
+ inkscape:persp3d-origin="8 : 5.3333333 : 1"
+ id="perspective80" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3656"
+ id="linearGradient5816"
+ gradientUnits="userSpaceOnUse"
+ x1="-26.753757"
+ y1="11.566258"
+ x2="-24.75"
+ y2="9.687501" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3520"
+ id="linearGradient5836"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.9223058,0,0,0.9185751,-92.447368,61.3257)"
+ x1="-18.588562"
+ y1="11.052948"
+ x2="-28.789402"
+ y2="14.069944" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3671"
+ id="radialGradient5839"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.4073362,-0.2798276,0.7510293,1.0932492,-115.18484,51.56213)"
+ cx="-26.305403"
+ cy="10.108011"
+ fx="-26.305403"
+ fy="10.108011"
+ r="7.0421038" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient6469">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop6471" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop6473" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6469"
+ id="linearGradient6475"
+ x1="58.282169"
+ y1="70.751839"
+ x2="61.181217"
+ y2="67.799171"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-180,0)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3741"
+ id="radialGradient5810"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8860258,0,0,1.1764706,-3.5441033,-4.2352941)"
+ cx="4"
+ cy="5.2999997"
+ fx="4"
+ fy="5.2999997"
+ r="17" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3613"
+ id="linearGradient5845"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-90,60)"
+ x1="-47.5"
+ y1="49.020683"
+ x2="-62.75"
+ y2="-22.502075" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3683"
+ id="radialGradient5843"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.9957492,0,0,1.9350367,0.62141,28.832578)"
+ cx="-30.249996"
+ cy="35.357208"
+ fx="-30.249996"
+ fy="35.357208"
+ r="18.000002" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3702"
+ id="linearGradient5804"
+ gradientUnits="userSpaceOnUse"
+ x1="25.058096"
+ y1="47.027729"
+ x2="25.058096"
+ y2="39.999443" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5802"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5800"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3702"
+ id="linearGradient5798"
+ gradientUnits="userSpaceOnUse"
+ x1="25.058096"
+ y1="47.027729"
+ x2="25.058096"
+ y2="39.999443" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5796"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,-20.01187,-104.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3688"
+ id="radialGradient5794"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.003784,0,0,1.4,27.98813,-17.4)"
+ cx="4.9929786"
+ cy="43.5"
+ fx="4.9929786"
+ fy="43.5"
+ r="2.5" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3656">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3658" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3660" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3520">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.41295547"
+ offset="0"
+ id="stop3522" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3524" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3671">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3673" />
+ <stop
+ id="stop3691"
+ offset="0.47533694"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3675" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3741">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3743" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop3745" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3613">
+ <stop
+ style="stop-color:#888a85;stop-opacity:1"
+ offset="0"
+ id="stop3615" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3617" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3683">
+ <stop
+ id="stop3685"
+ offset="0"
+ style="stop-color:#f6f6f5;stop-opacity:1;" />
+ <stop
+ id="stop3689"
+ offset="1"
+ style="stop-color:#d3d7cf;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3688"
+ inkscape:collect="always">
+ <stop
+ id="stop3690"
+ offset="0"
+ style="stop-color:black;stop-opacity:1;" />
+ <stop
+ id="stop3692"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3702">
+ <stop
+ id="stop3704"
+ offset="0"
+ style="stop-color:black;stop-opacity:0;" />
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0.5"
+ id="stop3710" />
+ <stop
+ id="stop3706"
+ offset="1"
+ style="stop-color:black;stop-opacity:0;" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ inkscape:window-y="125"
+ inkscape:window-x="60"
+ inkscape:window-height="872"
+ inkscape:window-width="1048"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ showgrid="false"
+ inkscape:current-layer="layer6"
+ inkscape:cy="6.5182375"
+ inkscape:cx="1.1981567"
+ inkscape:zoom="27.125"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ borderopacity="0.25490196"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Generic Text</dc:title>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>text</rdf:li>
+ <rdf:li>plaintext</rdf:li>
+ <rdf:li>regular</rdf:li>
+ <rdf:li>document</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source />
+ <dc:date />
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:publisher>
+ <dc:identifier />
+ <dc:relation />
+ <dc:language />
+ <dc:coverage />
+ <dc:description />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer6"
+ inkscape:label="Shadow">
+ <g
+ style="display:inline"
+ id="g6015"
+ transform="matrix(0.3302612,0,0,0.3302612,49.612911,-19.741941)">
+ <rect
+ y="60"
+ x="-150"
+ height="48"
+ width="48"
+ id="rect5504"
+ style="opacity:0;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;display:inline" />
+ <g
+ transform="matrix(1.0464281,0,0,0.8888889,-151.18572,65.72224)"
+ inkscape:label="Shadow"
+ id="g5508"
+ style="opacity:0.65587045;display:inline">
+ <g
+ transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)"
+ style="opacity:0.4"
+ id="g5511">
+ <rect
+ style="opacity:1;fill:url(#radialGradient5794);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5513"
+ width="5"
+ height="7"
+ x="38"
+ y="40" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient5796);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5515"
+ width="5"
+ height="7"
+ x="-10"
+ y="-47"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient5798);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5517"
+ width="28"
+ height="7.0000005"
+ x="10"
+ y="40" />
+ </g>
+ </g>
+ <g
+ transform="matrix(0.9548466,0,0,0.5555562,-148.98776,79.888875)"
+ inkscape:label="Shadow"
+ id="g5519"
+ style="display:inline">
+ <g
+ transform="matrix(1.052632,0,0,1.285713,-1.263158,-13.42854)"
+ style="opacity:0.4"
+ id="g5521">
+ <rect
+ style="opacity:1;fill:url(#radialGradient5800);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5523"
+ width="5"
+ height="7"
+ x="38"
+ y="40" />
+ <rect
+ style="opacity:1;fill:url(#radialGradient5802);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5525"
+ width="5"
+ height="7"
+ x="-10"
+ y="-47"
+ transform="scale(-1,-1)" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient5804);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect5527"
+ width="28"
+ height="7.0000005"
+ x="10"
+ y="40" />
+ </g>
+ </g>
+ <path
+ sodipodi:nodetypes="ccsccccccc"
+ id="path5529"
+ d="M -141.47614,63.5 C -141.47614,63.5 -124,63.5 -122.5,63.5 C -118.62295,63.572942 -116,66 -113.5,68.5 C -111,71 -108.89232,73.752625 -108.5,77.5 C -108.5,79 -108.5,102.47614 -108.5,102.47614 C -108.5,103.59736 -109.40264,104.5 -110.52385,104.5 L -141.47614,104.5 C -142.59736,104.5 -143.5,103.59736 -143.5,102.47614 L -143.5,65.523858 C -143.5,64.402641 -142.59736,63.5 -141.47614,63.5 z"
+ style="fill:url(#radialGradient5843);fill-opacity:1;stroke:url(#linearGradient5845);stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ transform="translate(-150,60)"
+ d="M 8.53125,4 C 7.6730803,4 7,4.6730802 7,5.53125 L 7,42.46875 C 7,43.32692 7.6730802,44 8.53125,44 L 39.46875,44 C 40.326919,44 41,43.326918 41,42.46875 C 41,42.46875 41,19 41,17.5 C 41,16.10803 40.513021,13.200521 38.65625,11.34375 C 36.65625,9.34375 35.65625,8.34375 33.65625,6.34375 C 31.799479,4.4869792 28.89197,4 27.5,4 C 26,4 8.53125,4 8.53125,4 z"
+ id="path5531"
+ style="opacity:0.68016196;fill:url(#radialGradient5810);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline"
+ inkscape:original="M 8.53125 3.5 C 7.410033 3.5 6.5 4.4100329 6.5 5.53125 L 6.5 42.46875 C 6.5 43.589967 7.4100329 44.5 8.53125 44.5 L 39.46875 44.5 C 40.589967 44.5 41.5 43.589966 41.5 42.46875 C 41.5 42.46875 41.5 19 41.5 17.5 C 41.5 16 41 13 39 11 C 37 9 36 8 34 6 C 32 4 29 3.5 27.5 3.5 C 26 3.5 8.5312499 3.5 8.53125 3.5 z "
+ inkscape:radius="-0.4861359"
+ sodipodi:type="inkscape:offset" />
+ <path
+ id="rect5857"
+ d="M -138.59375,69.125 C -138.81243,69.125 -139,69.312565 -139,69.53125 C -139,69.749934 -138.81243,69.937499 -138.59375,69.9375 L -117.40625,69.9375 C -117.18757,69.9375 -117,69.749934 -117,69.53125 C -117,69.312566 -117.18757,69.125 -117.40625,69.125 L -138.59375,69.125 z M -138.53125,71.0625 C -138.79094,71.0625 -139,71.271563 -139,71.53125 C -139,71.790937 -138.79094,72 -138.53125,72 L -116.46875,72 C -116.20906,72 -116,71.790937 -116,71.53125 C -116,71.271563 -116.20906,71.0625 -116.46875,71.0625 L -138.53125,71.0625 z M -138.53125,73.0625 C -138.79094,73.0625 -139,73.271563 -139,73.53125 C -139,73.790937 -138.79094,74 -138.53125,74 L -113.34375,74 C -113.08406,74 -112.875,73.790937 -112.875,73.53125 C -112.875,73.271563 -113.08406,73.0625 -113.34375,73.0625 L -138.53125,73.0625 z M -138.53125,75.0625 C -138.79094,75.0625 -139,75.271563 -139,75.53125 C -139,75.790937 -138.79094,76 -138.53125,76 L -113.34375,76 C -113.08406,76 -112.875,75.790937 -112.875,75.53125 C -112.875,75.271563 -113.08406,75.0625 -113.34375,75.0625 L -138.53125,75.0625 z M -138.53125,77.0625 C -138.79094,77.0625 -139,77.271563 -139,77.53125 C -139,77.790937 -138.79094,78 -138.53125,78 L -113.34375,78 C -113.08406,78 -112.875,77.790937 -112.875,77.53125 C -112.875,77.271563 -113.08406,77.0625 -113.34375,77.0625 L -138.53125,77.0625 z"
+ style="opacity:0.15;fill:url(#linearGradient6475);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ sodipodi:nodetypes="ccccczc"
+ id="path5533"
+ d="M -122.5,64 C -123.88889,64 -122.54207,64.497088 -121.15625,65.125 C -119.77043,65.752912 -116.18337,68.340052 -117,72 C -112.67669,71.569417 -110.32087,75.122378 -110,76.28125 C -109.67913,77.440122 -109,78.888889 -109,77.5 C -108.97167,73.694419 -111.84543,71.068299 -113.84375,68.84375 C -115.84207,66.619201 -118.84621,64.476761 -122.5,64 z"
+ style="fill:url(#radialGradient5839);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path5535"
+ d="M -121.39912,65.014353 C -120.47682,65.014353 -118.39068,71.210015 -119.31298,75.343603 C -115.01802,74.915844 -110.4596,75.43178 -110,76.28125 C -110.32087,75.122378 -112.67669,71.569417 -117,72 C -116.13534,68.124761 -120.18657,65.382702 -121.39912,65.014353 z"
+ style="opacity:0.87854249;fill:url(#linearGradient5836);fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;display:inline" />
+ <path
+ transform="translate(-90,60)"
+ d="M -51.46875,4.5 C -52.051916,4.5 -52.5,4.9480842 -52.5,5.53125 L -52.5,42.46875 C -52.5,43.051915 -52.051914,43.5 -51.46875,43.5 L -20.53125,43.5 C -19.948085,43.5 -19.5,43.051914 -19.5,42.46875 C -19.5,42.46875 -19.5,19 -19.5,17.5 C -19.5,16.220971 -19.980469,13.394531 -21.6875,11.6875 C -23.6875,9.6875 -24.6875,8.6875 -26.6875,6.6875 C -28.394531,4.9804687 -31.220971,4.5 -32.5,4.5 C -34,4.5 -51.46875,4.5 -51.46875,4.5 z"
+ id="path5537"
+ style="fill:none;fill-opacity:1;stroke:url(#linearGradient5816);stroke-width:1;stroke-miterlimit:4;display:inline"
+ inkscape:original="M -51.46875 3.5 C -52.589967 3.5 -53.5 4.4100329 -53.5 5.53125 L -53.5 42.46875 C -53.5 43.589967 -52.589966 44.5 -51.46875 44.5 L -20.53125 44.5 C -19.410033 44.5 -18.5 43.589966 -18.5 42.46875 C -18.5 42.46875 -18.5 19 -18.5 17.5 C -18.5 16 -19 13 -21 11 C -23 9 -24 8 -26 6 C -28 4 -31 3.5 -32.5 3.5 C -34 3.5 -51.468749 3.5 -51.46875 3.5 z "
+ inkscape:radius="-0.99436891"
+ sodipodi:type="inkscape:offset" />
+ <g
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ transform="matrix(0.928889,0,0,1,-148.28889,60)"
+ style="opacity:0.15;fill:#000000;display:inline"
+ id="g5539">
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="19.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5549"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5553"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="21.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5555"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="23.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="25.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5557"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="27.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5559"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5561"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="29.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect5563"
+ width="28.125"
+ height="0.9375"
+ x="10"
+ y="31.0625"
+ inkscape:r_cx="true"
+ inkscape:r_cy="true"
+ rx="0.50463516"
+ ry="0.46875" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="33.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5565"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="35.0625"
+ x="10"
+ height="0.9375"
+ width="28.125"
+ id="rect5567"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ ry="0.46875"
+ rx="0.50463516"
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ y="37.0625"
+ x="10"
+ height="0.9375"
+ width="13.8125"
+ id="rect5569"
+ style="opacity:1;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.99999982px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+ </g>
+ <g
+ style="display:inline"
+ inkscape:groupmode="layer"
+ inkscape:label="Base"
+ id="layer1" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="Text"
+ style="display:inline" />
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/encrypted.svg b/emacs.d/lisp/rudel/icons/encrypted.svg
new file mode 100644
index 0000000..8c32cc6
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/encrypted.svg
@@ -0,0 +1,902 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg12360"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/data/Desktop/icons/scaleable"
+ sodipodi:docname="encrypted.svg"
+ inkscape:export-filename="/data/Desktop/icons/scaleable/seahorse-applet-encrypted.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs12362">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective3757" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2259">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2261" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2263" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2251">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2253" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2255" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2239">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2241" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2243" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2224">
+ <stop
+ style="stop-color:#7c7c7c;stop-opacity:1;"
+ offset="0"
+ id="stop2226" />
+ <stop
+ style="stop-color:#b8b8b8;stop-opacity:1;"
+ offset="1"
+ id="stop2228" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2216">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2218" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2220" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15234">
+ <stop
+ style="stop-color:#97978a;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15236" />
+ <stop
+ id="stop15242"
+ offset="0.50000000"
+ style="stop-color:#c2c2b9;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#7d7d6f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15238" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15218">
+ <stop
+ style="stop-color:#f0f0ef;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15220" />
+ <stop
+ id="stop2269"
+ offset="0.59928656"
+ style="stop-color:#e8e8e8;stop-opacity:1;" />
+ <stop
+ id="stop2267"
+ offset="0.82758623"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d8d8d3;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15222" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14484">
+ <stop
+ style="stop-color:#c68827;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop14486" />
+ <stop
+ style="stop-color:#89601f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop14488" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient13746">
+ <stop
+ style="stop-color:#646459;stop-opacity:1;"
+ offset="0"
+ id="stop13748" />
+ <stop
+ style="stop-color:#646459;stop-opacity:0;"
+ offset="1"
+ id="stop13750" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient13746"
+ id="radialGradient13752"
+ cx="24.647722"
+ cy="45.272587"
+ fx="24.647722"
+ fy="45.272587"
+ r="21.011173"
+ gradientTransform="matrix(1,0,0,0.110577,0,40.26648)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14484"
+ id="linearGradient14490"
+ x1="6.1071744"
+ y1="10.45129"
+ x2="33.857143"
+ y2="37.87986"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15218"
+ id="linearGradient15224"
+ x1="22.308331"
+ y1="18.99214"
+ x2="35.785294"
+ y2="39.498238"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.065698,0,0,0.987595,-1.564439,7.487332e-2)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient15240"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.052632,0,0,1,-1.789474,0)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2216"
+ id="linearGradient2222"
+ x1="36.8125"
+ y1="39.15625"
+ x2="39.0625"
+ y2="42.0625"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2224"
+ id="linearGradient2230"
+ x1="35.996582"
+ y1="40.458221"
+ x2="33.664921"
+ y2="37.770721"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient2245"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2251"
+ id="linearGradient2257"
+ x1="33.396004"
+ y1="36.921333"
+ x2="34.170048"
+ y2="38.070381"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2259"
+ id="linearGradient2265"
+ x1="26.076092"
+ y1="26.696676"
+ x2="30.811172"
+ y2="42.007351"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient2283"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.538743,0,0,0.511806,10.8008,-0.58264)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.404572"
+ y2="6.481061" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient2287"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.005222,0,0,0.883928,-0.627923,0.84375)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ y2="14.259961"
+ x2="11.779029"
+ y1="20.579729"
+ x1="11.5"
+ gradientTransform="matrix(0.980472,0,0,0.490236,34.67523,22.83397)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1898"
+ xlink:href="#linearGradient12071"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="3.9566603"
+ x2="17.859085"
+ y1="6.8795347"
+ x1="14.217941"
+ gradientTransform="matrix(0.980472,0,0,0.461806,23.89003,23.47875)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1896"
+ xlink:href="#linearGradient12071"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="36.127281"
+ x2="30.875446"
+ y1="25.002281"
+ x1="10.907269"
+ gradientTransform="matrix(0.453445,0,0,0.470026,30.17248,24.3894)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1894"
+ xlink:href="#linearGradient9845"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="25.793524"
+ x2="8.6713638"
+ y1="41.791817"
+ x1="31.630468"
+ gradientTransform="matrix(0.490236,0,0,0.534297,29.28263,22.22637)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1892"
+ xlink:href="#linearGradient11327"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="32.161697"
+ x2="40.938126"
+ y1="32.161697"
+ x1="6.72682"
+ gradientTransform="matrix(0.490236,0,0,0.534297,29.28263,21.67589)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1890"
+ xlink:href="#linearGradient2092"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="6.0396547"
+ x2="16.198252"
+ y1="9.6635771"
+ x1="19.250618"
+ gradientTransform="matrix(0.480246,0,0,0.497322,29.22711,23.01153)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1888"
+ xlink:href="#linearGradient11335"
+ inkscape:collect="always" />
+ <linearGradient
+ y2="18.414022"
+ x2="20.087339"
+ y1="4.3602757"
+ x1="12.88666"
+ gradientTransform="matrix(0.480246,0,0,0.497322,29.22711,23.01153)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient1886"
+ xlink:href="#linearGradient10591"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2329"
+ id="linearGradient2337"
+ x1="-35.122688"
+ y1="34.242237"
+ x2="-35.074745"
+ y2="30.962345"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2321"
+ id="linearGradient2327"
+ x1="-35.658386"
+ y1="33.416473"
+ x2="-35.658386"
+ y2="28.205938"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2253"
+ id="linearGradient1561"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.104397,0,0,0.905471,4.5,2.875)"
+ x1="10.390738"
+ y1="5.3817744"
+ x2="32.536823"
+ y2="31.246054" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2733"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2729"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2725"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2721"
+ gradientUnits="userSpaceOnUse"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2711"
+ id="linearGradient2717"
+ x1="34.300991"
+ y1="3.9384086"
+ x2="35.520542"
+ y2="3.8451097"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2701"
+ id="linearGradient2707"
+ gradientTransform="matrix(1.816345,0,0,1.278927,2.5,-40.24508)"
+ x1="12.206709"
+ y1="53.535141"
+ x2="12.127711"
+ y2="64.892525"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2683"
+ id="linearGradient2689"
+ gradientTransform="matrix(5.705159,0,0,0.17528,5.5,2.195627)"
+ x1="3.7069976"
+ y1="171.29134"
+ x2="3.7069974"
+ y2="162.45061"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2675"
+ id="linearGradient2681"
+ gradientTransform="matrix(1.174139,0,0,0.945431,5.221825,1.543476)"
+ x1="19.150396"
+ y1="32.622238"
+ x2="16.315819"
+ y2="8.8666229"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2667"
+ id="linearGradient2673"
+ gradientTransform="matrix(1.238977,0,0,0.895955,5.090553,1.543476)"
+ x1="11.492236"
+ y1="1.6537577"
+ x2="17.199417"
+ y2="26.729263"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ gradientUnits="userSpaceOnUse"
+ r="8.7662792"
+ fy="67.501709"
+ fx="12.57571"
+ cy="67.501709"
+ cx="12.57571"
+ gradientTransform="scale(1.925808,0.519262)"
+ id="radialGradient2460"
+ xlink:href="#linearGradient2454"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="55.200756"
+ x2="34.974548"
+ y1="13.004725"
+ x1="17.698339"
+ gradientTransform="matrix(1.108069,0,0,0.902471,5.5,3.875)"
+ id="linearGradient2421"
+ xlink:href="#linearGradient2415"
+ inkscape:collect="always" />
+ <linearGradient
+ gradientUnits="userSpaceOnUse"
+ y2="33.339787"
+ x2="34.784473"
+ y1="7.2293582"
+ x1="8.6116238"
+ gradientTransform="matrix(1.129863,0,0,0.885063,2.875,1.570628)"
+ id="linearGradient1506"
+ xlink:href="#linearGradient2245"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient1502">
+ <stop
+ id="stop2247"
+ offset="0.0000000"
+ style="stop-color:#dde1d9;stop-opacity:1.0000000;" />
+ <stop
+ id="stop2249"
+ offset="1.0000000"
+ style="stop-color:#cacdc6;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2253">
+ <stop
+ id="stop1499"
+ offset="0.0000000"
+ style="stop-color:#8f8f8f;stop-opacity:1.0000000;" />
+ <stop
+ id="stop2257"
+ offset="1.0000000"
+ style="stop-color:#494949;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2415"
+ inkscape:collect="always">
+ <stop
+ id="stop2417"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop2419"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2454"
+ inkscape:collect="always">
+ <stop
+ id="stop2456"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:1;" />
+ <stop
+ id="stop2458"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2667">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2669" />
+ <stop
+ style="stop-color:#fcfcff;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2671" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2675">
+ <stop
+ style="stop-color:#5b5b97;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2677" />
+ <stop
+ style="stop-color:#1b1b43;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2679" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2683">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2685" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2687" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2701">
+ <stop
+ style="stop-color:#585956;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2703" />
+ <stop
+ style="stop-color:#bbbeb8;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop2705" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2711">
+ <stop
+ style="stop-color:#909090;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2713" />
+ <stop
+ style="stop-color:#bebebe;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2715" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2321">
+ <stop
+ style="stop-color:#7b7f7a;stop-opacity:1;"
+ offset="0"
+ id="stop2323" />
+ <stop
+ style="stop-color:#7b7f7a;stop-opacity:0;"
+ offset="1"
+ id="stop2325" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2329">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop2331" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop2333" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient10591">
+ <stop
+ id="stop10593"
+ offset="0.0000000"
+ style="stop-color:#cad0c6;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#eaece9;stop-opacity:1.0000000;"
+ offset="0.50000000"
+ id="stop10599" />
+ <stop
+ id="stop10595"
+ offset="1.0000000"
+ style="stop-color:#c5cbc0;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11335">
+ <stop
+ id="stop11337"
+ offset="0"
+ style="stop-color:#6f716d;stop-opacity:1;" />
+ <stop
+ id="stop11339"
+ offset="1.0000000"
+ style="stop-color:#9ea09c;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2092">
+ <stop
+ style="stop-color:#fff7b0;stop-opacity:1;"
+ offset="0"
+ id="stop2094" />
+ <stop
+ id="stop2098"
+ offset="0.20999999"
+ style="stop-color:#ffec41;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#e2cc00;stop-opacity:1;"
+ offset="0.83999997"
+ id="stop2293" />
+ <stop
+ style="stop-color:#c3af00;stop-opacity:1;"
+ offset="1"
+ id="stop2100" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient11327">
+ <stop
+ id="stop11329"
+ offset="0"
+ style="stop-color:#7d6400;stop-opacity:1;" />
+ <stop
+ id="stop11331"
+ offset="1.0000000"
+ style="stop-color:#be9700;stop-opacity:1.0000000;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient9845">
+ <stop
+ id="stop9847"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop9849"
+ offset="1.0000000"
+ style="stop-color:#ffffff;stop-opacity:0.49484536;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient12071"
+ inkscape:collect="always">
+ <stop
+ id="stop12073"
+ offset="0"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ id="stop12075"
+ offset="1"
+ style="stop-color:#ffffff;stop-opacity:0;" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient3781"
+ gradientUnits="userSpaceOnUse"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.61960784"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="6.605754"
+ inkscape:cy="13.296835"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata12365">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Edit Paste</dc:title>
+ <dc:date>2005-10-10</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>paste</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g3759"
+ transform="matrix(0.3282573,0,0,0.3282573,-3.6446223e-2,0.2924263)">
+ <rect
+ ry="1.3879364"
+ rx="1.3879371"
+ y="4.5"
+ x="4.4643173"
+ height="41.045437"
+ width="39.035683"
+ id="rect12368"
+ style="opacity:1;fill:url(#linearGradient14490);fill-opacity:1;fill-rule:evenodd;stroke:#714c16;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.56650835"
+ rx="0.56650835"
+ y="6.5295157"
+ x="8.5323219"
+ height="35.976688"
+ width="30.951559"
+ id="rect12413"
+ style="opacity:1;fill:url(#linearGradient15224);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.98387533"
+ rx="0.98387533"
+ y="0"
+ x="18"
+ height="4"
+ width="12"
+ id="rect13756"
+ style="opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="7.4665856"
+ x="9.5171413"
+ height="34.040764"
+ width="29.014147"
+ id="rect15244"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2265);stroke-width:1.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.47879848"
+ rx="0.47879848"
+ y="5.4307775"
+ x="5.4393425"
+ height="39.092987"
+ width="37.085655"
+ id="rect15974"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c68827;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ style="opacity:0.10795456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2208"
+ width="18.947376"
+ height="7"
+ x="14.791488"
+ y="4.4722719"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient15240);fill-opacity:1;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2285"
+ width="18.947376"
+ height="7"
+ x="14.526322"
+ y="3.5"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient2283);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2281"
+ width="9.6973763"
+ height="3.5826404"
+ x="19.151323"
+ y="1.2086792"
+ rx="0.32543635"
+ ry="0.32543635" />
+ <rect
+ ry="1.0129364"
+ rx="1.0129364"
+ y="3.9375"
+ x="14.953014"
+ height="6.1875"
+ width="18.093992"
+ id="rect13754"
+ style="opacity:1;fill:url(#linearGradient2287);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2212"
+ d="M 39.018306,36.25 L 39.0625,42.0625 L 30.5625,42.018306 L 39.018306,36.25 z"
+ style="opacity:0.48863639;fill:url(#linearGradient2222);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ id="rect2232"
+ d="M 19.46875,1.46875 C 19.466654,1.4708456 19.470414,1.4975336 19.46875,1.5 C 19.46758,1.502776 19.438116,1.4969757 19.4375,1.5 L 19.4375,4.375 C 19.4375,4.3814229 19.46641,4.4006981 19.46875,4.40625 C 19.471216,4.4079135 19.465974,4.4363298 19.46875,4.4375 L 15.9375,4.4375 C 15.91974,4.4375 15.892285,4.4357551 15.875,4.4375 C 15.840968,4.4426713 15.781454,4.4572762 15.75,4.46875 C 15.611832,4.5269964 15.482328,4.6677699 15.4375,4.8125 C 15.426991,4.8535348 15.4375,4.9243489 15.4375,4.96875 L 15.4375,9.125 C 15.4375,9.1427605 15.435755,9.1702147 15.4375,9.1875 C 15.442671,9.2215321 15.457276,9.2810456 15.46875,9.3125 C 15.478458,9.3355281 15.487176,9.3851004 15.5,9.40625 C 15.5046,9.41307 15.526336,9.4309205 15.53125,9.4375 C 15.552124,9.4628138 15.599686,9.5103764 15.625,9.53125 C 15.638159,9.5410789 15.6734,9.5539504 15.6875,9.5625 C 15.702038,9.5703781 15.734648,9.5872782 15.75,9.59375 C 15.781454,9.6052238 15.840968,9.6198287 15.875,9.625 C 15.892285,9.6267449 15.91974,9.625 15.9375,9.625 L 32.0625,9.625 C 32.08026,9.625 32.107715,9.6267449 32.125,9.625 C 32.159032,9.6198287 32.218546,9.6052238 32.25,9.59375 C 32.265352,9.5872782 32.297962,9.5703781 32.3125,9.5625 C 32.3266,9.5539504 32.361841,9.5410789 32.375,9.53125 C 32.400314,9.5103764 32.447876,9.4628138 32.46875,9.4375 C 32.473664,9.4309205 32.4954,9.41307 32.5,9.40625 C 32.512824,9.3851004 32.521542,9.3355281 32.53125,9.3125 C 32.542724,9.2810456 32.557329,9.2215321 32.5625,9.1875 C 32.564245,9.1702147 32.5625,9.1427605 32.5625,9.125 L 32.5625,4.96875 C 32.5625,4.9243489 32.573009,4.8535348 32.5625,4.8125 C 32.517672,4.6677698 32.388168,4.5269964 32.25,4.46875 C 32.218546,4.4572762 32.159032,4.4426713 32.125,4.4375 C 32.107715,4.4357551 32.08026,4.4375 32.0625,4.4375 L 28.53125,4.4375 C 28.534026,4.4363298 28.528784,4.4079135 28.53125,4.40625 C 28.533591,4.4006981 28.5625,4.3814229 28.5625,4.375 L 28.5625,1.5 C 28.561884,1.4969757 28.53242,1.502776 28.53125,1.5 C 28.529586,1.4975336 28.533346,1.4708456 28.53125,1.46875 C 28.528474,1.4675798 28.503024,1.4693657 28.5,1.46875 L 19.5,1.46875 C 19.496976,1.4693657 19.471526,1.4675798 19.46875,1.46875 z"
+ style="opacity:0.31681818;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3781);stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2210"
+ d="M 30.059082,42.086864 C 31.850223,42.254516 39.048809,37.717278 39.539922,33.698855 C 37.97666,36.121952 34.584971,35.667446 30.476213,35.826456 C 30.476213,35.826456 30.871582,41.586864 30.059082,42.086864 z"
+ style="opacity:1;fill:url(#linearGradient2230);fill-opacity:1;fill-rule:evenodd;stroke:#868a84;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.36931817;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2257);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 31.509519,40.68705 C 32.879298,40.003221 36.038783,38.086016 37.338164,36.205012 C 35.545641,36.581496 34.347243,36.794585 31.610576,36.900494 C 31.610576,36.900494 31.697137,39.91208 31.509519,40.68705 z"
+ id="path2247"
+ sodipodi:nodetypes="cccc" />
+ <g
+ transform="matrix(1.631663,0,0,1.631663,-7.203818,2.952894)"
+ id="g1529"
+ inkscape:label="Layer 1">
+ <g
+ id="g1879"
+ transform="matrix(0.844217,0,0,0.844217,-10.3995,-12.36372)">
+ <path
+ sodipodi:nodetypes="cczcccczccc"
+ id="path2086"
+ d="M 34.238513,34.181365 L 34.238513,30.359668 C 34.238513,26.445675 36.861875,24.661287 40.762635,24.710167 C 44.684619,24.759046 47.274012,26.461946 47.274012,30.421985 L 47.267528,34.181365 L 44.874632,34.181365 L 44.874632,31.406199 C 44.810387,30.442875 45.141632,27.216102 40.790111,27.216102 C 36.408575,27.216102 36.666117,30.454534 36.681818,31.425378 L 36.681818,34.181365 L 34.238513,34.181365 z"
+ style="fill:url(#linearGradient1886);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1888);stroke-width:1.1845268;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <rect
+ ry="2.3033772"
+ rx="2.6473897"
+ y="34.231865"
+ x="32.468109"
+ height="11.769073"
+ width="17.156261"
+ id="rect1314"
+ style="fill:url(#linearGradient1890);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1892);stroke-width:1.18452692;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="1.4387805"
+ rx="1.4387794"
+ y="35.387321"
+ x="33.559612"
+ height="9.4392996"
+ width="14.977587"
+ id="rect6903"
+ style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient1894);stroke-width:1.18452799;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.60109289" />
+ <path
+ sodipodi:nodetypes="ccsccc"
+ id="rect11343"
+ d="M 34.675226,30.571517 C 34.805219,27.673419 35.610937,25.490973 40.985429,25.305958 C 37.505396,25.7964 35.612515,26.812487 35.612515,29.842371 C 35.612515,29.842371 35.525705,33.597665 35.525705,33.597665 L 34.675226,33.597665 L 34.675226,30.571517 z"
+ style="fill:url(#linearGradient1896);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="28.716803"
+ x="45.460419"
+ height="4.90236"
+ width="0.98047203"
+ id="rect1345"
+ style="fill:url(#linearGradient1898);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/person.svg b/emacs.d/lisp/rudel/icons/person.svg
new file mode 100644
index 0000000..9abbb02
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/person.svg
@@ -0,0 +1,388 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2108"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/home/dobey/Projects/gnome-icon-theme/scalable/stock/generic"
+ sodipodi:docname="person.svg"
+ inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-icon-theme/48x48/stock/generic/stock_person.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective39" />
+ <linearGradient
+ id="linearGradient4562">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop4564" />
+ <stop
+ style="stop-color:#d6d6d2;stop-opacity:1;"
+ offset="1"
+ id="stop4566" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient4356">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop4358" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop4360" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3824">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop3826" />
+ <stop
+ style="stop-color:#c9c9c9;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop3828" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3816">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop3818" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop3820" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3816"
+ id="radialGradient3822"
+ cx="31.112698"
+ cy="19.008621"
+ fx="31.112698"
+ fy="19.008621"
+ r="8.6620579"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient4362"
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.329025,6.0757e-2,-6.0757e-2,0.329025,16.100244,13.290312)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient4366"
+ gradientUnits="userSpaceOnUse"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,32.768766,12.999177)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient1366"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,28.188541,10.75574)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3824"
+ id="linearGradient1372"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3345875,0,0,0.3345875,10.045981,12.133792)"
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient4568"
+ cx="24.753788"
+ cy="26.814409"
+ fx="24.753788"
+ fy="26.814409"
+ r="17.986025"
+ gradientTransform="matrix(0.3386292,0,0,0.3415987,16.17891,14.840961)"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3816"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.558489,0,-1.377346e-8,0.563387,14.87134,4.364123)"
+ cx="29.922075"
+ cy="17.727694"
+ fx="29.922075"
+ fy="17.727694"
+ r="17.986025" />
+ <filter
+ inkscape:collect="always"
+ x="-0.076111108"
+ width="1.1522222"
+ y="-0.28344828"
+ height="1.5668966"
+ id="filter5655">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.4531044"
+ id="feGaussianBlur5657" />
+ </filter>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3824"
+ id="linearGradient3196"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3345875,0,0,0.3345875,10.045981,12.133792)"
+ x1="30.935921"
+ y1="29.553486"
+ x2="30.935921"
+ y2="35.803486" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3198"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,28.188541,10.75574)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3200"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.3386292,0,0,0.3415987,16.17891,14.840961)"
+ cx="24.753788"
+ cy="26.814409"
+ fx="24.753788"
+ fy="26.814409"
+ r="17.986025" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3202"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.3271212,7.02885e-2,7.02885e-2,0.3271212,32.768766,12.999177)"
+ x1="22.686766"
+ y1="36.3904"
+ x2="21.408455"
+ y2="35.739632" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4356"
+ id="linearGradient3204"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.329025,6.0757e-2,-6.0757e-2,0.329025,16.100244,13.290312)"
+ x1="20.661695"
+ y1="35.817974"
+ x2="22.626925"
+ y2="36.217758" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3816"
+ id="radialGradient3206"
+ gradientUnits="userSpaceOnUse"
+ cx="31.112698"
+ cy="19.008621"
+ fx="31.112698"
+ fy="19.008621"
+ r="8.6620579" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4562"
+ id="radialGradient3208"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.558489,0,-1.377346e-8,0.563387,14.87134,4.364123)"
+ cx="29.922075"
+ cy="17.727694"
+ fx="29.922075"
+ fy="17.727694"
+ r="17.986025" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:showpageshadow="false"
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.16862745"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="25.782205"
+ inkscape:cx="7.1442001"
+ inkscape:cy="7.5126712"
+ inkscape:current-layer="layer2"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ fill="#9db029"
+ stroke="#727e0a"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Person</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://jimmac.musichall.cz</dc:source>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>user</rdf:li>
+ <rdf:li>person</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="cipek"
+ inkscape:groupmode="layer"
+ style="display:inline"
+ transform="translate(-20.05096,-17.593986)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="dalsi cipek"
+ style="display:inline"
+ transform="translate(-20.05096,-17.593986)">
+ <g
+ id="g3184"
+ transform="matrix(1.4267997,0,0,1.4267997,-6.9832045,-7.3342725)">
+ <path
+ id="path4173"
+ d="M 21.757143,23.52136 L 23.176678,23.52136 L 22.348616,22.752445 L 22.171174,22.989035 L 21.993732,22.811593 L 21.757143,23.52136 z"
+ style="opacity:1;fill:url(#linearGradient3196);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.22784807;fill:url(#linearGradient3198);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 23.386507,25.431438 C 23.798468,25.23705 23.99023,24.761487 23.99023,24.761487 C 23.66932,23.408755 22.65986,22.471964 22.65986,22.471964 C 22.65986,22.471964 23.484482,24.59412 23.386507,25.431438 z"
+ id="path4370"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ transform="matrix(0.2337963,0,0,0.2337963,18.811068,17.877885)"
+ ry="5.126524"
+ rx="5.126524"
+ y="35.448853"
+ x="5.3033009"
+ height="10.253048"
+ width="38.183765"
+ id="rect4608"
+ style="opacity:0.34857142;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.30000001;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:block;overflow:visible;filter:url(#filter5655);enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cczcczc"
+ id="path4308"
+ d="M 22.895503,28.188054 L 26.444339,28.188054 C 27.449843,28.188054 28.445335,27.819361 28.81023,26.768519 C 29.156742,25.77062 28.869377,23.870303 26.621781,22.332474 L 22.422325,22.332474 C 20.174728,23.752008 19.89385,25.693349 20.411317,26.827666 C 20.938492,27.983261 21.830852,28.188054 22.895503,28.188054 z"
+ style="opacity:1;fill:url(#radialGradient3200);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.24999996px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ style="opacity:0.29120878;fill:url(#linearGradient3202);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 27.966732,27.674875 C 28.378694,27.480487 28.570455,27.004924 28.570455,27.004924 C 28.249546,25.652192 27.240085,24.715401 27.240085,24.715401 C 27.240085,24.715401 28.064708,26.837557 27.966732,27.674875 z"
+ id="path4364"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:r_cy="true"
+ inkscape:r_cx="true"
+ sodipodi:nodetypes="cccc"
+ id="path4354"
+ d="M 21.326525,27.820334 C 20.909091,27.637994 20.722261,27.198577 20.722261,27.198577 C 21.003744,25.837095 21.966902,24.841001 21.966902,24.841001 C 21.966902,24.841001 21.20427,26.986214 21.326525,27.820334 z"
+ style="opacity:0.54945056;fill:url(#linearGradient3204);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ style="opacity:0.64285715;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.24999997px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 22.814062,27.9295 L 26.445984,27.921851 C 27.359628,27.921851 28.264173,27.586842 28.595733,26.632002 C 28.910588,25.725268 28.562948,23.998559 26.520687,22.601222 L 22.531825,22.517093 C 20.489564,23.806942 20.09428,25.570927 20.572121,26.685746 C 21.049963,27.800564 21.747249,27.921851 22.814062,27.9295 z"
+ id="path4314"
+ sodipodi:nodetypes="cczcczc" />
+ <path
+ transform="matrix(0.3345875,0,0,0.3345875,14.159031,15.428212)"
+ sodipodi:type="arc"
+ style="opacity:1;fill:url(#radialGradient3206);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path4318"
+ sodipodi:cx="31.112698"
+ sodipodi:cy="19.008621"
+ sodipodi:rx="8.6620579"
+ sodipodi:ry="8.6620579"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" />
+ <path
+ transform="matrix(0.3345875,0,0,0.3345875,14.200853,14.257155)"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z"
+ sodipodi:ry="8.6620579"
+ sodipodi:rx="8.6620579"
+ sodipodi:cy="19.008621"
+ sodipodi:cx="31.112698"
+ id="path4320"
+ style="opacity:1;fill:url(#radialGradient3208);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:0.74718857px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(0.3037807,0,0,0.3037807,15.159341,14.842753)"
+ sodipodi:type="arc"
+ style="opacity:0.19620254;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:0.82296228px;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="path4322"
+ sodipodi:cx="31.112698"
+ sodipodi:cy="19.008621"
+ sodipodi:rx="8.6620579"
+ sodipodi:ry="8.6620579"
+ d="M 39.774755,19.008621 A 8.6620579,8.6620579 0 1 1 22.45064,19.008621 A 8.6620579,8.6620579 0 1 1 39.774755,19.008621 z" />
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/icons/plaintext.svg b/emacs.d/lisp/rudel/icons/plaintext.svg
new file mode 100644
index 0000000..1086ba2
--- /dev/null
+++ b/emacs.d/lisp/rudel/icons/plaintext.svg
@@ -0,0 +1,474 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg12360"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docbase="/data/Desktop/icons/scaleable"
+ sodipodi:docname="plaintext.svg"
+ inkscape:export-filename="/data/Desktop/icons/scaleable/seahorse-applet-text.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ version="1.0">
+ <defs
+ id="defs12362">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 24 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="48 : 24 : 1"
+ inkscape:persp3d-origin="24 : 16 : 1"
+ id="perspective3119" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2259">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2261" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2263" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2251">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2253" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2255" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2239">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop2241" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:0;"
+ offset="1"
+ id="stop2243" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2224">
+ <stop
+ style="stop-color:#7c7c7c;stop-opacity:1;"
+ offset="0"
+ id="stop2226" />
+ <stop
+ style="stop-color:#b8b8b8;stop-opacity:1;"
+ offset="1"
+ id="stop2228" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2216">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop2218" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="1"
+ id="stop2220" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15234">
+ <stop
+ style="stop-color:#97978a;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15236" />
+ <stop
+ id="stop15242"
+ offset="0.50000000"
+ style="stop-color:#c2c2b9;stop-opacity:1.0000000;" />
+ <stop
+ style="stop-color:#7d7d6f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15238" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient15218">
+ <stop
+ style="stop-color:#f0f0ef;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop15220" />
+ <stop
+ id="stop2269"
+ offset="0.59928656"
+ style="stop-color:#e8e8e8;stop-opacity:1;" />
+ <stop
+ id="stop2267"
+ offset="0.82758623"
+ style="stop-color:#ffffff;stop-opacity:1;" />
+ <stop
+ style="stop-color:#d8d8d3;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop15222" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient14484">
+ <stop
+ style="stop-color:#c68827;stop-opacity:1.0000000;"
+ offset="0.0000000"
+ id="stop14486" />
+ <stop
+ style="stop-color:#89601f;stop-opacity:1.0000000;"
+ offset="1.0000000"
+ id="stop14488" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient13746">
+ <stop
+ style="stop-color:#646459;stop-opacity:1;"
+ offset="0"
+ id="stop13748" />
+ <stop
+ style="stop-color:#646459;stop-opacity:0;"
+ offset="1"
+ id="stop13750" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient13746"
+ id="radialGradient3142"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1,0,0,0.110577,0,40.26648)"
+ cx="24.647722"
+ cy="45.272587"
+ fx="24.647722"
+ fy="45.272587"
+ r="21.011173" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient14484"
+ id="linearGradient3144"
+ gradientUnits="userSpaceOnUse"
+ x1="6.1071744"
+ y1="10.45129"
+ x2="33.857143"
+ y2="37.87986" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15218"
+ id="linearGradient3146"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.065698,0,0,0.987595,-1.564439,7.487332e-2)"
+ x1="22.308331"
+ y1="18.99214"
+ x2="35.785294"
+ y2="39.498238" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2259"
+ id="linearGradient3148"
+ gradientUnits="userSpaceOnUse"
+ x1="26.076092"
+ y1="26.696676"
+ x2="30.811172"
+ y2="42.007351" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3150"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.052632,0,0,1,-1.789474,0)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3152"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.538743,0,0,0.511806,10.8008,-0.58264)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.404572"
+ y2="6.481061" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient15234"
+ id="linearGradient3154"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.005222,0,0,0.883928,-0.627923,0.84375)"
+ x1="25.404572"
+ y1="3.8180194"
+ x2="25.464211"
+ y2="9.3233509" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2216"
+ id="linearGradient3156"
+ gradientUnits="userSpaceOnUse"
+ x1="36.8125"
+ y1="39.15625"
+ x2="39.0625"
+ y2="42.0625" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2224"
+ id="linearGradient3158"
+ gradientUnits="userSpaceOnUse"
+ x1="35.996582"
+ y1="40.458221"
+ x2="33.664921"
+ y2="37.770721" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2239"
+ id="linearGradient3160"
+ gradientUnits="userSpaceOnUse"
+ x1="25.682829"
+ y1="12.172059"
+ x2="25.692169"
+ y2="-0.20294096" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2251"
+ id="linearGradient3162"
+ gradientUnits="userSpaceOnUse"
+ x1="33.396004"
+ y1="36.921333"
+ x2="34.170048"
+ y2="38.070381" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="0.15294118"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="10.980754"
+ inkscape:cy="28.267956"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1152"
+ inkscape:window-height="818"
+ inkscape:window-x="1152"
+ inkscape:window-y="0"
+ inkscape:showpageshadow="false" />
+ <metadata
+ id="metadata12365">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Edit Paste</dc:title>
+ <dc:date>2005-10-10</dc:date>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Andreas Nilsson</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>edit</rdf:li>
+ <rdf:li>paste</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:contributor>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Attribution" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g3121"
+ transform="matrix(0.3298017,0,0,0.3298017,9.0643304e-2,8.4759164e-2)">
+ <path
+ transform="matrix(0.913383,0,0,1.178892,1.920946,-8.11047)"
+ d="M 45.658895,45.272587 A 21.011173,2.3233509 0 1 1 3.636549,45.272587 A 21.011173,2.3233509 0 1 1 45.658895,45.272587 z"
+ sodipodi:ry="2.3233509"
+ sodipodi:rx="21.011173"
+ sodipodi:cy="45.272587"
+ sodipodi:cx="24.647722"
+ id="path13018"
+ style="opacity:1;fill:url(#radialGradient3142);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.90907735;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ sodipodi:type="arc" />
+ <rect
+ ry="1.3879364"
+ rx="1.3879371"
+ y="4.5"
+ x="4.4643173"
+ height="41.045437"
+ width="39.035683"
+ id="rect12368"
+ style="opacity:1;fill:url(#linearGradient3144);fill-opacity:1;fill-rule:evenodd;stroke:#714c16;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.56650835"
+ rx="0.56650835"
+ y="6.5295157"
+ x="8.5323219"
+ height="35.976688"
+ width="30.951559"
+ id="rect12413"
+ style="opacity:1;fill:url(#linearGradient3146);fill-opacity:1;fill-rule:evenodd;stroke:#888a85;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.98387533"
+ rx="0.98387533"
+ y="0"
+ x="18"
+ height="4"
+ width="12"
+ id="rect13756"
+ style="opacity:1;fill:#5c5c5c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0"
+ rx="0"
+ y="7.4665856"
+ x="9.5171413"
+ height="34.040764"
+ width="29.014147"
+ id="rect15244"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3148);stroke-width:1.00000048;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ ry="0.47879848"
+ rx="0.47879848"
+ y="5.4307775"
+ x="5.4393425"
+ height="39.092987"
+ width="37.085655"
+ id="rect15974"
+ style="opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#c68827;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <rect
+ style="opacity:0.10795456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2208"
+ width="18.947376"
+ height="7"
+ x="14.791488"
+ y="4.4722719"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient3150);fill-opacity:1;fill-rule:evenodd;stroke:#5c5c5c;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2285"
+ width="18.947376"
+ height="7"
+ x="14.526322"
+ y="3.5"
+ rx="1.3879377"
+ ry="1.3879364" />
+ <rect
+ style="opacity:1;fill:url(#linearGradient3152);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ id="rect2281"
+ width="9.6973763"
+ height="3.5826404"
+ x="19.151323"
+ y="1.2086792"
+ rx="0.32543635"
+ ry="0.32543635" />
+ <rect
+ ry="1.0129364"
+ rx="1.0129364"
+ y="3.9375"
+ x="14.953014"
+ height="6.1875"
+ width="18.093992"
+ id="rect13754"
+ style="opacity:1;fill:url(#linearGradient3154);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2212"
+ d="M 39.018306,36.25 L 39.0625,42.0625 L 30.5625,42.018306 L 39.018306,36.25 z"
+ style="opacity:0.48863639;fill:url(#linearGradient3156);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path2210"
+ d="M 30.059082,42.086864 C 31.850223,42.254516 39.048809,37.717278 39.539922,33.698855 C 37.97666,36.121952 34.584971,35.667446 30.476213,35.826456 C 30.476213,35.826456 30.871582,41.586864 30.059082,42.086864 z"
+ style="opacity:1;fill:url(#linearGradient3158);fill-opacity:1;fill-rule:evenodd;stroke:#868a84;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <path
+ id="rect2232"
+ d="M 19.46875,1.46875 C 19.466654,1.4708456 19.470414,1.4975336 19.46875,1.5 C 19.46758,1.502776 19.438116,1.4969757 19.4375,1.5 L 19.4375,4.375 C 19.4375,4.3814229 19.46641,4.4006981 19.46875,4.40625 C 19.471216,4.4079135 19.465974,4.4363298 19.46875,4.4375 L 15.9375,4.4375 C 15.91974,4.4375 15.892285,4.4357551 15.875,4.4375 C 15.840968,4.4426713 15.781454,4.4572762 15.75,4.46875 C 15.611832,4.5269964 15.482328,4.6677699 15.4375,4.8125 C 15.426991,4.8535348 15.4375,4.9243489 15.4375,4.96875 L 15.4375,9.125 C 15.4375,9.1427605 15.435755,9.1702147 15.4375,9.1875 C 15.442671,9.2215321 15.457276,9.2810456 15.46875,9.3125 C 15.478458,9.3355281 15.487176,9.3851004 15.5,9.40625 C 15.5046,9.41307 15.526336,9.4309205 15.53125,9.4375 C 15.552124,9.4628138 15.599686,9.5103764 15.625,9.53125 C 15.638159,9.5410789 15.6734,9.5539504 15.6875,9.5625 C 15.702038,9.5703781 15.734648,9.5872782 15.75,9.59375 C 15.781454,9.6052238 15.840968,9.6198287 15.875,9.625 C 15.892285,9.6267449 15.91974,9.625 15.9375,9.625 L 32.0625,9.625 C 32.08026,9.625 32.107715,9.6267449 32.125,9.625 C 32.159032,9.6198287 32.218546,9.6052238 32.25,9.59375 C 32.265352,9.5872782 32.297962,9.5703781 32.3125,9.5625 C 32.3266,9.5539504 32.361841,9.5410789 32.375,9.53125 C 32.400314,9.5103764 32.447876,9.4628138 32.46875,9.4375 C 32.473664,9.4309205 32.4954,9.41307 32.5,9.40625 C 32.512824,9.3851004 32.521542,9.3355281 32.53125,9.3125 C 32.542724,9.2810456 32.557329,9.2215321 32.5625,9.1875 C 32.564245,9.1702147 32.5625,9.1427605 32.5625,9.125 L 32.5625,4.96875 C 32.5625,4.9243489 32.573009,4.8535348 32.5625,4.8125 C 32.517672,4.6677698 32.388168,4.5269964 32.25,4.46875 C 32.218546,4.4572762 32.159032,4.4426713 32.125,4.4375 C 32.107715,4.4357551 32.08026,4.4375 32.0625,4.4375 L 28.53125,4.4375 C 28.534026,4.4363298 28.528784,4.4079135 28.53125,4.40625 C 28.533591,4.4006981 28.5625,4.3814229 28.5625,4.375 L 28.5625,1.5 C 28.561884,1.4969757 28.53242,1.502776 28.53125,1.5 C 28.529586,1.4975336 28.533346,1.4708456 28.53125,1.46875 C 28.528474,1.4675798 28.503024,1.4693657 28.5,1.46875 L 19.5,1.46875 C 19.496976,1.4693657 19.471526,1.4675798 19.46875,1.46875 z"
+ style="opacity:0.31681818;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3160);stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ style="opacity:0.36931817;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient3162);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ d="M 31.509519,40.68705 C 32.879298,40.003221 36.038783,38.086016 37.338164,36.205012 C 35.545641,36.581496 34.347243,36.794585 31.610576,36.900494 C 31.610576,36.900494 31.697137,39.91208 31.509519,40.68705 z"
+ id="path2247"
+ sodipodi:nodetypes="cccc" />
+ <rect
+ y="15"
+ x="14"
+ height="2"
+ width="21"
+ id="rect2271"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2273"
+ width="20"
+ height="2"
+ x="14"
+ y="19" />
+ <rect
+ y="23"
+ x="14"
+ height="2"
+ width="18"
+ id="rect2275"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ <rect
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
+ id="rect2277"
+ width="21"
+ height="2"
+ x="14"
+ y="27" />
+ <rect
+ y="31"
+ x="14"
+ height="2"
+ width="13"
+ id="rect2279"
+ style="opacity:0.17045456;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
+ </g>
+ </g>
+</svg>
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/all-wcprops b/emacs.d/lisp/rudel/jupiter/.svn/all-wcprops
new file mode 100644
index 0000000..87ab5a7
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/all-wcprops
@@ -0,0 +1,47 @@
+K 25
+svn:wc:ra_dav:version-url
+V 41
+/svnroot/rudel/!svn/ver/402/trunk/jupiter
+END
+jupiter-operation.el
+K 25
+svn:wc:ra_dav:version-url
+V 62
+/svnroot/rudel/!svn/ver/181/trunk/jupiter/jupiter-operation.el
+END
+jupiter-delete.el
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/rudel/!svn/ver/402/trunk/jupiter/jupiter-delete.el
+END
+jupiter.el
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/401/trunk/jupiter/jupiter.el
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 53
+/svnroot/rudel/!svn/ver/127/trunk/jupiter/Project.ede
+END
+jupiter-compound.el
+K 25
+svn:wc:ra_dav:version-url
+V 61
+/svnroot/rudel/!svn/ver/401/trunk/jupiter/jupiter-compound.el
+END
+jupiter-insert.el
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/rudel/!svn/ver/401/trunk/jupiter/jupiter-insert.el
+END
+jupiter-nop.el
+K 25
+svn:wc:ra_dav:version-url
+V 56
+/svnroot/rudel/!svn/ver/401/trunk/jupiter/jupiter-nop.el
+END
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/entries b/emacs.d/lisp/rudel/jupiter/.svn/entries
new file mode 100644
index 0000000..9c980a3
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/entries
@@ -0,0 +1,266 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/jupiter
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-12T01:25:58.278168Z
+402
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+jupiter-operation.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+550a78114bf28f2e455b046b044de3ab
+2009-10-03T00:38:22.402651Z
+181
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1768
+
+jupiter-delete.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+6d404ed5777e97ebc85ecceccd7c192f
+2009-10-12T01:25:58.278168Z
+402
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4567
+
+jupiter.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+f8061c6bda7d06bb8baec72c4ad99455
+2009-10-10T00:40:22.102805Z
+401
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4289
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+9c70097606c8b04470919770f3ee7f27
+2009-10-03T00:27:43.856107Z
+127
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+380
+
+jupiter-compound.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+924928b8dcad42bebf1892a1f8815d84
+2009-10-10T00:40:22.102805Z
+401
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2569
+
+jupiter-insert.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+418f814ecd47f022790826fd91547e19
+2009-10-10T00:40:22.102805Z
+401
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4126
+
+jupiter-nop.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+3af498a68a91644e00dfb63a1a2ca4a7
+2009-10-10T00:40:22.102805Z
+401
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1457
+
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..275d1ed
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,14 @@
+;; Object rudel/jupiter
+;; EDE project file.
+(ede-proj-project "rudel/jupiter"
+ :name "jupiter"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "jupiter"
+ :name "jupiter"
+ :path ""
+ :source '("jupiter.el" "jupiter-operation.el" "jupiter-insert.el" "jupiter-delete.el" "jupiter-compound.el" "jupiter-nop.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-compound.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-compound.el.svn-base
new file mode 100644
index 0000000..789bbc2
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-compound.el.svn-base
@@ -0,0 +1,89 @@
+;;; jupiter-compound.el --- Jupiter compound operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, compound
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-compound' implements a compound operation comprised
+;; of a number of child operations.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-compound
+;;
+
+(defclass jupiter-compound (jupiter-operation)
+ ((children :initarg :children
+ :type list
+ :initform nil
+ :documentation
+ ""))
+ "Objects of this class are operations, which are composed of a
+number of child operation.")
+
+;; TODO this has side effects. It can only be called once
+(defmethod rudel-apply ((this jupiter-compound) object)
+ "Apply THIS to BUFFER by applying the child operation."
+ (with-slots (children) this
+ (let ((child (first children))
+ (rest (rest children)))
+ ;; Apply all child operations
+ (while child
+ (rudel-apply child object)
+ ;; For each applied child operation, transform remaining
+ ;; operation with the applied operation.
+ (dolist (next rest)
+ (setf next (jupiter-transform child next)))
+ ;; Advance to next child operation.
+ (setq child (first rest)
+ rest (rest rest)))))
+ )
+
+(defmethod jupiter-transform ((this jupiter-compound) other)
+ "Transform OTHER using the child operations of THIS."
+ (with-slots (children) this
+ (dolist (child children) ;; TODO reverse children?
+ (setq other (jupiter-transform child other)))
+ other))
+
+(defmethod object-print ((this jupiter-compound) &rest strings)
+ "Add number of children to string representation of THIS."
+ (with-slots (children) this
+ (call-next-method
+ this
+ (format " children %d" (length children)))))
+
+(provide 'jupiter-compound)
+;;; jupiter-compound.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-delete.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-delete.el.svn-base
new file mode 100644
index 0000000..db2e985
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-delete.el.svn-base
@@ -0,0 +1,176 @@
+;;; jupiter-delete.el --- Jupiter delete operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, delete
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-delete' implements a delete operation for the
+;; Jupiter algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-delete
+;;
+
+(defclass jupiter-delete (jupiter-operation
+ rudel-delete-op)
+ ()
+ "Objects of this class represent deletions in buffers.")
+
+(defmethod jupiter-transform ((this jupiter-delete) other)
+ "Transform other using THIS.
+OTHER is destructively modified or replaced."
+ (cond
+
+ ;;
+ ;; Transform an insert operation
+ ;;
+ ((jupiter-insert-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+ ;;
+ ;; <other>
+ ;; <this>
+ ;;
+ ((<= other-to this-from))
+
+ ;; <other>
+ ;; <this>
+ ((> other-from this-to)
+ (decf other-from this-length))
+
+ ;; <other>
+ ;; < this >
+ ((and (> other-from this-from) (< other-to this-to))
+ (setq other-from this-from))
+ )))
+ )
+
+ ;;
+ ;; Transform a delete operation
+ ;;
+ ((jupiter-delete-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+
+ ;; <other>
+ ;; <this>
+ ;; OTHER deleted a region after the region deleted by
+ ;; THIS. Therefore OTHER has to be shifted by the length of
+ ;; the deleted region.
+ ((> other-from this-to)
+ (decf other-from this-length)
+ (decf other-to this-length))
+
+ ;; <other>
+ ;; <this>
+ ;; OTHER deleted a region before the region affected by
+ ;; THIS. That is not affected by THIS operation.
+ ((<= other-to this-from))
+
+ ;; < other >
+ ;; <this>
+ ((and (>= other-from this-from) (>= other-to this-to))
+ (decf other-to this-length))
+
+ ;; <other>
+ ;; <this>
+ ((and (< other-from this-from) (< other-to this-to))
+ (decf other-to (- other-to this-to)))
+
+ ;; <other>
+ ;; <this>
+ ;; The region deleted by OTHER overlaps with the region
+ ;; deleted by THIS, such that a part of the region of this is
+ ;; before the region of OTHER. The first part of the region
+ ;; deleted by OTHER has already been deleted. Therefore, the
+ ;; start of OTHER has to be shifted by the length of the
+ ;; overlap.
+ ((and (< other-from this-to) (> other-to this-to))
+ (setq other-from this-from)
+ (incf other-to (+ other-from (- other-to this-to))))
+
+ ;; <other>
+ ;; < this >
+ ;; The region deleted by OTHER is completely contained in
+ ;; the region affected by THIS. Therefore, OTHER must not
+ ;; be executed.
+ ((and (>= other-from this-from) (<= other-to this-to))
+ (setq other (jupiter-nop "nop")))
+
+ (t (error "logic error in (jupiter-transform (x jupiter-delete) (y jupiter-delete))"))
+ ))))
+
+ ;;
+ ;; Transform a compound operation
+ ;;
+ ((jupiter-compound-p other) ;; TODO encapsulation violation
+ (with-slots (children) other
+ (dolist (child children)
+ (setf child (jupiter-transform this child)))))
+
+ ;;
+ ;; Transform a nop operation
+ ;;
+ ((jupiter-nop-p other))
+
+ ;; TODO this is for debugging
+ (t (error "Cannot transform operation of type `%s'"
+ (object-class other))))
+ other)
+
+(defmethod object-print ((this jupiter-delete) &rest strings)
+ "Add from, to and length to string representation of THIS."
+ (with-slots (from to length) this
+ (call-next-method
+ this
+ (format " from %d" from)
+ (format " to %d" to)
+ (format " length %d" length)))
+ )
+
+(provide 'jupiter-delete)
+;;; jupiter-delete.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-insert.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-insert.el.svn-base
new file mode 100644
index 0000000..339270e
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-insert.el.svn-base
@@ -0,0 +1,165 @@
+;;; jupiter-insert.el --- Jupiter insert operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, insert
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-insert' implements an insert operation for the
+;; Jupiter algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-insert
+;;
+
+(defclass jupiter-insert (jupiter-operation
+ rudel-insert-op)
+ ()
+ "Objects of this class represent insertions into buffers.")
+
+(defmethod jupiter-transform ((this jupiter-insert) other)
+ "Transform OTHER using THIS."
+ (cond
+
+ ;;
+ ;; Transform an insert operation
+ ;;
+ ((jupiter-insert-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)
+ (this-data :data)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)
+ (other-data :data)) other
+ (cond
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; No need to do anything in this case.
+ ;; ((< other-from this-from))
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;;
+ ((> other-from this-from)
+ (incf other-from this-length))
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; OTHER inserted at the same start position as we did. Since
+ ;; the situation is symmetric in the location properties of
+ ;; OTHER and THIS, we use the inserted data to construct an
+ ;; ordering.
+ ((= other-from this-from)
+ (when (string< this-data other-data)
+ (incf other-from this-length)))))))
+
+ ;;
+ ;; Transform a delete operation
+ ;;
+ ((jupiter-delete-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; just keep OTHER
+
+ ;;
+ ;; <other> and <other> and <other>
+ ;; <this> <this> <this>
+ ((>= other-from this-from)
+ (incf other-from this-length)
+ (incf other-to this-length))
+
+ ;;
+ ;; < other >
+ ;; <this>
+ ;; OTHER deleted a region that includes the point at which THIS
+ ;; inserted in its interior. OTHER has to be split into one
+ ;; deletion before and one delete after the inserted data.
+ ((and (< other-from this-from) (> other-to this-to))
+ (setq other
+ (jupiter-compound "compound"
+ :children (list (jupiter-delete "delete-left"
+ :from other-from
+ :to this-from)
+ (jupiter-delete "delete-right"
+ :from this-to
+ :to (+ other-to this-length))))))
+ ))))
+
+ ;;
+ ;; Transform a compound operation
+ ;;
+ ((jupiter-compound-p other) ;; TODO encapsulation violation
+ (with-slots (children) other
+ (dolist (child children)
+ (setf child (jupiter-transform this child)))))
+
+ ;;
+ ;; Transform a nop operation
+ ;;
+ ((jupiter-nop-p other))
+
+ ;; TODO this is for debugging
+ (t (error "Cannot transform operation of type `%s'"
+ (object-class other))))
+ other)
+
+(defmethod object-print ((this jupiter-insert) &rest strings)
+ "Add from, to, length and data to string representation of THIS."
+ (with-slots (from to length data) this
+ (call-next-method
+ this
+ (format " from %d" from)
+ (format " to %d" to)
+ (format " length %d" length)
+ (format " data \"%s\"" data)))
+ )
+
+(provide 'jupiter-insert)
+;;; jupiter-insert.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-nop.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-nop.el.svn-base
new file mode 100644
index 0000000..e0f4a5c
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-nop.el.svn-base
@@ -0,0 +1,59 @@
+;;; jupiter-nop.el --- Jupiter no operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, nop
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-nop' implements a no-operation for the Jupiter
+;; algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-nop
+;;
+
+(defclass jupiter-nop (jupiter-operation)
+ ()
+ "Operation, which does not change anything.")
+
+(defmethod rudel-apply ((this jupiter-nop) object)
+ "Applying THIS does not change OBJECT.")
+
+(defmethod jupiter-transform ((this jupiter-nop) other)
+ "Transforming OTHER with THIS simply returns OTHER."
+ other)
+
+(provide 'jupiter-nop)
+;;; jupiter-nop.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-operation.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-operation.el.svn-base
new file mode 100644
index 0000000..bc91fee
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter-operation.el.svn-base
@@ -0,0 +1,61 @@
+;;; jupiter-operation.el --- Operation base class for jupiter algorithm
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Jupiter, operation, base
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; The class jupiter-operation is a base class for Jupiter operation
+;; classes.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+
+
+;;; Class jupiter-operation
+;;
+
+(defclass jupiter-operation (rudel-operation)
+ ()
+ "Objects of derived classes represent operations, which change documents.
+Objects can transform each other to produce sequences of
+operations, which produce identical changes than permutations of
+the same operations."
+ :abstract t)
+
+;; This one really could use multiple dispatch
+(defgeneric jupiter-transform ((this jupiter-operation) other)
+ "Transform OTHER such that the effect of applying it after THIS are equal to applying OTHER before THIS unmodified.
+In general, OTHER is destructively modified or replaced.")
+
+(provide 'jupiter-operation)
+;;; jupiter-operation.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter.el.svn-base b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter.el.svn-base
new file mode 100644
index 0000000..d285041
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/.svn/text-base/jupiter.el.svn-base
@@ -0,0 +1,135 @@
+;;; jupiter.el --- An implementation of the Jupiter algorithm
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, jupiter, algorithm, distributed, integrity
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains an implementation of the jupiter algorithm,
+;; which ensures the synchronization of data shared between multiple
+;; peers despite differences in network latency.
+;;
+;; This implementation is partly based on the implementation used in
+;; the obby library <http://gobby.0x539.de/trac/>. Note, however, that
+;; the details of the implementations differ.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+(require 'jupiter-insert)
+(require 'jupiter-delete)
+(require 'jupiter-compound)
+(require 'jupiter-nop)
+
+
+;;; Class jupiter-context
+;;
+
+(defclass jupiter-context ()
+ ((local-revision :initarg :local-revision
+ :type (integer 0)
+ :initform 0
+ :documentation
+ "Revision number of the local data.")
+ (remote-revision :initarg :remote-revision
+ :type (integer 0)
+ :initform 0
+ :documentation
+ "Revision number of the remote data.")
+ (local-log :initarg :local-log
+ :type list
+ :initform nil
+ :documentation
+ "List of local operations, that have not been
+acknowledged by the remote side."))
+ "Objects of this class store the state of one side of a
+concurrent modification activity, which is synchronized using the
+jupiter algorithm.")
+
+(defmethod jupiter-local-operation ((this jupiter-context) operation)
+ "Store OPERATION in the operation log of THIS and increase local revision count."
+ (with-slots (local-revision local-log) this
+ (push (cons local-revision operation) local-log)
+ (incf local-revision)))
+
+(defmethod jupiter-remote-operation ((this jupiter-context)
+ local-revision remote-revision
+ operation)
+ "Transform OPERATION with revisions LOCAL-REVISION and REMOTE-REVISION using the local operations stored in THIS.
+LOCAL-REVISION is the local revision of THIS context, the remote
+site is referring to."
+ (let ((transformed-operation operation))
+ (with-slots ((this-remote-revision :remote-revision)
+ local-log) this
+
+ ;; Discard stored local operations which are older than the
+ ;; local revision to which the remote site refers.
+ (setq local-log (delete-if
+ (lambda (revision) (< revision local-revision))
+ local-log
+ :key 'car))
+
+ ;; Transform the operation
+ (mapc
+ (lambda (log-operation)
+
+ ;; Transform the remote operation using the stored operation.
+ (setq transformed-operation
+ (jupiter-transform (cdr log-operation)
+ transformed-operation))
+
+ ;; Transform the stored operation using the already
+ ;; transformed remote operation.
+ (setf (cdr log-operation)
+ (jupiter-transform transformed-operation
+ (cdr log-operation))))
+ (reverse local-log))
+
+ ;; Increase remote revision
+ (incf this-remote-revision))
+ ;; The transformed operation is the result of the computation.
+ transformed-operation)
+ )
+
+(defmethod object-print ((this jupiter-context) &rest strings)
+ "Add revisions and log length to string representation of THIS."
+ (with-slots (local-revision remote-revision local-log) this
+ (call-next-method
+ this
+ (format " local %d" local-revision)
+ (format " remote %d" remote-revision)
+ (format " log-items %d" (length local-log)))))
+
+(provide 'jupiter)
+;;; jupiter.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/Project.ede b/emacs.d/lisp/rudel/jupiter/Project.ede
new file mode 100644
index 0000000..275d1ed
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/Project.ede
@@ -0,0 +1,14 @@
+;; Object rudel/jupiter
+;; EDE project file.
+(ede-proj-project "rudel/jupiter"
+ :name "jupiter"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "jupiter"
+ :name "jupiter"
+ :path ""
+ :source '("jupiter.el" "jupiter-operation.el" "jupiter-insert.el" "jupiter-delete.el" "jupiter-compound.el" "jupiter-nop.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter-compound.el b/emacs.d/lisp/rudel/jupiter/jupiter-compound.el
new file mode 100644
index 0000000..789bbc2
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter-compound.el
@@ -0,0 +1,89 @@
+;;; jupiter-compound.el --- Jupiter compound operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, compound
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-compound' implements a compound operation comprised
+;; of a number of child operations.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-compound
+;;
+
+(defclass jupiter-compound (jupiter-operation)
+ ((children :initarg :children
+ :type list
+ :initform nil
+ :documentation
+ ""))
+ "Objects of this class are operations, which are composed of a
+number of child operation.")
+
+;; TODO this has side effects. It can only be called once
+(defmethod rudel-apply ((this jupiter-compound) object)
+ "Apply THIS to BUFFER by applying the child operation."
+ (with-slots (children) this
+ (let ((child (first children))
+ (rest (rest children)))
+ ;; Apply all child operations
+ (while child
+ (rudel-apply child object)
+ ;; For each applied child operation, transform remaining
+ ;; operation with the applied operation.
+ (dolist (next rest)
+ (setf next (jupiter-transform child next)))
+ ;; Advance to next child operation.
+ (setq child (first rest)
+ rest (rest rest)))))
+ )
+
+(defmethod jupiter-transform ((this jupiter-compound) other)
+ "Transform OTHER using the child operations of THIS."
+ (with-slots (children) this
+ (dolist (child children) ;; TODO reverse children?
+ (setq other (jupiter-transform child other)))
+ other))
+
+(defmethod object-print ((this jupiter-compound) &rest strings)
+ "Add number of children to string representation of THIS."
+ (with-slots (children) this
+ (call-next-method
+ this
+ (format " children %d" (length children)))))
+
+(provide 'jupiter-compound)
+;;; jupiter-compound.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter-delete.el b/emacs.d/lisp/rudel/jupiter/jupiter-delete.el
new file mode 100644
index 0000000..db2e985
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter-delete.el
@@ -0,0 +1,176 @@
+;;; jupiter-delete.el --- Jupiter delete operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, delete
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-delete' implements a delete operation for the
+;; Jupiter algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-delete
+;;
+
+(defclass jupiter-delete (jupiter-operation
+ rudel-delete-op)
+ ()
+ "Objects of this class represent deletions in buffers.")
+
+(defmethod jupiter-transform ((this jupiter-delete) other)
+ "Transform other using THIS.
+OTHER is destructively modified or replaced."
+ (cond
+
+ ;;
+ ;; Transform an insert operation
+ ;;
+ ((jupiter-insert-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+ ;;
+ ;; <other>
+ ;; <this>
+ ;;
+ ((<= other-to this-from))
+
+ ;; <other>
+ ;; <this>
+ ((> other-from this-to)
+ (decf other-from this-length))
+
+ ;; <other>
+ ;; < this >
+ ((and (> other-from this-from) (< other-to this-to))
+ (setq other-from this-from))
+ )))
+ )
+
+ ;;
+ ;; Transform a delete operation
+ ;;
+ ((jupiter-delete-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+
+ ;; <other>
+ ;; <this>
+ ;; OTHER deleted a region after the region deleted by
+ ;; THIS. Therefore OTHER has to be shifted by the length of
+ ;; the deleted region.
+ ((> other-from this-to)
+ (decf other-from this-length)
+ (decf other-to this-length))
+
+ ;; <other>
+ ;; <this>
+ ;; OTHER deleted a region before the region affected by
+ ;; THIS. That is not affected by THIS operation.
+ ((<= other-to this-from))
+
+ ;; < other >
+ ;; <this>
+ ((and (>= other-from this-from) (>= other-to this-to))
+ (decf other-to this-length))
+
+ ;; <other>
+ ;; <this>
+ ((and (< other-from this-from) (< other-to this-to))
+ (decf other-to (- other-to this-to)))
+
+ ;; <other>
+ ;; <this>
+ ;; The region deleted by OTHER overlaps with the region
+ ;; deleted by THIS, such that a part of the region of this is
+ ;; before the region of OTHER. The first part of the region
+ ;; deleted by OTHER has already been deleted. Therefore, the
+ ;; start of OTHER has to be shifted by the length of the
+ ;; overlap.
+ ((and (< other-from this-to) (> other-to this-to))
+ (setq other-from this-from)
+ (incf other-to (+ other-from (- other-to this-to))))
+
+ ;; <other>
+ ;; < this >
+ ;; The region deleted by OTHER is completely contained in
+ ;; the region affected by THIS. Therefore, OTHER must not
+ ;; be executed.
+ ((and (>= other-from this-from) (<= other-to this-to))
+ (setq other (jupiter-nop "nop")))
+
+ (t (error "logic error in (jupiter-transform (x jupiter-delete) (y jupiter-delete))"))
+ ))))
+
+ ;;
+ ;; Transform a compound operation
+ ;;
+ ((jupiter-compound-p other) ;; TODO encapsulation violation
+ (with-slots (children) other
+ (dolist (child children)
+ (setf child (jupiter-transform this child)))))
+
+ ;;
+ ;; Transform a nop operation
+ ;;
+ ((jupiter-nop-p other))
+
+ ;; TODO this is for debugging
+ (t (error "Cannot transform operation of type `%s'"
+ (object-class other))))
+ other)
+
+(defmethod object-print ((this jupiter-delete) &rest strings)
+ "Add from, to and length to string representation of THIS."
+ (with-slots (from to length) this
+ (call-next-method
+ this
+ (format " from %d" from)
+ (format " to %d" to)
+ (format " length %d" length)))
+ )
+
+(provide 'jupiter-delete)
+;;; jupiter-delete.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter-insert.el b/emacs.d/lisp/rudel/jupiter/jupiter-insert.el
new file mode 100644
index 0000000..339270e
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter-insert.el
@@ -0,0 +1,165 @@
+;;; jupiter-insert.el --- Jupiter insert operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, insert
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-insert' implements an insert operation for the
+;; Jupiter algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-insert
+;;
+
+(defclass jupiter-insert (jupiter-operation
+ rudel-insert-op)
+ ()
+ "Objects of this class represent insertions into buffers.")
+
+(defmethod jupiter-transform ((this jupiter-insert) other)
+ "Transform OTHER using THIS."
+ (cond
+
+ ;;
+ ;; Transform an insert operation
+ ;;
+ ((jupiter-insert-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)
+ (this-data :data)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)
+ (other-data :data)) other
+ (cond
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; No need to do anything in this case.
+ ;; ((< other-from this-from))
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;;
+ ((> other-from this-from)
+ (incf other-from this-length))
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; OTHER inserted at the same start position as we did. Since
+ ;; the situation is symmetric in the location properties of
+ ;; OTHER and THIS, we use the inserted data to construct an
+ ;; ordering.
+ ((= other-from this-from)
+ (when (string< this-data other-data)
+ (incf other-from this-length)))))))
+
+ ;;
+ ;; Transform a delete operation
+ ;;
+ ((jupiter-delete-p other)
+ (with-slots ((this-from :from)
+ (this-to :to)
+ (this-length :length)) this
+ (with-slots ((other-from :from)
+ (other-to :to)
+ (other-length :length)) other
+ (cond
+
+ ;;
+ ;; <other>
+ ;; <this>
+ ;; just keep OTHER
+
+ ;;
+ ;; <other> and <other> and <other>
+ ;; <this> <this> <this>
+ ((>= other-from this-from)
+ (incf other-from this-length)
+ (incf other-to this-length))
+
+ ;;
+ ;; < other >
+ ;; <this>
+ ;; OTHER deleted a region that includes the point at which THIS
+ ;; inserted in its interior. OTHER has to be split into one
+ ;; deletion before and one delete after the inserted data.
+ ((and (< other-from this-from) (> other-to this-to))
+ (setq other
+ (jupiter-compound "compound"
+ :children (list (jupiter-delete "delete-left"
+ :from other-from
+ :to this-from)
+ (jupiter-delete "delete-right"
+ :from this-to
+ :to (+ other-to this-length))))))
+ ))))
+
+ ;;
+ ;; Transform a compound operation
+ ;;
+ ((jupiter-compound-p other) ;; TODO encapsulation violation
+ (with-slots (children) other
+ (dolist (child children)
+ (setf child (jupiter-transform this child)))))
+
+ ;;
+ ;; Transform a nop operation
+ ;;
+ ((jupiter-nop-p other))
+
+ ;; TODO this is for debugging
+ (t (error "Cannot transform operation of type `%s'"
+ (object-class other))))
+ other)
+
+(defmethod object-print ((this jupiter-insert) &rest strings)
+ "Add from, to, length and data to string representation of THIS."
+ (with-slots (from to length data) this
+ (call-next-method
+ this
+ (format " from %d" from)
+ (format " to %d" to)
+ (format " length %d" length)
+ (format " data \"%s\"" data)))
+ )
+
+(provide 'jupiter-insert)
+;;; jupiter-insert.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter-nop.el b/emacs.d/lisp/rudel/jupiter/jupiter-nop.el
new file mode 100644
index 0000000..e0f4a5c
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter-nop.el
@@ -0,0 +1,59 @@
+;;; jupiter-nop.el --- Jupiter no operation
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: jupiter, operation, nop
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Class `jupiter-nop' implements a no-operation for the Jupiter
+;; algorithm.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+
+
+;;; Class jupiter-nop
+;;
+
+(defclass jupiter-nop (jupiter-operation)
+ ()
+ "Operation, which does not change anything.")
+
+(defmethod rudel-apply ((this jupiter-nop) object)
+ "Applying THIS does not change OBJECT.")
+
+(defmethod jupiter-transform ((this jupiter-nop) other)
+ "Transforming OTHER with THIS simply returns OTHER."
+ other)
+
+(provide 'jupiter-nop)
+;;; jupiter-nop.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter-operation.el b/emacs.d/lisp/rudel/jupiter/jupiter-operation.el
new file mode 100644
index 0000000..bc91fee
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter-operation.el
@@ -0,0 +1,61 @@
+;;; jupiter-operation.el --- Operation base class for jupiter algorithm
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Jupiter, operation, base
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; The class jupiter-operation is a base class for Jupiter operation
+;; classes.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-operations)
+
+
+;;; Class jupiter-operation
+;;
+
+(defclass jupiter-operation (rudel-operation)
+ ()
+ "Objects of derived classes represent operations, which change documents.
+Objects can transform each other to produce sequences of
+operations, which produce identical changes than permutations of
+the same operations."
+ :abstract t)
+
+;; This one really could use multiple dispatch
+(defgeneric jupiter-transform ((this jupiter-operation) other)
+ "Transform OTHER such that the effect of applying it after THIS are equal to applying OTHER before THIS unmodified.
+In general, OTHER is destructively modified or replaced.")
+
+(provide 'jupiter-operation)
+;;; jupiter-operation.el ends here
diff --git a/emacs.d/lisp/rudel/jupiter/jupiter.el b/emacs.d/lisp/rudel/jupiter/jupiter.el
new file mode 100644
index 0000000..d285041
--- /dev/null
+++ b/emacs.d/lisp/rudel/jupiter/jupiter.el
@@ -0,0 +1,135 @@
+;;; jupiter.el --- An implementation of the Jupiter algorithm
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, jupiter, algorithm, distributed, integrity
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains an implementation of the jupiter algorithm,
+;; which ensures the synchronization of data shared between multiple
+;; peers despite differences in network latency.
+;;
+;; This implementation is partly based on the implementation used in
+;; the obby library <http://gobby.0x539.de/trac/>. Note, however, that
+;; the details of the implementations differ.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'jupiter-operation)
+(require 'jupiter-insert)
+(require 'jupiter-delete)
+(require 'jupiter-compound)
+(require 'jupiter-nop)
+
+
+;;; Class jupiter-context
+;;
+
+(defclass jupiter-context ()
+ ((local-revision :initarg :local-revision
+ :type (integer 0)
+ :initform 0
+ :documentation
+ "Revision number of the local data.")
+ (remote-revision :initarg :remote-revision
+ :type (integer 0)
+ :initform 0
+ :documentation
+ "Revision number of the remote data.")
+ (local-log :initarg :local-log
+ :type list
+ :initform nil
+ :documentation
+ "List of local operations, that have not been
+acknowledged by the remote side."))
+ "Objects of this class store the state of one side of a
+concurrent modification activity, which is synchronized using the
+jupiter algorithm.")
+
+(defmethod jupiter-local-operation ((this jupiter-context) operation)
+ "Store OPERATION in the operation log of THIS and increase local revision count."
+ (with-slots (local-revision local-log) this
+ (push (cons local-revision operation) local-log)
+ (incf local-revision)))
+
+(defmethod jupiter-remote-operation ((this jupiter-context)
+ local-revision remote-revision
+ operation)
+ "Transform OPERATION with revisions LOCAL-REVISION and REMOTE-REVISION using the local operations stored in THIS.
+LOCAL-REVISION is the local revision of THIS context, the remote
+site is referring to."
+ (let ((transformed-operation operation))
+ (with-slots ((this-remote-revision :remote-revision)
+ local-log) this
+
+ ;; Discard stored local operations which are older than the
+ ;; local revision to which the remote site refers.
+ (setq local-log (delete-if
+ (lambda (revision) (< revision local-revision))
+ local-log
+ :key 'car))
+
+ ;; Transform the operation
+ (mapc
+ (lambda (log-operation)
+
+ ;; Transform the remote operation using the stored operation.
+ (setq transformed-operation
+ (jupiter-transform (cdr log-operation)
+ transformed-operation))
+
+ ;; Transform the stored operation using the already
+ ;; transformed remote operation.
+ (setf (cdr log-operation)
+ (jupiter-transform transformed-operation
+ (cdr log-operation))))
+ (reverse local-log))
+
+ ;; Increase remote revision
+ (incf this-remote-revision))
+ ;; The transformed operation is the result of the computation.
+ transformed-operation)
+ )
+
+(defmethod object-print ((this jupiter-context) &rest strings)
+ "Add revisions and log length to string representation of THIS."
+ (with-slots (local-revision remote-revision local-log) this
+ (call-next-method
+ this
+ (format " local %d" local-revision)
+ (format " remote %d" remote-revision)
+ (format " log-items %d" (length local-log)))))
+
+(provide 'jupiter)
+;;; jupiter.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/all-wcprops b/emacs.d/lisp/rudel/obby/.svn/all-wcprops
new file mode 100644
index 0000000..1794a33
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/all-wcprops
@@ -0,0 +1,53 @@
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svnroot/rudel/!svn/ver/468/trunk/obby
+END
+rudel-obby-client.el
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/rudel/!svn/ver/397/trunk/obby/rudel-obby-client.el
+END
+rudel-obby-state.el
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svnroot/rudel/!svn/ver/330/trunk/obby/rudel-obby-state.el
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/215/trunk/obby/Project.ede
+END
+rudel-obby.el
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/397/trunk/obby/rudel-obby.el
+END
+rudel-obby-debug.el
+K 25
+svn:wc:ra_dav:version-url
+V 58
+/svnroot/rudel/!svn/ver/318/trunk/obby/rudel-obby-debug.el
+END
+rudel-obby-server.el
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/rudel/!svn/ver/356/trunk/obby/rudel-obby-server.el
+END
+rudel-obby-errors.el
+K 25
+svn:wc:ra_dav:version-url
+V 59
+/svnroot/rudel/!svn/ver/319/trunk/obby/rudel-obby-errors.el
+END
+rudel-obby-util.el
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/rudel/!svn/ver/468/trunk/obby/rudel-obby-util.el
+END
diff --git a/emacs.d/lisp/rudel/obby/.svn/entries b/emacs.d/lisp/rudel/obby/.svn/entries
new file mode 100644
index 0000000..2d21fc4
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/entries
@@ -0,0 +1,300 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/obby
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-16T01:48:03.160288Z
+468
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+rudel-obby-client.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+9cb0ae63b9f86199be36f208feb51b26
+2009-10-10T00:39:13.745463Z
+397
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+30971
+
+rudel-obby-state.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+f7a018739f96fe975da0ab4cc112e7e4
+2009-10-03T01:58:59.186010Z
+330
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4955
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+a99a4bf5a1243e8bd25e87d74b02db1d
+2009-10-03T00:45:44.545055Z
+215
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+388
+
+rudel-obby.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+af5ba069b2183fac68261ba2d34f199d
+2009-10-10T00:39:13.745463Z
+397
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+15453
+
+rudel-obby-debug.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+915461ef0b7ccb7dbad60a69aa973389
+2009-10-03T01:56:22.854481Z
+318
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3300
+
+rudel-obby-server.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+cd9ab22e9a8d09b558693edfc7b5505a
+2009-10-03T02:08:53.322972Z
+356
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+24935
+
+rudel-obby-errors.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+72c6c1dfe7ec7b8a95d5808d439088dd
+2009-10-03T01:56:39.182216Z
+319
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1839
+
+rudel-obby-util.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+991ece971eaeba3b86359fc05a410b9d
+2009-10-16T01:48:03.160288Z
+468
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+9523
+
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..53d2422
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,14 @@
+;; Object rudel/obby
+;; EDE project file.
+(ede-proj-project "rudel/obby"
+ :name "obby"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "obby"
+ :name "obby"
+ :path ""
+ :source '("rudel-obby.el" "rudel-obby-util.el" "rudel-obby-client.el" "rudel-obby-server.el" "rudel-obby-errors.el" "rudel-obby-state.el")
+ :aux-packages '("rudel" "jupiter")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-client.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-client.el.svn-base
new file mode 100644
index 0000000..5c192db
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-client.el.svn-base
@@ -0,0 +1,973 @@
+;;; rudel-obby-client.el --- Client functions of the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, client
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the client part of the obby backend.
+
+
+;;; History:
+;;
+;; 0.2 - State machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter)
+
+(require 'rudel-state-machine)
+(require 'rudel-operations)
+(require 'rudel-chat)
+
+(require 'rudel-obby-errors)
+(require 'rudel-obby-util)
+(require 'rudel-obby-state)
+
+
+;;; Class rudel-obby-client-state-new
+;;
+
+(defclass rudel-obby-client-state-new
+ (rudel-obby-client-connection-state)
+ ()
+ "Start state of newly established connections.")
+
+(defmethod rudel-obby/obby_welcome
+ ((this rudel-obby-client-state-new) version)
+ "Handle obby 'welcome' message."
+ ;; Examine announced protocol version.
+ (with-parsed-arguments ((version number))
+ (message "Received Obby welcome message (version %d)" version))
+ ;; Start encryption handshake
+ 'encryption-negotiate)
+
+
+;;; Class rudel-obby-client-state-encryption-negotiate
+;;
+
+(defclass rudel-obby-client-state-encryption-negotiate
+ (rudel-obby-client-connection-state)
+ ()
+ "Start state of the encryption handshake.")
+
+(defmethod rudel-obby/net6_encryption
+ ((this rudel-obby-client-state-encryption-negotiate) value)
+ "Handle net6 'encryption' message."
+ (rudel-send this "net6_encryption_ok")
+ 'encryption-start)
+
+
+;;; Class rudel-obby-client-connection-encryption-start
+;;
+
+(defclass rudel-obby-client-state-encryption-start
+ (rudel-obby-client-connection-state)
+ ()
+ "Second state of the encryption handshake.")
+
+(defmethod rudel-obby/net6_encryption_begin
+ ((this rudel-obby-client-state-encryption-start))
+ "Handle net6 'encryption_begin' message."
+ ;; Start TLS encryption for the connection.
+ (with-slots (connection) this
+ (with-slots (socket) connection
+ (when (rudel-process-object socket :supports-tls)
+ (rudel-tls-start-tls socket)
+ (sit-for 1))))
+
+ ;; The connection is now established
+ 'joining)
+
+(defmethod rudel-obby/net6_encryption_failed
+ ((this rudel-obby-client-state-encryption-start))
+ "Handle net6 'encryption_failed' message."
+ ;; The connection is now established; without encryption though
+ 'joining)
+
+
+;;; Class rudel-obby-client-state-joining
+;;
+
+(defclass rudel-obby-client-state-joining
+ (rudel-obby-client-connection-state)
+ ()
+ "First state after the connection has been properly set up.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-joining))
+ "When entering this state, send a login request."
+ ;; Send login request with username and color. This can easily fail
+ ;; (resulting in response 'net6_login_failed') if the username or
+ ;; color is already taken.
+ (with-slots (info) (oref this connection)
+ (let ((username (plist-get info :username))
+ (color (plist-get info :color))
+ (global-password (plist-get info :global-password))
+ (user-password (plist-get info :user-password)))
+ (apply #'rudel-send
+ this
+ "net6_client_login"
+ username (rudel-obby-format-color color)
+ (append (when global-password
+ (list global-password))
+ (when (and global-password user-password)
+ (list user-password))))))
+ nil)
+
+(defmethod rudel-obby/obby_sync_init
+ ((this rudel-obby-client-state-joining) count)
+ "Handle obby 'sync_init' message."
+ ;; Switch to 'synching' state, passing the number of synchronization
+ ;; items.
+ (with-parsed-arguments ((count number))
+ (list 'session-synching count)))
+
+(defmethod rudel-obby/net6_login_failed
+ ((this rudel-obby-client-state-joining) reason)
+ "Handle net6 'login_failed' message."
+ (with-parsed-arguments ((reason number))
+ (with-slots (connection) this
+ (let ((error-data
+ (cond
+ ;; Invalid username
+ ((= reason rudel-obby-error-username-invalid)
+ (cons 'rudel-obby-username-invalid nil))
+ ;; Username in use
+ ((= reason rudel-obby-error-username-in-use)
+ (cons 'rudel-obby-username-in-use nil))
+ ;; Color in use
+ ((= reason rudel-obby-error-color-in-use)
+ (cons 'rudel-obby-color-in-use nil))
+ ;; Wrong global password
+ ((= reason rudel-obby-error-wrong-global-password)
+ (cons 'rudel-obby-wrong-global-password nil))
+ ;; Wrong user password
+ ((= reason rudel-obby-error-wrong-user-password)
+ (cons 'rudel-obby-wrong-user-password nil))
+ ;; Otherwise, signal a generic join error
+ (t (cons 'rudel-join-error nil)))))
+
+ ;; Switch to 'join-failed' state, pass the error data.
+ (list 'join-failed error-data))))
+ )
+
+
+;;; Class rudel-obby-client-state-join-failed
+;;
+
+(defclass rudel-obby-client-state-join-failed
+ (rudel-obby-client-connection-state)
+ ((error-symbol :initarg :error-symbol
+ :type symbol
+ :documentation
+ "Error symbol describing the reason for the
+login failure.")
+ (error-data :initarg :error-data
+ :type list
+ :documentation
+ "Additional error data describing the login
+failure."))
+ "State for failed login attempts.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-join-failed)
+ error)
+ "When the state is entered, store the error data passed in ERROR."
+ (with-slots (error-symbol error-data) this
+ (setq error-symbol (car error)
+ error-data (cdr error)))
+ nil)
+
+
+;;; Class rudel-obby-client-state idle
+;;
+
+(defclass rudel-obby-client-state-idle
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ()
+ "Default state of the connection.")
+
+(defmethod rudel-obby/net6_client_join
+ ((this rudel-obby-client-state-idle)
+ client-id name encryption user-id color)
+ "Handle net6 'client_join' message."
+ (with-parsed-arguments ((client-id number)
+ (user-id number)
+ (color color))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'eq #'rudel-id)))
+ (if user
+ ;; If we have such a user object, update its state.
+ (with-slots ((client-id1 client-id)
+ (color1 color)
+ connected
+ (encryption1 encryption)) user
+ (setq client-id1 client-id
+ color1 color
+ connected t
+ encryption1 (string= encryption "1"))
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook))
+ ;; Otherwise, create a new user object.
+ (let ((user (rudel-obby-user
+ name
+ :client-id client-id
+ :user-id user-id
+ :connected t
+ :encryption (string= encryption "1")
+ :color color)))
+ (rudel-add-user session user))))))
+ (message "Client joined: %s %s" name color))
+ nil)
+
+(defmethod rudel-obby/net6_client_part
+ ((this rudel-obby-client-state-idle) client-id)
+ "Handle net6 'client_part' message."
+ ;; Find the user object, associated to the client id. Remove the
+ ;; client id and change the user's state to disconnected.
+ (with-parsed-arguments ((client-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session client-id
+ #'eql #'rudel-client-id)))
+ (if user
+ (with-slots (client-id connected) user
+ ;; Set slot values.
+ (setq client-id nil
+ connected nil)
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook))
+ (display-warning
+ '(rudel obby)
+ (format "Cannot find user for client id: %d"
+ client-id)
+ :warning))))))
+ nil)
+
+(defmethod rudel-obby/obby_user_colour
+ ((this rudel-obby-client-state-idle) user-id color)
+ "Handle obby 'user_colour' message."
+ (with-parsed-arguments ((user-id number)
+ (color color))
+ ;; Find user object and set color.
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (with-slots ((name :object-name) (color1 :color)) user
+ ;; Set color in user object.
+ (setq color1 color)
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook)
+
+ ;; Update overlays.
+ (rudel-overlay-set-face-attributes
+ (rudel-overlay-make-face-symbol 'author name)
+ color1))))))
+ nil)
+
+(defmethod rudel-obby/obby_document_create
+ ((this rudel-obby-client-state-idle)
+ owner-id doc-id name suffix encoding)
+ "Handle obby 'document_create' message."
+ (with-parsed-arguments ((owner-id number)
+ (doc-id number)
+ (suffix number)
+ (encoding coding-system))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((owner (rudel-find-user session owner-id
+ #'= #'rudel-id)))
+ (rudel-add-document session (rudel-obby-document
+ name
+ :subscribed (list owner)
+ :id doc-id
+ :owner-id owner-id
+ :suffix suffix))))
+ (message "New document: %s" name)))
+ nil)
+
+(defmethod rudel-obby/obby_document_remove
+ ((this rudel-obby-client-state-idle) doc-id)
+ "Handle obby 'document_remove' message."
+ (with-parsed-arguments ((doc-id document-id))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((document (rudel-find-document
+ session doc-id
+ #'equal #'rudel-both-ids)))
+ (if document
+ (progn
+ (rudel-remove-document session document)
+ (with-slots ((name :object-name)) document
+ (message "Document removed: %s" name)))
+ (display-warning
+ '(rudel obby)
+ (format "Document not found: %s" doc-id)
+ :warning))))))
+ nil)
+
+(defmethod rudel-obby/obby_document/rename
+ ((this rudel-obby-client-state-idle)
+ document user new-name new-suffix)
+ "Handle obby 'rename' submessage of the 'obby_document' message."
+ (with-parsed-arguments ((new-suffix number))
+ (with-slots ((name :object-name) suffix) document
+ (setq name new-name
+ suffix new-suffix)))
+ nil)
+
+(defmethod rudel-obby/obby_document/subscribe
+ ((this rudel-obby-client-state-idle)
+ document user-id)
+ "Handle 'subscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (rudel-add-user document user)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/unsubscribe
+ ((this rudel-obby-client-state-idle)
+ document user-id)
+ "Handle 'unsubscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (rudel-remove-user document user)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record
+ ((this rudel-obby-client-state-idle)
+ document user-id local-revision remote-revision
+ action &rest arguments)
+ "Handle 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number)
+ (local-revision number)
+ (remote-revision number))
+ ;; Locate the user.
+ (let ((user (with-slots (connection) this
+ (with-slots (session) connection
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))))
+ (if user
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch
+ this "rudel-obby/obby_document/record/" action
+ (append (list document user local-revision remote-revision)
+ arguments))
+ ;; Warn if we failed to locate or execute the
+ ;; method. Return nil in this case, so we remain in the
+ ;; current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s:%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby/obby_document/record/" action arguments)
+ :debug)
+ nil)))
+ ;; If we did not find the user, warn.
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "User not found: %d" user-id)
+ :warning)
+ nil))))
+ )
+
+(defmethod rudel-obby/obby_document/record/ins
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ position data)
+ "Handle 'ins' submessage of 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((position number))
+ (let ((operation (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :data data)))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/del
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ position length)
+ "Handle 'del' submessage of 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((position number)
+ (length number))
+ (let ((operation (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :to (+ position length))))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/split
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ &rest operations)
+ "Handle 'split' submessage of 'record' submessage of obby 'document' message."
+ (let ((operation (rudel-message->operation
+ (cons "split" operations)
+ local-revision remote-revision)))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation)))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/noop
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision)
+ "Handle 'noop' submessage of 'record' submessage of obby 'document' message."
+ (let ((operation (jupiter-nop
+ (format "nop-%d-%d"
+ remote-revision local-revision))))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation)))
+ nil)
+
+(defmethod rudel-obby/obby_message ((this rudel-obby-client-state-idle)
+ sender text)
+ "Handle obby 'message' message"
+ (with-parsed-arguments ((sender number))
+ (with-slots (session) (oref this :connection)
+ (let ((sender (rudel-find-user session sender #'eq #'rudel-id)))
+ (rudel-chat-dispatch-message sender text))))
+ nil)
+
+
+;;; Class rudel-obby-client-state-session-synching
+;;
+
+(defclass rudel-obby-client-state-session-synching
+ (rudel-obby-client-connection-state)
+ ((all-items :initarg :all-items
+ :type (integer 0)
+ :documentation
+ "Total number of synchronization items expected
+ to receive from the server.")
+ (remaining-items :initarg :remaining-items
+ :type (integer 0)
+ :documentation
+ "Number of synchronization items not yet
+ received from the server.")
+ (have-self :initarg :have-self
+ :type boolean
+ :documentation
+ "Flag that remembers, whether the session has
+ a 'self' user object."))
+ "State used for synching session data.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-session-synching)
+ num-items)
+ "When entering state, store number of expected items."
+ (with-slots (all-items remaining-items have-self) this
+ (setq all-items num-items
+ remaining-items num-items
+ have-self nil))
+ nil)
+
+(defmethod rudel-obby/net6_client_join
+ ((this rudel-obby-client-state-session-synching)
+ client-id name encryption user-id color)
+ "Handle net6 'client_join' message."
+ (with-parsed-arguments ((client-id number)
+ (user-id number)
+ (color color))
+ (with-slots (connection remaining-items have-self) this
+ (with-slots (session) connection
+ ;; Construct user object and add it to the session.
+ (let ((user (rudel-obby-user
+ name
+ :client-id client-id
+ :user-id user-id
+ :connected t
+ :encryption (string= encryption "1")
+ :color color)))
+ (rudel-add-user session user)
+
+ ;; The first user object describes the user of this client.
+ (unless have-self
+ (with-slots (self) session
+ (setq self user
+ have-self t)))))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_usertable_user
+ ((this rudel-obby-client-state-session-synching) user-id name color)
+ "Handle obby 'sync_usertable_user' message."
+ (with-parsed-arguments ((user-id number)
+ (color color))
+ (with-slots (connection remaining-items) this
+ (with-slots (session) connection
+ (rudel-add-user session (rudel-obby-user
+ name
+ :user-id user-id
+ :connected nil
+ :color color)))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_doclist_document
+ ((this rudel-obby-client-state-session-synching)
+ owner-id doc-id name suffix encoding &rest subscribed-user-ids)
+ "Handle obby 'sync_doclist_document' message."
+ (with-parsed-arguments ((doc-id number)
+ (owner-id number)
+ (suffix number)
+ (encoding coding-system))
+ (with-slots (connection remaining-items) this
+ (with-slots (session) connection
+ ;; Retrieve the subscribed users
+ (let ((subscribed-users
+ (mapcar
+ (lambda (user-id)
+ (with-parsed-arguments ((user-id number))
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ subscribed-user-ids)))
+
+ ;; Make a new document with the list of subscribed users.
+ (rudel-add-document session (rudel-obby-document
+ name
+ :subscribed subscribed-users
+ :id doc-id
+ :owner-id owner-id
+ :suffix suffix))))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_final
+ ((this rudel-obby-client-state-session-synching))
+ "Handle obby 'sync_final' message."
+ 'idle)
+
+(defmethod object-print ((this rudel-obby-client-state-session-synching)
+ &rest strings)
+ "Append number of remaining items to string representation."
+ (with-slots (remaining-items) this
+ (call-next-method this (format " remaining: %d" remaining-items))))
+
+
+;;; Class rudel-obby-client-state-subscribing
+;;
+
+(defclass rudel-obby-client-state-subscribing
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ((document :initarg :document
+ :type rudel-obby-document-child
+ :documentation
+ ""))
+ "")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-subscribing)
+ user document)
+ "When entering this state, send a subscription request to the server."
+ (with-slots ((document1 :document)) this
+ (setq document1 document)
+
+ (with-slots ((doc-id :id) owner-id) document1
+ (with-slots (user-id) user
+ (rudel-send this "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "subscribe"
+ (format "%x" user-id)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/sync_init
+ ((this rudel-obby-client-state-subscribing)
+ document num-bytes)
+ "Handle obby 'sync_init' message."
+ (with-parsed-arguments ((num-bytes number))
+ (with-slots (documents) this
+ (if (= num-bytes 0)
+ 'idle
+ (list 'document-synching document num-bytes))))
+ )
+
+
+;;; Class rudel-obby-client-state-document-synching
+;;
+
+(defclass rudel-obby-client-state-document-synching
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ((document :initarg :document
+ :type rudel-obby-document-child
+ :documentation
+ "")
+ (all-bytes :initarg :all-bytes
+ :type (integer 0)
+ :documentation
+ "")
+ (remaining-bytes :initarg :remaining-bytes
+ :type (integer 0)
+ :documentation
+ ""))
+ "")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-document-synching)
+ document num-bytes)
+ ""
+ (with-slots ((document1 :document) all-bytes remaining-bytes) this
+ (setq document1 document
+ all-bytes num-bytes
+ remaining-bytes num-bytes))
+ nil)
+
+(defmethod rudel-obby/obby_document/sync_chunk
+ ((this rudel-obby-client-state-document-synching)
+ document data user-id)
+ "Handle obby 'sync_chunk' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection remaining-bytes) this
+ (with-slots (session) connection
+ (let* ((user (unless (zerop user-id)
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (operation (rudel-insert-op "bulk-insert"
+ :from nil
+ :data data)))
+ (rudel-remote-operation document user operation)))
+
+ ;; After all bytes are transferred, go back to idle state.
+ (decf remaining-bytes (string-bytes data))
+ (if (= remaining-bytes 0)
+ 'idle
+ nil)))
+ )
+
+(defmethod object-print ((this rudel-obby-client-state-document-synching)
+ &rest strings)
+ "Append number of remaining items to string representation."
+ (with-slots (remaining-bytes) this
+ (call-next-method this (format " remaining: %d" remaining-bytes))))
+
+
+;;; Class rudel-obby-client-state-they-finalized
+;;
+
+(defclass rudel-obby-client-state-they-finalized
+ (rudel-obby-client-connection-state)
+ ()
+ "State used to indicate that the connection was closed by the peer.")
+
+
+;;; Client connection states.
+;;
+
+(defvar rudel-obby-client-connection-states
+ '((new . rudel-obby-client-state-new)
+ (encryption-negotiate . rudel-obby-client-state-encryption-negotiate)
+ (encryption-start . rudel-obby-client-state-encryption-start)
+ (joining . rudel-obby-client-state-joining)
+ (join-failed . rudel-obby-client-state-join-failed)
+ (idle . rudel-obby-client-state-idle)
+ (session-synching . rudel-obby-client-state-session-synching)
+ (subscribing . rudel-obby-client-state-subscribing)
+ (document-synching . rudel-obby-client-state-document-synching)
+ (they-finalized . rudel-obby-client-state-they-finalized))
+ "Name symbols and classes of connection states.")
+
+
+;;; Class rudel-obby-connection
+;;
+
+(defclass rudel-obby-connection (rudel-obby-socket-owner
+ rudel-connection
+ rudel-state-machine)
+ ((info :initarg :info
+ :type list
+ :documentation
+ "Stores connection information for later use.")
+ (contexts :initarg :contexts
+ :type hash-table
+ :documentation
+ "Contains jupiter context objects for all
+documents."))
+ "Class rudel-obby-connection ")
+
+(defmethod initialize-instance ((this rudel-obby-connection) &rest slots)
+ ;; Initialize slots of THIS
+ (when (next-method-p)
+ (call-next-method))
+
+ ;; Create a new hash-table object to hold jupiter contexts
+ ;; associated to documents.
+ (with-slots (contexts) this
+ (setq contexts (make-hash-table :test #'equal)))
+
+ ;; Register states.
+ (rudel-register-states this rudel-obby-client-connection-states)
+ )
+
+(defmethod rudel-register-state ((this rudel-obby-connection)
+ symbol state)
+ "Register SYMBOL and STATE and set connection slot of STATE."
+ ;; Associate THIS connection to STATE.
+ (oset state :connection this)
+
+ ;; Register STATE.
+ (when (next-method-p)
+ (call-next-method))
+ )
+
+(defmethod rudel-disconnect ((this rudel-obby-connection))
+ ""
+ (when (next-method-p)
+ (call-next-method)))
+
+(defmethod rudel-close ((this rudel-obby-connection))
+ ""
+ ;; Move the state machine into an error state.
+ (rudel-switch this 'they-finalized)
+
+ ;; Terminate the session.
+ (with-slots (session) this
+ (rudel-end session)))
+
+(defmethod rudel-find-context ((this rudel-obby-connection) document)
+ "Return the jupiter context associated to DOCUMENT in THIS connection."
+ (with-slots (contexts) this
+ (gethash (oref document :id) contexts)))
+
+(defmethod rudel-add-context ((this rudel-obby-connection) document)
+ "Add a jupiter context for DOCUMENT to THIS connection."
+ (with-slots (contexts) this
+ (with-slots ((doc-name :object-name) (doc-id :id)) document
+ (puthash doc-id
+ (jupiter-context (format "%s" doc-name))
+ contexts)))
+ )
+
+(defmethod rudel-remove-context ((this rudel-obby-connection) document)
+ "Remove the jupiter context associated to DOCUMENT from THIS connection."
+ (with-slots (contexts) this
+ (remhash (oref document :id) contexts)))
+
+(defmethod rudel-message ((this rudel-obby-connection) message)
+ "Dispatch MESSAGE to the current state of THIS object.
+If the state has no suitable method, generate a warning, but do
+nothing else."
+ ;; Dispatch message to state.
+ (rudel-accept this message))
+
+(defmethod rudel-change-color- ((this rudel-obby-connection) color)
+ ""
+ (rudel-send this "obby_user_colour"
+ (rudel-obby-format-color color)))
+
+(defmethod rudel-publish ((this rudel-obby-connection) document)
+ ""
+ ;; Create a new jupiter context for DOCUMENT.
+ (rudel-add-context this document)
+
+ ;; Announce the new document to the server.
+ (with-slots ((name :object-name) id buffer) document
+ (rudel-send this "obby_document_create"
+ (format "%x" id)
+ name
+ "UTF-8"
+ (with-current-buffer buffer
+ (buffer-string))))
+ )
+
+(defmethod rudel-unpublish ((this rudel-obby-connection) document)
+ "Remove DOCUMENT from the obby session THIS is connected to."
+ ;; Request removal of DOCUMENT.
+ (with-slots ((doc-id :id) owner-id) document
+ (rudel-send this "obby_document_remove"
+ (format "%x %x" owner-id doc-id)))
+
+ ;; Remove the jupiter context for DOCUMENT.
+ (rudel-remove-context this document)
+ )
+
+(defmethod rudel-subscribe-to ((this rudel-obby-connection) document)
+ ""
+ ;; Create a new jupiter context for DOCUMENT.
+ (rudel-add-context this document)
+
+ ;; Switch to subscribing state and wait until the state goes back to
+ ;; idle.
+ (with-slots (session) this
+ (with-slots (self) session
+ (rudel-switch this 'subscribing self document)))
+
+ (lexical-let ((reporter (make-progress-reporter "Subscribing " 0.0 1.0)))
+ (flet ((display-progress (state)
+ (cond
+ ;; Syncing document content, we can provide detailed progress.
+ ((and (consp state)
+ (eq (car state) 'document-synching))
+ (with-slots (all-bytes remaining-bytes) (cdr state)
+ (progress-reporter-force-update
+ reporter
+ (- 1.0 (/ (float remaining-bytes) (float all-bytes)))
+ (format "Subscribing (%s) " (car state)))))
+
+ ;; For other states, we just spin.
+ ((consp state)
+ (progress-reporter-force-update
+ reporter 0.5
+ (format "Subscribing (%s) " (car state))))
+
+ ;; Done
+ (t
+ (progress-reporter-force-update reporter 1.0 "Subscribing ")
+ (progress-reporter-done reporter)))))
+ (rudel-state-wait this '(idle) '(they-finalized) #'display-progress)))
+
+ ;; We receive a notification of our own subscription from the
+ ;; server. Consequently we do not add SELF to the list of subscribed
+ ;; users of DOCUMENT.
+ )
+
+(defmethod rudel-unsubscribe-from ((this rudel-obby-connection) document)
+ ""
+ ;; Delete the jupiter context for DOCUMENT.
+ (rudel-remove-context this document)
+
+ ;; Announce the end of our subscription to the server.
+ (with-slots (session) this
+ (with-slots (user-id) (oref session :self)
+ (with-slots ((doc-id :id) owner-id) document
+ (rudel-send this "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "unsubscribe"
+ (format "%x" user-id)))))
+
+ ;; We receive a notification of the end of our own subscription from
+ ;; the server. Consequently we do not remove SELF from the list of
+ ;; subscribed users of DOCUMENT.
+ )
+
+(defmethod rudel-local-insert ((this rudel-obby-connection)
+ document position data)
+ ""
+ (rudel-local-operation
+ this
+ document
+ (jupiter-insert "insert" :from position :data data)))
+
+(defmethod rudel-local-delete ((this rudel-obby-connection)
+ document position length)
+ ""
+ (rudel-local-operation
+ this
+ document
+ (jupiter-delete "delete" :from position :to (+ position length))))
+
+(defmethod rudel-local-operation ((this rudel-obby-connection)
+ document operation)
+ "Handle OPERATION performed on DOCUMENT by sending a message through THIS connection."
+ ;; Convert character positions in OPERATION to byte positions, since
+ ;; the obby protocol works with byte positions, but Emacs uses
+ ;; character positions.
+ (with-slots (buffer) document
+ (rudel-obby-char->byte operation buffer))
+
+ ;; Find jupiter context for DOCUMENT.
+ (let ((context (rudel-find-context this document)))
+
+ ;; Notify the server of the operation.
+ (with-slots (owner-id (doc-id :id)) document
+ (with-slots (local-revision remote-revision) context
+ (apply #'rudel-send
+ this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "record"
+ (format "%x" local-revision)
+ (format "%x" remote-revision)
+ (rudel-operation->message operation))))
+
+ ;; Submit the operation to the jupiter context.
+ (jupiter-local-operation context operation))
+ )
+
+(defmethod rudel-remote-operation ((this rudel-obby-connection)
+ document user
+ remote-revision local-revision
+ operation)
+ "Handle OPERATION received through THIS connection performed by USER on DOCUMENT."
+ (let* (;; Find jupiter context for DOCUMENT.
+ (context (rudel-find-context this document))
+ ;; And transform the operation.
+ (transformed (jupiter-remote-operation
+ context
+ remote-revision local-revision
+ operation)))
+
+ ;; Convert byte positions in OPERATION to character positions,
+ ;; since the obby protocol works with byte positions, but Emacs
+ ;; uses character positions.
+ (with-slots (buffer) document
+ (rudel-obby-byte->char transformed buffer)) ;; TODO operation's responsibility?
+
+ ;; Apply the transformed operation to the document.
+ (rudel-remote-operation document user transformed))
+ )
+
+(provide 'rudel-obby-client)
+;;; rudel-obby-client.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-debug.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-debug.el.svn-base
new file mode 100644
index 0000000..8f5f168
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-debug.el.svn-base
@@ -0,0 +1,122 @@
+;;; rudel-obby-debug.el --- Debugging functions for obby backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, debugging
+;; X-RCS: $Id:$
+;;
+;; 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 3 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, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Debugging functions for the obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-debug)
+
+(require 'rudel-obby-util)
+
+
+;;; Variables
+;;
+
+(defvar rudel-obby-debug-old-state nil
+ "Saves state of state machines across one function call.")
+
+
+;;; Functions
+;;
+
+(defmethod rudel-send :before ((this rudel-obby-socket-owner)
+ name &rest arguments)
+ "Print NAME and ARGUMENTS to debug stream."
+ (let ((message (apply #'rudel-obby-assemble-message
+ name arguments)))
+
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :sent
+ (concat (substring message 0 (min (length message) 100))
+ (when (> (length message) 100)
+ "..."))
+ (append (list name) arguments))))
+ )
+
+(defmethod rudel-receive :before ((this rudel-obby-socket-owner) data)
+ "Print DATA to debug stream."
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :received
+ (concat (substring data 0 (min (length data) 100))
+ (when (> (length data) 100)
+ "..."))))
+ )
+
+(defmethod rudel-message :before ((this rudel-obby-socket-owner)
+ message)
+ "Print DATA to debug stream."
+ (let ((data (apply #'rudel-obby-assemble-message message)))
+
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :received-processed
+ (concat (substring data 0 (min (length data) 100))
+ (when (> (length data) 100)
+ "..."))
+ message)
+ ))
+ )
+
+(defmethod rudel-switch :before ((this rudel-obby-socket-owner)
+ state &rest arguments)
+ "Store name of STATE for later printing."
+ (with-slots (state) this
+ (setq rudel-obby-debug-old-state
+ (if state
+ (object-name-string state)
+ "#start")))
+ )
+
+(defmethod rudel-switch :after ((this rudel-obby-socket-owner)
+ state &rest arguments)
+ "Print STATE and ARGUMENTS to debug stream."
+ (with-slots (socket state) this
+ (let ((old-state rudel-obby-debug-old-state)
+ (new-state (object-name-string state)))
+ (unless (string= old-state new-state)
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :special
+ (if arguments
+ (format "%s -> %s %s" old-state new-state arguments)
+ (format "%s -> %s" old-state new-state))))))
+ )
+
+(provide 'rudel-obby-debug)
+;;; rudel-obby-debug.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-errors.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-errors.el.svn-base
new file mode 100644
index 0000000..689d4a8
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-errors.el.svn-base
@@ -0,0 +1,65 @@
+;;; rudel-obby-errors.el --- Error data used in the obby Rudel backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, errors
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains definitions of error conditions and numeric
+;; error codes used in the Rudel obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+
+;;; Obby protocol error codes
+;;
+
+(defconst rudel-obby-error-username-invalid #x0001
+ "Error code for invalid username.")
+
+(defconst rudel-obby-error-username-in-use #x0002
+ "Error code for username already in use.")
+
+(defconst rudel-obby-error-color-in-use #x0100
+ "Error code for color already in use.")
+
+(defconst rudel-obby-error-wrong-global-password #x0101
+ "Error code for wrong global password.")
+
+(defconst rudel-obby-error-wrong-user-password #x0102
+ "Error code for wrong user password.")
+
+(defconst rudel-obby-error-protocol-version-mismatch #x0103
+ "Error code for protocol version mismatch.")
+
+(defconst rudel-obby-error-not-encrypted #x0104
+ "Error code for not encrypted.")
+
+(provide 'rudel-obby-errors)
+;;; rudel-obby-errors.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-server.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-server.el.svn-base
new file mode 100644
index 0000000..5bf1158
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-server.el.svn-base
@@ -0,0 +1,798 @@
+;;; rudel-obby-server.el --- Server component of the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, server
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the server part of the obby backend for Rudel.
+;;
+;; It is implemented using one state machine (class
+;; `rudel-obby-client') for each client connection. These state
+;; machines have the following states:
+;;
+;; + new `rudel-obby-server-state-new'
+;; + encryption-negotiate `rudel-obby-server-state-encryption-negotiate'
+;; + before-join `rudel-obby-server-state-before-join'
+;; + idle `rudel-obby-server-state-idle'
+
+
+;;; History:
+;;
+;; 0.2 - State machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'jupiter)
+
+(require 'rudel-state-machine)
+
+(require 'rudel-obby-errors)
+(require 'rudel-obby-util)
+(require 'rudel-obby-state)
+
+
+;;; Class rudel-obby-server-state-new
+;;
+
+(defclass rudel-obby-server-state-new
+ (rudel-obby-server-connection-state)
+ ()
+ "State in which new connections start out.")
+
+(defmethod rudel-enter ((this rudel-obby-server-state-new))
+ "Sends welcome messages to the client and starts the session
+timeout timer."
+ ;; Send greeting sequence to the client.
+ (rudel-send this
+ "obby_welcome"
+ (number-to-string rudel-obby-protocol-version))
+
+ ;; Switch to encryption negotiation state.
+ 'encryption-negotiate)
+
+
+;;; Class rudel-obby-server-state-encryption-negotiate
+;;
+
+(defclass rudel-obby-server-state-encryption-negotiate
+ (rudel-obby-server-connection-state)
+ ()
+ "Encryption negotiation state.")
+
+(defmethod rudel-enter ((this rudel-obby-server-state-encryption-negotiate))
+ "Send net6 'encryption' message requesting to not enable encryption."
+ (rudel-send this "net6_encryption" "0")
+ nil)
+
+(defmethod rudel-obby/net6_encryption_ok
+ ((this rudel-obby-server-state-encryption-negotiate))
+ "Handle net6 'encryption_ok' message.
+Even if the client requests an encrypted connection, we cancel
+the negotiation."
+ (rudel-send this "net6_encryption_failed")
+ 'before-join)
+
+(defmethod rudel-obby/net6_encryption_failed
+ ((this rudel-obby-server-state-encryption-negotiate))
+ "Handle net6 'encryption_failed' message.
+No action has to be taken, since the client simply proceeds after
+failed encryption negotiation."
+ 'before-join)
+
+
+;;; Class rudel-obby-server-state-before-join
+;;
+
+(defclass rudel-obby-server-state-before-join
+ (rudel-obby-server-connection-state)
+ ()
+ "Waiting for client request joining the session.")
+
+(defmethod rudel-obby/net6_client_login
+ ((this rudel-obby-server-state-before-join) username color
+ &optional global-password user-password)
+ "Handle net6 'client_login' message."
+ (with-parsed-arguments ((color color))
+ (with-slots (server
+ (client-id :id)
+ user
+ encryption) (oref this :connection)
+ ;; Make sure USERNAME and COLOR are valid.
+ (let ((error (rudel-check-username-and-color
+ server username color)))
+ (if error
+ ;; If USERNAME or COLOR are invalid, send the error code
+ ;; to the client and stay in the current state.
+ (progn
+ (rudel-send this
+ "net6_login_failed"
+ (format "%x" error))
+ nil)
+
+ ;; Create a user object for this client and add it to the
+ ;; server.
+ (setq user (rudel-make-user
+ server
+ username client-id color encryption))
+ (rudel-add-user server user)
+
+ ;; Broadcast the join event to all clients (including the
+ ;; new one).
+ (with-slots ((name :object-name) color (user-id :user-id)) user
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "net6_client_join"
+ (format "%x" client-id)
+ name
+ "0"
+ (format "%x" user-id)
+ (rudel-obby-format-color color)))
+
+ ;; Get the new client up to date:
+ ;; - transmit user list
+ ;; - connected users
+ ;; - disconnected users
+ ;; - transmit document list
+ (with-slots (users clients documents) server
+ ;; Send number of synchronization items: sum of numbers of
+ ;; offline users and documents.
+ (let ((number-of-items (+ (length users) (length documents))))
+ (rudel-send this
+ "obby_sync_init"
+ (format "%x" number-of-items)))
+
+ ;; Transmit list of connected users.
+ (dolist (client clients)
+ (with-slots ((client-id :id) user) client
+ (when user
+ (with-slots ((name :object-name)
+ color
+ (user-id :user-id)) user
+ (rudel-send this
+ "net6_client_join"
+ (format "%x" client-id)
+ name
+ "0"
+ (format "%x" user-id)
+ (rudel-obby-format-color color))))))
+
+ ;; Transmit list of disconnected users.
+ (let ((offline-users (remove-if #'rudel-connected users)))
+ (dolist (user offline-users)
+ (with-slots ((name :object-name) user-id color) user
+ (rudel-send this
+ "obby_sync_usertable_user"
+ (format "%x" user-id)
+ name
+ (rudel-obby-format-color color)))))
+
+ ;; Transmit document list
+ (dolist (document documents)
+ (with-slots ((name :object-name)
+ (doc-id :id)
+ owner-id
+ suffix
+ subscribed) document
+ (apply #'rudel-send
+ this
+ "obby_sync_doclist_document"
+ (format "%x" owner-id)
+ (format "%x" doc-id)
+ name
+ (format "%x" suffix)
+ "UTF-8"
+ (mapcar
+ (lambda (user1) ;; TODO we could use `user' here, but there is a bug in cl
+ (format "%x" (rudel-id user1)))
+ subscribed)))))
+
+ (rudel-send this "obby_sync_final")
+ 'idle))))
+ )
+
+
+;;; Class rudel-obby-server-state-idle
+;;
+
+(defclass rudel-obby-server-state-idle
+ (rudel-obby-server-connection-state)
+ ()
+ "Idle state of a server connection.
+
+The connection enters this state when all setup work is finished,
+the client has joined the session and no operation is in
+progress. In this state, the connection waits for new messages
+from the client that initiate operations. Simple (which means
+stateless in this case) operations are performed without leaving
+the idle state.")
+
+(defmethod rudel-obby/obby_user_colour
+ ((this rudel-obby-server-state-idle) color-)
+ "Handle obby 'user_colour' message.
+This method is called when the connected user requests a change
+of her color to COLOR."
+ (with-parsed-arguments ((color- color))
+ (with-slots (user) (oref this :connection)
+ (with-slots (color (user-id :user-id)) user
+ ;; Set color slot value.
+ (setq color color-)
+
+ ;; Run change hook.
+ (object-run-hook-with-args user 'change-hook)
+
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "obby_user_colour"
+ (format "%x" user-id)
+ (rudel-obby-format-color color)))))
+ nil)
+
+(defmethod rudel-obby/obby_document_create
+ ((this rudel-obby-server-state-idle)
+ doc-id name encoding content)
+ "Handle obby 'document_create' message."
+ (with-parsed-arguments ((doc-id number)
+ (encoding coding-system))
+ (with-slots (user server) (oref this :connection)
+ (with-slots ((user-id :user-id)) user
+ ;; Create a (hidden) buffer for the new document.
+ (let* ((buffer (get-buffer-create
+ (generate-new-buffer-name
+ (concat " *" name "*"))))
+ ;; Create the new document object
+ (document (rudel-obby-document
+ name
+ :buffer buffer
+ :subscribed (list user)
+ :id doc-id
+ :owner-id user-id
+ :suffix 1)))
+
+ ;; Initialize the buffer's content
+ (with-current-buffer buffer
+ (insert content))
+
+ (with-slots (suffix) document
+ ;; Determine an appropriate suffix to provide an unique
+ ;; name for the new document.
+ (while (rudel-find-document server
+ (if (= suffix 1)
+ name
+ (format "%s<%d>" name suffix))
+ #'string= #'rudel-unique-name)
+ (incf suffix))
+
+ ;; Add the document to the server's document list
+ (rudel-add-document server document)
+
+ ;; Maybe notify the creating client of the changed suffix.
+ (unless (= suffix 1)
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" user-id doc-id)
+ "rename"
+ (format "%x" user-id)
+ name
+ (format "%x" suffix)))
+
+ ;; Notify other clients of the new document
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "obby_document_create"
+ (format "%x" user-id)
+ (format "%x" doc-id)
+ name
+ (format "%x" suffix)
+ (upcase (symbol-name encoding))))
+
+ ;; Add a jupiter context for (THIS DOCUMENT).
+ (rudel-add-context server (oref this :connection) document))))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document
+ ((this rudel-obby-server-state-idle) doc-id action &rest arguments)
+ "Handle obby 'document' messages."
+ (with-parsed-arguments ((doc-id document-id))
+ ;; Locate the document based on owner id and document id
+ (let ((document (with-slots (server) (oref this :connection)
+ (rudel-find-document server doc-id
+ #'equal #'rudel-both-ids))))
+ (rudel-obby-dispatch this action
+ (append (list document) arguments)
+ "rudel-obby/obby_document/")))
+ )
+
+(defmethod rudel-obby/obby_document/subscribe
+ ((this rudel-obby-server-state-idle) document user-id)
+ "Handle 'subscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (let ((user (with-slots (server) (oref this :connection)
+ (rudel-find-user server user-id
+ #'= #'rudel-id))))
+ (with-slots (owner-id (doc-id :id) subscribed buffer) document
+
+ ;; Track subscription, handle duplicate subscription requests.
+ (when (memq user subscribed)
+ (error "User `%s' already subscribed to document `%s'"
+ (object-name user) (object-name document)))
+ (rudel-add-user document user)
+
+ ;; Synchronize the buffer content to the client.
+ (with-current-buffer buffer
+ ;; Send overall buffer size
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "sync_init"
+ (format "%x" (1- (position-bytes (point-max)))))
+
+ ;; Send buffer chunks with author ids
+ (dolist (chunk (rudel-chunks document))
+ (multiple-value-bind (from to author) chunk
+ (let ((string (buffer-substring (+ from 1) (+ to 1))))
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "sync_chunk"
+ string
+ (format "%x"
+ (if author
+ (oref author :user-id)
+ 0)))))))
+
+ ;; Notify clients of the new subscription (including our own
+ ;; client, who requested the subscription).
+ (with-slots ((user-id :user-id)) user
+ (rudel-broadcast this nil
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "subscribe"
+ (format "%x" user-id)))))
+
+ ;; Add a jupiter context for (THIS document).
+ (with-slots (server) (oref this :connection)
+ (rudel-add-context server (oref this :connection) document))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/unsubscribe
+ ((this rudel-obby-server-state-idle) document user-id)
+ "Handle 'unsubscribe' submessage of 'obby_document' message."
+ (with-parsed-arguments ((user-id number))
+ (let ((user (with-slots (server) (oref this :connection)
+ (rudel-find-user server user-id
+ #'= #'rudel-id))))
+ (with-slots (owner-id (doc-id :id) subscribed) document
+
+ ;; Track subscription, handle invalid unsubscribe requests
+ (unless (memq user subscribed)
+ (error "User `%s' not subscribed to document `%s'"
+ (object-name user) (object-name document)))
+ (rudel-remove-user document user)
+
+ ;; Notify clients of the canceled subscription (including our
+ ;; own client, who requested being unsubscribed).
+ (with-slots ((user-id :user-id)) user
+ (rudel-broadcast this nil
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "unsubscribe"
+ (format "%x" user-id))))
+
+ ;; Remove jupiter context for (THIS DOCUMENT).
+ (with-slots (server) (oref this :connection)
+ (rudel-remove-context server (oref this :connection) document)))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/record
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision action &rest arguments)
+ "Handle 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((local-revision number)
+ (remote-revision number))
+ ;; Dispatch to specialized operation handlers.
+ (rudel-obby-dispatch
+ this action
+ (append (list document local-revision remote-revision)
+ arguments)
+ "rudel-obby/obby_document/record/"))
+ )
+
+(defmethod rudel-obby/obby_document/record/ins
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision position data)
+ "Handle 'ins' submessage of 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((position number))
+ ;; Construct the operation object and process it.
+ (rudel-remote-operation
+ (oref this :connection) document
+ remote-revision local-revision
+ (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :data data))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/record/del
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision position length)
+ "Handle 'del' submessage of 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((position number)
+ (length number))
+ ;; Construct the operation object and process it.
+ (rudel-remote-operation
+ (oref this :connection) document
+ remote-revision local-revision
+ (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :to (+ position length)))
+ nil)
+ )
+
+
+;;; Client connection states.
+;;
+
+(defvar rudel-obby-server-connection-states
+ '((new . rudel-obby-server-state-new)
+ (encryption-negotiate . rudel-obby-server-state-encryption-negotiate)
+ (before-join . rudel-obby-server-state-before-join)
+ (idle . rudel-obby-server-state-idle))
+ "Name symbols and classes of connection states.")
+
+
+;;; Class rudel-obby-client
+;;
+
+(defclass rudel-obby-client (rudel-obby-socket-owner
+ rudel-state-machine)
+ ((server :initarg :server
+ :type rudel-obby-server
+ :documentation
+ "")
+ (id :initarg :id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "")
+ (user :initarg :user
+ :type (or rudel-obby-user null)
+ :initform nil
+ :documentation
+ "")
+ (encryption :initarg :encryption
+ :type boolean
+ :documentation
+ ""))
+ "Each object of this class represents one client, that is
+connected to the server. This object handles all direct
+communication with the client, while broadcast messages are
+handled by the server.")
+
+(defmethod initialize-instance ((this rudel-obby-client) &rest slots)
+ "Initialize slots of THIS and register state machine states."
+ ;; Initialize slots of THIS
+ (when (next-method-p)
+ (call-next-method))
+
+ ;; Register states.
+ (rudel-register-states this rudel-obby-server-connection-states)
+ )
+
+(defmethod rudel-register-state ((this rudel-obby-client) symbol state)
+ "Register SYMBOL and STATE and set connection slot of STATE."
+ ;; Associate THIS connection to STATE.
+ (oset state :connection this)
+
+ ;; Register STATE.
+ (call-next-method))
+
+(defmethod rudel-end ((this rudel-obby-client))
+ ""
+ (rudel-disconnect this))
+
+(defmethod rudel-close ((this rudel-obby-client))
+ ""
+ (with-slots (server) this
+ (rudel-remove-client server this)))
+
+(defmethod rudel-message ((this rudel-obby-client) message)
+ "Dispatch MESSAGE to the active state of THIS state machine."
+ ;; Dispatch message to state
+ (rudel-accept this message))
+
+(defmethod rudel-broadcast ((this rudel-obby-client)
+ receivers name &rest arguments)
+ "Broadcast message NAME with arguments ARGUMENTS to RECEIVERS."
+ (with-slots (server) this
+ (apply #'rudel-broadcast server receivers name arguments)))
+
+(defmethod rudel-remote-operation ((this rudel-obby-client)
+ document
+ local-revision remote-revision
+ operation)
+ "Execute and relay OPERATION on DOCUMENT."
+ (with-slots (server user) this
+ ;; Transform OPERATION and find clients that need to receive
+ ;; notifications.
+ (let* ((context (rudel-find-context server this document))
+ (transformed (jupiter-remote-operation
+ context
+ local-revision remote-revision
+ operation))
+ (receivers (rudel-subscribed-clients-not-self
+ this document)))
+
+ ;; Relay change notification to other clients. We use
+ ;; TRANSFORMED before the byte -> char conversion which is what
+ ;; the receivers expect.
+ (with-slots (user-id) user
+ (with-slots (owner-id (doc-id :id)) document
+ ;; Construct and send messages to all receivers individually
+ ;; since the contents of the messages depends on the state
+ ;; of the jupiter context associated the respective
+ ;; receiver.
+ (dolist (receiver receivers)
+
+ ;; Find the jupiter context for RECEIVER and use its
+ ;; revision information.
+ (let ((context (rudel-find-context server receiver document)))
+ ;; Construct and send one message.
+ (with-slots (local-revision remote-revision) context
+ (apply #'rudel-send
+ receiver
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "record"
+ (format "%x" user-id)
+ (format "%x" local-revision)
+ (format "%x" remote-revision)
+ (rudel-operation->message transformed)))
+
+ ;; Submit the operation to the jupiter context.
+ (jupiter-local-operation context transformed)))))
+
+ ;; Incorporate change into DOCUMENT (the server-side
+ ;; document). We have to convert bytes -> chars before we can do
+ ;; this.
+ (with-slots (buffer) document
+ (rudel-obby-byte->char transformed buffer))
+
+ (rudel-remote-operation document user transformed)))
+ )
+
+(defmethod rudel-subscribed-clients-not-self ((this rudel-obby-client)
+ document)
+ "Return a list of clients subscribed to DOCUMENT excluding THIS."
+ (with-slots (clients) (oref this :server)
+ (with-slots (subscribed) document
+ (remove-if
+ (lambda (client)
+ (with-slots (user) client
+ (or (eq client this)
+ (not (memq user subscribed)))))
+ clients)))
+ )
+
+
+;;; Class rudel-obby-server
+;;
+
+(defclass rudel-obby-server (rudel-server-session
+ rudel-socket-owner)
+ ((clients :initarg :clients
+ :type list
+ :initform nil
+ :documentation
+ "")
+ (next-client-id :initarg :next-client-id
+ :type integer
+ :initform 1
+ :documentation
+ "")
+ (next-user-id :initarg :next-user-id
+ :type integer
+ :initform 1
+ :documentation
+ "")
+ (contexts :initarg :contexts
+ :type hash-table
+ :documentation
+ ""))
+ "Class rudel-obby-server ")
+
+(defmethod initialize-instance ((this rudel-obby-server) &rest slots)
+ ""
+ (when (next-method-p)
+ (call-next-method))
+
+ (with-slots (contexts) this
+ (setq contexts (make-hash-table :test 'equal))))
+
+(defmethod rudel-end ((this rudel-obby-server))
+ ""
+ (rudel-disconnect this))
+
+(defmethod rudel-broadcast ((this rudel-obby-server)
+ receivers name &rest arguments)
+ "Send a message of type NAME with arguments ARGUMENTS to RECEIVERS.
+
+RECEIVERS can be a object derived from rudel-obby-client, a list
+of such objects or a list with car 'exclude and cdr a list of
+such objects derived from rudel-obby-client."
+ ;; Construct list of receivers.
+ (let ((receiver-list
+ (cond
+ ;; If RECEIVERS is nil, the message should be broadcast to
+ ;; all clients.
+ ((null receivers) (oref this :clients))
+ ;; If RECEIVERS is a (non-empty) list of rudel-obby-client
+ ;; (or derived) objects, treat it as a list of receivers.
+ ((and (listp receivers)
+ (rudel-obby-client-child-p (car receivers)))
+ receivers)
+ ;; If RECEIVERS is a (non-empty) list with cdr equal to
+ ;; 'exclude treat it as a list of receivers to exclude.
+ ((and (listp receivers)
+ (eq (car receivers) 'exclude))
+ (with-slots (clients) this
+ (set-difference clients (cdr receivers)
+ :key #'rudel-id)))
+ ;; If RECEIVERS is a single rudel-obby-client (or derived)
+ ;; object, send the message to that client.
+ ((rudel-obby-client-child-p receivers)
+ (list receivers))
+ ;;
+ (t (signal 'wrong-type-argument (type-of receivers))))))
+
+ ;; Send message to receivers.
+ (dolist (receiver receiver-list)
+ (apply #'rudel-send receiver name arguments)))
+ )
+
+(defmethod rudel-make-user ((this rudel-obby-server)
+ name client-id color encryption)
+ ""
+ (with-slots (next-user-id) this
+ (let ((user (rudel-obby-user name
+ :color color
+ :client-id client-id
+ :user-id next-user-id
+ :connected t
+ :encryption encryption)))
+ (incf next-user-id)
+ user))
+ )
+
+(defmethod rudel-check-username-and-color ((this rudel-obby-server)
+ username color)
+ "Check whether USERNAME and COLOR are valid.
+USERNAME must not be empty and must not be used by another
+user. COLOR has to be sufficiently different from used colors."
+ (cond
+ ;; The empty user name is not allowed
+ ((string= username "")
+ rudel-obby-error-username-invalid)
+
+ ;; Make sure the user name is not already in use.
+ ((rudel-find-user this username
+ #'string= #'object-name-string)
+ rudel-obby-error-username-in-use)
+
+ ;; Make sure the color is sufficiently dissimilar to all used
+ ;; colors.
+ ((rudel-find-user this color
+ (lambda (left right)
+ (< (color-distance left right) 20000)) ;; TODO constant
+ #'rudel-color)
+ rudel-obby-error-color-in-use))
+ )
+
+(defmethod rudel-add-client ((this rudel-obby-server)
+ client-socket)
+ ""
+ (with-slots (next-client-id clients) this
+ (let ((client (rudel-obby-client (process-name client-socket)
+ :server this
+ :socket client-socket
+ :id next-client-id
+ :encryption nil)))
+ (push client clients))
+ (incf next-client-id))
+ )
+
+(defmethod rudel-remove-client ((this rudel-obby-server)
+ client)
+ ""
+ (with-slots ((client-id :id) user) client
+ ;; Broadcast the part event to all remaining clients.
+ (rudel-broadcast this (list 'exclude client)
+ "net6_client_part"
+ (format "%x" client-id))
+
+ ;; If the client has an associated user object, set the status of
+ ;; the user object to offline.
+ (when user
+ ;; Set slot value.
+ (with-slots (connected) user
+ (setq connected nil))
+
+ ;; Run change hook.
+ (object-run-hook-with-args user 'change-hook)))
+
+ (object-remove-from-list this :clients client)
+ )
+
+(defmethod rudel-find-context ((this rudel-obby-server) client document)
+ "Return the jupiter context associated to (CLIENT DOCUMENT) in THIS."
+ (with-slots (contexts) this
+ (gethash (rudel-obby-context-key client document) contexts)))
+
+(defmethod rudel-add-context ((this rudel-obby-server) client document)
+ "Add a jupiter context for (CLIENT DOCUMENT) to THIS."
+ (with-slots (contexts) this
+ (with-slots ((client-id :id)) client
+ (with-slots ((doc-name :object-name)) document
+ (puthash
+ (rudel-obby-context-key client document)
+ (jupiter-context (format "%d-%s" client-id doc-name))
+ contexts))))
+ )
+
+(defmethod rudel-remove-context ((this rudel-obby-server) client document)
+ "Remove the jupiter context associated to (CLIENT DOCUMENT) from THIS."
+ (with-slots (contexts) this
+ (remhash
+ (rudel-obby-context-key client document)
+ contexts)))
+
+(defun rudel-obby-context-key (client document)
+ "Generate hash key based on CLIENT and DOCUMENT."
+ (with-slots ((client-id :id)) client
+ (with-slots ((doc-id :id)) document
+ (list client-id doc-id))))
+
+(defmethod object-print ((this rudel-obby-server) &rest strings)
+ "Print THIS with number of clients."
+ (with-slots (clients) this
+ (apply #'call-next-method
+ this
+ (format " clients: %d"
+ (length clients))
+ strings))
+ )
+
+(provide 'rudel-obby-server)
+;;; rudel-obby-server.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-state.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-state.el.svn-base
new file mode 100644
index 0000000..a190967
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-state.el.svn-base
@@ -0,0 +1,169 @@
+;;; rudel-obby-state.el --- Base class for states used in the obby backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, state machine
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a base class for finite state machine states
+;; used in the obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-util)
+(require 'rudel-state-machine)
+
+(require 'rudel-obby-util)
+
+
+;;; Class rudel-obby-state
+;;
+
+(defclass rudel-obby-state (rudel-state)
+ ((connection :initarg :connection
+ :type rudel-obby-socket-owner
+ :documentation
+ "Connection object that uses the state."))
+ "Base class for state classes used in the obby backend."
+ :abstract t)
+
+(defmethod rudel-enter ((this rudel-obby-state))
+ "Default behavior is doing nothing when entering a state."
+ nil)
+
+(defmethod rudel-leave ((this rudel-obby-state))
+ "Default behavior is doing nothing when leaving a state.")
+
+(defmethod rudel-accept ((this rudel-obby-state) message)
+ "Dispatch to appropriate handler based on MESSAGE.
+Display a warning if no such handler is found."
+ ;; Try to dispatch to the correct message handler. If there is none,
+ ;; warn.
+ (let ((name (car message))
+ (arguments (cdr message)))
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch this "rudel-obby/" name arguments)
+ ;; Warn if we failed to locate or execute the method. Return nil
+ ;; in this case, so we remain in the current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s/%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby" name arguments)
+ :debug)
+ nil))))
+ )
+
+(defmethod rudel-send ((this rudel-obby-state) &rest args)
+ "Send ARGS through the connection associated with THIS."
+ (with-slots (connection) this
+ (apply #'rudel-send connection args)))
+
+
+;;; Class rudel-obby-client-connection-state
+;;
+
+(defclass rudel-obby-client-connection-state (rudel-obby-state)
+ ()
+ "Base class for state classes used by obby client connections."
+ :abstract t)
+
+(defmethod rudel-obby/net6_ping ((this rudel-obby-client-connection-state))
+ "Handle net6 'ping' message."
+ (rudel-send this "net6_pong")
+ nil)
+
+
+;;; Class rudel-obby-server-connection-state
+;;
+
+(defclass rudel-obby-server-connection-state (rudel-obby-state)
+ ()
+ "Base class for server connection states."
+ :abstract t)
+
+(defmethod rudel-broadcast ((this rudel-obby-server-connection-state)
+ receivers name &rest arguments)
+ "Broadcast message NAME with arguments ARGUMENTS to RECEIVERS."
+ (with-slots (connection) this
+ (apply #'rudel-broadcast connection receivers name arguments)))
+
+
+;;; Class rudel-obby-document-handler
+;;
+
+(defclass rudel-obby-document-handler ()
+ ()
+ "Mixin class that provides ability to process submessages of
+ obby 'document' messages.")
+
+(defmethod rudel-obby/obby_document
+ ((this rudel-obby-document-handler) doc-id action &rest arguments)
+ "Handle obby 'document' message family."
+ ;; Try to dispatch to the correct message handler. If there is none,
+ ;; warn.
+ (with-parsed-arguments ((doc-id document-id))
+ ;; Locate the document based on owner id and document id.
+ (let ((document (with-slots (connection) this
+ (with-slots (session) connection
+ (rudel-find-document session doc-id
+ #'equal #'rudel-both-ids)))))
+ (if document
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch this "rudel-obby/obby_document/" action
+ (cons document arguments))
+ ;; Warn if we failed to locate or execute the
+ ;; method. Return nil in this case, so we remain in the
+ ;; current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s:%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby/obby_document/" action arguments)
+ :debug)
+ nil)))
+ ;; If we did not find the document, warn.
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "Document not found: %s" doc-id)
+ :debug)
+ nil))))
+ )
+
+(provide 'rudel-obby-state)
+;;; rudel-obby-state.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-util.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-util.el.svn-base
new file mode 100644
index 0000000..faefe70
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby-util.el.svn-base
@@ -0,0 +1,314 @@
+;;; rudel-obby-util.el --- Miscellaneous functions for the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, miscellaneous
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;;
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel)
+(require 'rudel-util)
+
+(require 'jupiter)
+
+
+;;; Class rudel-obby-socket-owner
+;;
+
+(defclass rudel-obby-socket-owner (rudel-socket-owner)
+ ((buffer :initarg :buffer
+ :type (or null string)
+ :initform nil
+ :documentation
+ "Stores message fragments until complete messages can
+be assembled."))
+ "This class adds functions for sending and receiving obby
+messages to the base class rudel-socket-owner.")
+
+(defmethod rudel-send ((this rudel-obby-socket-owner)
+ name &rest arguments)
+ "Send obby message NAME with arguments ARGUMENTS through the socket associated to THIS."
+ (with-slots (socket) this
+ (rudel-obby-send socket name arguments)))
+
+(defmethod rudel-receive ((this rudel-obby-socket-owner) data)
+ "Reassemble lines in DATA received on the socket associated with THIS and call message handler."
+ ;; Assemble fragmented lines.
+ (with-slots (buffer) this
+ (rudel-assemble-line-fragments data buffer))
+
+ ;; Process all available lines.
+ (rudel-loop-lines data line
+ ;; `rudel-message' has to dispatch message to an appropriate
+ ;; handler.
+ (let ((message (rudel-obby-parse-message line)))
+ (rudel-message this message)))
+ )
+
+(defgeneric rudel-message ((this rudel-obby-socket-owner) message)
+ "Called when a message arrives.
+Should be implemented in derived classes.")
+
+
+;;; Message serialization
+;;
+
+(defgeneric rudel-operation->message ((this jupiter-operation))
+ "Generate a list obby message components from THIS operation.")
+
+(defmethod rudel-operation->message ((this jupiter-insert))
+ "Serialize THIS insert operation."
+ (with-slots (from data) this
+ (list "ins" (format "%x" from) data)))
+
+(defmethod rudel-operation->message ((this jupiter-delete))
+ "Serialize THIS delete operation."
+ (with-slots (from length) this
+ (list "del" (format "%x" from) (format "%x" length))))
+
+(defmethod rudel-operation->message ((this jupiter-compound))
+ "Serialize THIS compound operation."
+ (with-slots (children) this
+ (apply #'append
+ (list "split" )
+ (mapcar #'rudel-operation->message children))))
+
+(defmethod rudel-operation->message ((this jupiter-nop))
+ "Serialize THIS nop operation."
+ (list "nop"))
+
+(defun rudel-message->operation (message local-revision remote-revision)
+ "Construct an operation object from MESSAGE and LOCAL-REVISION and REMOTE-REVISION.
+LOCAL-REVISION and REMOTE-REVISION are only used in the
+construction of the name of the new operation. "
+ (let ((type (car message)))
+ (cond
+
+ ;; Insert operation
+ ((string= type "ins")
+ (let ((position-numeric (string-to-number (nth 1 message) 16))
+ (data (nth 2 message)))
+ (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position-numeric
+ :data data)))
+
+ ;; Delete operation
+ ((string= type "del")
+ (let ((position-numeric (string-to-number (nth 1 message) 16))
+ (length-numeric (string-to-number (nth 2 message) 16)))
+ (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position-numeric
+ :to (+ position-numeric length-numeric))))
+
+ ;; Compound operation
+ ((string= type "split")
+ (let* ((rest (cdr message))
+ (offset (position-if
+ (lambda (item)
+ (member* item '("ins" "del" "nop")
+ :test #'string=))
+ rest
+ :start 1))
+ (first (subseq rest 0 offset))
+ (second (subseq rest offset)))
+ (jupiter-compound
+ (format "compound-%d-%d"
+ remote-revision local-revision)
+ :children
+ (list (rudel-message->operation
+ first local-revision remote-revision)
+ (rudel-message->operation
+ second local-revision remote-revision)))))
+
+ ;; No operation
+ ((string= type "nop")
+ (jupiter-nop
+ (format "nop-%d-%d"
+ remote-revision local-revision)))
+
+ ;; Unknown operation type
+ (t (error "Unknown document record type: `%s'" type))))
+ )
+
+
+;;; Character <-> byte position conversion
+;;
+
+(defgeneric rudel-obby-char->byte ((this jupiter-operation) buffer)
+ "Convert character positions and lengths in THIS to bytes.")
+
+(defmethod rudel-obby-char->byte ((this jupiter-insert) buffer)
+ "Convert character positions and lengths in THIS insert to bytes."
+ (with-slots (from) this
+ (with-current-buffer buffer
+ (setq from (- (position-bytes (+ from 1)) 1)))))
+
+(defmethod rudel-obby-char->byte ((this jupiter-delete) buffer)
+ "Convert character positions and lengths in THIS delete to bytes."
+ (with-slots (from to length) this
+ (let ((old-from (+ from 1))
+ (old-to (+ to 1)))
+ (with-current-buffer buffer
+ (destructuring-bind (change-from change-to string)
+ rudel-buffer-change-workaround-data
+ (setq from (- (position-bytes old-from) 1)
+ length (string-bytes
+ (substring string
+ (- old-from change-from)
+ (- old-to change-from))))))))
+ )
+
+(defmethod rudel-obby-char->byte ((this jupiter-compound) buffer)
+ "Convert character positions and lengths in THIS compound to bytes.."
+ (with-slots (children) this
+ (mapc
+ (lambda (child)
+ (rudel-obby-char->byte child buffer))
+ children))
+ )
+
+(defmethod rudel-obby-char->byte ((this jupiter-nop) buffer)
+ "Nothing to convert if THIS is a nop.")
+
+(defgeneric rudel-obby-byte->char ((this jupiter-operation) buffer)
+ "Convert byte positions and lengths in THIS to character positions.")
+
+(defmethod rudel-obby-byte->char ((this jupiter-insert) buffer)
+ "Convert byte positions and lengths in THIS insert to character positions."
+ (with-slots (from) this
+ (with-current-buffer buffer
+ (setq from (- (byte-to-position (+ from 1)) 1)))))
+
+(defmethod rudel-obby-byte->char ((this jupiter-delete) buffer)
+ "Convert byte positions and lengths in THIS delete to character positions."
+ (with-slots (from to length) this
+ (let ((old-from from)
+ (old-length length))
+ (with-current-buffer buffer
+ (setq from (- (byte-to-position (+ old-from 1)) 1)
+ to (- (byte-to-position (+ old-from old-length 1)) 1)))))
+ )
+
+(defmethod rudel-obby-byte->char ((this jupiter-compound) buffer)
+ "Convert byte positions and lengths in THIS compound to character positions."
+ (with-slots (children) this
+ (mapc
+ (lambda (child)
+ (rudel-obby-byte->char child buffer))
+ children))
+ )
+
+(defmethod rudel-obby-byte->char ((this jupiter-nop) buffer)
+ "Nothing to convert if THIS is a nop.")
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-obby-dispatch (object name arguments &optional prefix)
+ "Call method starting with PREFIX and ending in NAME of OBJECT with ARGUMENTS.
+When PREFIX is not specified, \"rudel-obby/\" is used."
+ ;; Default prefix.
+ (unless prefix
+ (setq prefix "rudel-obby/"))
+
+ ;; Construct a matching symbol.
+ (let ((method (intern-soft (concat prefix name))))
+ ;; If we found a suitable method, run it; Otherwise warn and do
+ ;; nothing.
+ (unless (and method
+ (condition-case error
+ ;; Try to call METHOD. If successful, always
+ ;; return t.
+ (progn
+ (apply method object arguments)
+ t)
+ ;; Warn only when the condition is
+ ;; 'no-method-definition' and refers to METHOD,
+ ;; otherwise continue unwinding.
+ (no-method-definition
+ (if (eq method (cadr error))
+ nil
+ (signal (car error) (cdr error))))))
+ (display-warning
+ '(rudel obby)
+ (format "%s: in context `%s': no method: `%s'; arguments: %s"
+ (object-name-string object) prefix name arguments)
+ :debug)))
+ )
+
+(defmacro with-parsed-arguments (specs &rest forms)
+ "Execute FORMS with variable bindings according to SPECS.
+SPECS is structured as follows:
+SPECS ::= (BINDING*)
+BINDING ::= (VAR TYPE)
+VAR is a symbol and TYPE is one of number, color, document-id and
+coding-system."
+ (declare (indent 1)
+ (debug (listp &rest form)))
+ (let ((bindings
+ (mapcar
+ (lambda (spec)
+ (destructuring-bind (var type) spec
+ (list var
+ (case type
+ ;; Number
+ (number
+ `(string-to-number ,var 16))
+ ;; Color
+ (color
+ `(rudel-obby-parse-color ,var))
+ ;; Document Id
+ (document-id
+ `(mapcar
+ (lambda (string)
+ (string-to-number string 16))
+ (split-string ,var " " t)))
+ ;; Coding System
+ (coding-system
+ `(rudel-get-coding-system (downcase ,var)))))))
+ specs)))
+ `(let (,@bindings)
+ ,@forms))
+ )
+
+(provide 'rudel-obby-util)
+;;; rudel-obby-util.el ends here
diff --git a/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby.el.svn-base b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby.el.svn-base
new file mode 100644
index 0000000..a09c0d3
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/.svn/text-base/rudel-obby.el.svn-base
@@ -0,0 +1,488 @@
+;;; rudel-obby.el --- An obby backend for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, implementation
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel protocol backend, which implements the
+;; obby protocol (used by the Gobby collaborative editor until version
+;; 0.5).
+
+
+;;; History:
+;;
+;; 0.2 - Refactored client and server to employ state machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel)
+(require 'rudel-backend)
+(require 'rudel-protocol)
+(require 'rudel-util)
+(require 'rudel-icons)
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Constants
+;;
+
+(defconst rudel-obby-version '(0 2)
+ "Version of the obby backend for Rudel.")
+
+(defconst rudel-obby-protocol-version 8
+ "Version of the obby protocol this library understands.")
+
+(defvar rudel-obby-long-message-threshold 32768
+ "Threshold for message size, above which messages are sent in
+multiple chunks.")
+
+(defvar rudel-obby-long-message-chunk-size 16384
+ "Chunk size used, when chunking long messages.")
+
+
+;;; Class rudel-obby-backend
+;;
+
+;;;###autoload
+(defclass rudel-obby-backend (rudel-protocol-backend)
+ ((capabilities :initform '(join host
+ change-color
+ track-subscriptions)))
+ "Main class of the Rudel obby backend. Creates obby client
+connections and creates obby servers.")
+
+(defmethod initialize-instance ((this rudel-obby-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-obby-version))
+
+(defmethod rudel-ask-connect-info ((this rudel-obby-backend) &optional info)
+ "Ask user for the information required to connect to an obby server."
+ ;; Read server host and port.
+ (let ((host (or (and info (plist-get info :host))
+ (read-string "Server: ")))
+ (port (or (and info (plist-get info :port))
+ (read-number "Port: " 6522)))
+ ;; Read desired username and color
+ (username (or (and info (plist-get info :username))
+ (read-string "Username: " user-login-name)))
+ (color (or (and info (plist-get info :color))
+ (read-color "Color: " t)))
+ (encryption (if (and info (member :encryption info))
+ (plist-get info :encryption)
+ (y-or-n-p "Use encryption? ")))
+ (global-password (if (and info (member :global-password info))
+ (plist-get info :global-password)
+ (read-string "Global password: " "")))
+ (user-password (if (and info (member :user-password info))
+ (plist-get info :user-password)
+ (read-string "User password: " ""))))
+ (append (list :host host
+ :port port
+ :username username
+ :color color
+ :encryption encryption
+ :global-password (unless (string= global-password "")
+ global-password)
+ :user-password (unless (string= user-password "")
+ user-password))
+ info))
+ )
+
+(defmethod rudel-connect ((this rudel-obby-backend) info)
+ "Connect to an obby server using the information INFO.
+Return the connection object."
+ ;; Before we start, load the client functionality.
+ (require 'rudel-obby-client)
+
+ ;; Create the network process
+ (let* ((session (plist-get info :session))
+ (host (plist-get info :host))
+ (port (plist-get info :port))
+ (encryption (plist-get info :encryption))
+ ;; Create the network process
+ (socket (funcall
+ (if encryption
+ (progn
+ (require 'rudel-tls)
+ #'rudel-tls-make-process)
+ #'make-network-process)
+ :name host
+ :host host
+ :service port
+ ;; Install connection filter to redirect data to
+ ;; the connection object
+ :filter #'rudel-filter-dispatch
+ ;; Install connection sentinel to redirect state
+ ;; changes to the connection object
+ :sentinel #'rudel-sentinel-dispatch
+ ;; Do not start receiving immediately since the
+ ;; filter function is not yet setup properly.
+ :stop t))
+ (connection (rudel-obby-connection
+ host
+ :session session
+ :socket socket
+ :info info)))
+
+ ;; Now start receiving and wait until the basic session setup is
+ ;; complete.
+ (continue-process socket)
+
+ ;; Wait for the connection to reach one of the states idle,
+ ;; join-failed and they-finalized.
+ (condition-case error
+ (lexical-let ((reporter (make-progress-reporter "Joining ")))
+ (flet ((display-progress (state)
+ (cond
+ ;; For all states, just spin.
+ ((consp state)
+ (progress-reporter-force-update
+ reporter nil (format "Joining (%s)" (car state))))
+
+ ;; Done
+ (t
+ (progress-reporter-force-update reporter nil "Joining ")
+ (progress-reporter-done reporter)))))
+
+ (rudel-state-wait connection
+ '(idle) '(join-failed they-finalized)
+ #'display-progress)))
+
+ (rudel-entered-error-state
+ (destructuring-bind (symbol . state) (cdr error)
+ (if (eq (rudel-find-state connection 'join-failed) state)
+ (with-slots (error-symbol error-data) state
+ (signal 'rudel-join-error
+ (append (list error-symbol) error-data)))
+ (signal 'rudel-join-error nil)))))
+
+ ;; The connection is now usable; return it.
+ connection)
+ )
+
+(defmethod rudel-ask-host-info ((this rudel-obby-backend))
+ "Ask user for information required to host an obby session."
+ (let ((port (read-number "Port: " 6522)))
+ (list :port port)))
+
+(defmethod rudel-host ((this rudel-obby-backend) info)
+ "Host an obby session using the information INFO.
+Return the created server."
+ ;; Before we start, we load the server functionality.
+ (require 'rudel-obby-server)
+
+ ;; Create the network process.
+ (let* ((port (plist-get info :port))
+ ;; Make a server socket
+ (socket (make-network-process
+ :name "obby-server"
+ :host "0.0.0.0"
+ :service port
+ :server t
+ :filter #'rudel-filter-dispatch
+ :sentinel #'rudel-sentinel-dispatch
+ ;;
+ :log
+ (lambda (server-process client-process message)
+ (let ((server (rudel-process-object server-process)))
+ (rudel-add-client server client-process)))))
+ ;; Construct server object.
+ (server (rudel-obby-server "obby-server"
+ :backend this
+ :socket socket)))
+
+ ;; Return the constructed server.
+ server)
+ )
+
+(defmethod rudel-make-document ((this rudel-obby-backend)
+ name session)
+ "Make a new document in SESSION named NAME.
+Return the new document."
+ ;; Find an unused document id and create a document with that id.
+ (let ((id (rudel-available-document-id this session)))
+ (with-slots (user-id) (oref session :self)
+ (rudel-obby-document name
+ :session session
+ :id id
+ :owner-id user-id
+ :suffix 1)))
+ )
+
+(defmethod rudel-available-document-id ((this rudel-obby-backend)
+ session)
+ "Return a document id, which is not in use in SESSION."
+ ;; Look through some candidates until an unused id is hit.
+ (let* ((used-ids (with-slots (documents) session
+ (mapcar 'rudel-id documents)))
+ (test-ids (number-sequence 0 (length used-ids))))
+ (car (sort (set-difference test-ids used-ids) '<)))
+ )
+
+
+;;; Class rudel-obby-user
+;;
+
+(defclass rudel-obby-user (rudel-user)
+ ((client-id :initarg :client-id
+ :type (or null integer) ;; We allow nil instead of making
+ :accessor rudel-client-id ;; the slot unbound, to be able to
+ :initform nil ;; search with test `rudel-client-id
+ :documentation ;; without headaches
+ "Id of the client connection, which the user used to log in.
+The value is an integer, if the user is connected, and nil
+otherwise.")
+ (user-id :initarg :user-id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "")
+ (connected :initarg :connected
+ :type boolean
+ :accessor rudel-connected
+ :documentation
+ "")
+ (encryption :initarg :encryption ;; TODO maybe we should use unbound when the user is not connected
+ :type boolean
+ :documentation
+ ""))
+ "Class rudel-obby-user ")
+
+(defmethod eieio-speedbar-description ((this rudel-obby-user))
+ "Provide a speedbar description for THIS."
+ (let ((connected (oref this :connected))
+ (encryption (if (slot-boundp this :encryption)
+ (oref this :encryption)
+ nil)))
+ (format "User %s (%s, %s)" (object-name-string this)
+ (if connected "Online" "Offline")
+ (if encryption "Encryption" "Plain")))
+ )
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-obby-user))
+ "Return a string to use as a speedbar button for THIS."
+ (rudel-display-string this))
+
+(defmethod rudel-display-string ((this rudel-obby-user)
+ &optional use-images align)
+ "Return a textual representation of THIS for user interface stuff."
+ (with-slots (connected color) this
+ (let ((encryption (and (slot-boundp this :encryption)
+ (oref this :encryption)))
+ (name-string (call-next-method)))
+ (concat
+ ;; Name bit
+ (cond
+ ((numberp align) (format (format "%-%ds" align) name-string))
+ ((eq align t) (format "%-12s" name-string))
+ (t name-string))
+
+ ;; Connection status bit
+ (apply
+ #'propertize
+ (if connected "c" "-")
+ 'help-echo (format (if connected
+ "%s is connected"
+ "%s is not connected")
+ name-string)
+ 'face (list :background color)
+ (when use-images
+ (list 'display (if connected
+ rudel-icon-connected
+ rudel-icon-disconnected))))
+
+ ;; Encryption bit
+ (apply
+ #'propertize
+ (if encryption "e" "-")
+ 'help-echo (format (if encryption
+ "%s's connection is encrypted"
+ "%s's connection is not encrypted")
+ name-string)
+ 'face (list :background color)
+ (when use-images
+ (list 'display (if encryption
+ rudel-icon-encrypted
+ rudel-icon-plaintext)))))))
+ )
+
+
+;;; Class rudel-obby-document
+;;
+
+(defclass rudel-obby-document (rudel-document)
+ ((id :initarg :id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "The id of this document.
+The id has to be unique only with respect to the other documents
+owned by the owner.")
+ (owner-id :initarg :owner-id
+ :type integer
+ :documentation
+ "")
+ (suffix :initarg :suffix
+ :type integer
+ :documentation
+ "A counter used to distinguish identically named
+documents."))
+ "Objects of the class rudel-obby-document represent shared
+documents in obby sessions.")
+
+(defmethod rudel-both-ids ((this rudel-obby-document))
+ "Return a list consisting of document and owner id of THIS document."
+ (with-slots ((doc-id :id) owner-id) this
+ (list owner-id doc-id)))
+
+(defmethod rudel-unique-name ((this rudel-obby-document))
+ "Generate a unique name for THIS based on the name and the suffix."
+ (with-slots (suffix) this
+ (concat (when (next-method-p)
+ (call-next-method))
+ (when (> suffix 1)
+ (format "<%d>" suffix))))
+ )
+
+(defmethod eieio-speedbar-description ((this rudel-obby-document))
+ "Construct a description for from the name of document object THIS."
+ (format "Document %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-obby-document))
+ "Return a string to use as a speedbar button for OBJECT."
+ (with-slots (subscribed) this
+ (format "%-12s %s" (object-name-string this)
+ (if subscribed "s" "-")))
+ )
+
+
+;;; Obby message functions
+;;
+
+(defun rudel-obby-replace-in-string (string replacements)
+ "Replace elements of REPLACEMENTS in STRING.
+REPLACEMENTS is a list of conses whose car is the pattern and
+whose cdr is the replacement for the pattern."
+ (let ((result string))
+ (dolist (replacement replacements)
+ (let ((from (car replacement))
+ (to (cdr replacement)))
+ (setq result (replace-regexp-in-string
+ from to result nil t))))
+ result)
+ )
+
+(defun rudel-obby-escape-string (string)
+ "Replace meta characters in STRING with their escape sequences."
+ (rudel-obby-replace-in-string
+ string
+ '(("\\\\" . "\\b") ("\n" . "\\n") (":" . "\\d")))
+ )
+
+(defun rudel-obby-unescape-string (string)
+ "Replace escaped versions of obby meta characters in STRING with the actual meta characters."
+ (rudel-obby-replace-in-string
+ string
+ '(("\\\\n" . "\n") ("\\\\d" . ":") ("\\\\b" . "\\")))
+ )
+
+(defun rudel-obby-parse-color (color)
+ "Parse the obby color string COLOR into an Emacs color."
+ (let* ((color-numeric (string-to-number color 16))
+ (color-string (format "#%04X%04X%04X"
+ (lsh (logand #xff0000 color-numeric) -08)
+ (lsh (logand #x00ff00 color-numeric) -00)
+ (lsh (logand #x0000ff color-numeric) 08))))
+ color-string)
+ )
+
+(defun rudel-obby-format-color (color)
+ "Format the Emacs color COLOR as obby color string."
+ (multiple-value-bind (red green blue) (color-values color)
+ (format "%02x%02x%02x" (lsh red -8) (lsh green -8) (lsh blue -8))))
+
+(defun rudel-obby-assemble-message (name &rest arguments)
+ ""
+ (concat (mapconcat
+ (lambda (part)
+ (if (and (not (null part)) (stringp part))
+ (rudel-obby-escape-string part)
+ part))
+ (cons name arguments) ":")
+ "\n")
+ )
+
+(defun rudel-obby-parse-message (message)
+ "Split MESSAGE at `:' and unescape resulting parts.
+
+The terminating `\n' should be removed from MESSAGE before
+calling this function."
+ (mapcar #'rudel-obby-unescape-string (split-string message ":")))
+
+(defun rudel-obby-send (socket name arguments)
+ "Send an obby message NAME with arguments ARGUMENTS through SOCKET."
+ ;; First, assemble the message string.
+ (let ((message (apply #'rudel-obby-assemble-message
+ name arguments)))
+ (if (>= (length message) rudel-obby-long-message-threshold)
+ ;; For huge messages, chunk the message data and transmit the
+ ;; chunks
+ (let ((total (/ (length message)
+ rudel-obby-long-message-chunk-size))
+ (current 0)
+ (reporter (make-progress-reporter "Sending data " 0.0 1.0)))
+ (rudel-loop-chunks message chunk rudel-obby-long-message-chunk-size
+ (progress-reporter-update reporter (/ (float current) total))
+ (process-send-string socket chunk)
+ (incf current))
+ (progress-reporter-done reporter))
+ ;; Send small messages in one chunk
+ (process-send-string socket message)))
+ )
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'protocol)
+ 'obby 'rudel-obby-backend)
+
+;;;###autoload
+(eval-after-load 'rudel-zeroconf
+ '(rudel-zeroconf-register-service "_lobby._tcp" 'obby))
+
+(provide 'rudel-obby)
+;;; rudel-obby.el ends here
diff --git a/emacs.d/lisp/rudel/obby/Project.ede b/emacs.d/lisp/rudel/obby/Project.ede
new file mode 100644
index 0000000..53d2422
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/Project.ede
@@ -0,0 +1,14 @@
+;; Object rudel/obby
+;; EDE project file.
+(ede-proj-project "rudel/obby"
+ :name "obby"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "obby"
+ :name "obby"
+ :path ""
+ :source '("rudel-obby.el" "rudel-obby-util.el" "rudel-obby-client.el" "rudel-obby-server.el" "rudel-obby-errors.el" "rudel-obby-state.el")
+ :aux-packages '("rudel" "jupiter")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-client.el b/emacs.d/lisp/rudel/obby/rudel-obby-client.el
new file mode 100644
index 0000000..5c192db
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-client.el
@@ -0,0 +1,973 @@
+;;; rudel-obby-client.el --- Client functions of the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, client
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the client part of the obby backend.
+
+
+;;; History:
+;;
+;; 0.2 - State machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'jupiter)
+
+(require 'rudel-state-machine)
+(require 'rudel-operations)
+(require 'rudel-chat)
+
+(require 'rudel-obby-errors)
+(require 'rudel-obby-util)
+(require 'rudel-obby-state)
+
+
+;;; Class rudel-obby-client-state-new
+;;
+
+(defclass rudel-obby-client-state-new
+ (rudel-obby-client-connection-state)
+ ()
+ "Start state of newly established connections.")
+
+(defmethod rudel-obby/obby_welcome
+ ((this rudel-obby-client-state-new) version)
+ "Handle obby 'welcome' message."
+ ;; Examine announced protocol version.
+ (with-parsed-arguments ((version number))
+ (message "Received Obby welcome message (version %d)" version))
+ ;; Start encryption handshake
+ 'encryption-negotiate)
+
+
+;;; Class rudel-obby-client-state-encryption-negotiate
+;;
+
+(defclass rudel-obby-client-state-encryption-negotiate
+ (rudel-obby-client-connection-state)
+ ()
+ "Start state of the encryption handshake.")
+
+(defmethod rudel-obby/net6_encryption
+ ((this rudel-obby-client-state-encryption-negotiate) value)
+ "Handle net6 'encryption' message."
+ (rudel-send this "net6_encryption_ok")
+ 'encryption-start)
+
+
+;;; Class rudel-obby-client-connection-encryption-start
+;;
+
+(defclass rudel-obby-client-state-encryption-start
+ (rudel-obby-client-connection-state)
+ ()
+ "Second state of the encryption handshake.")
+
+(defmethod rudel-obby/net6_encryption_begin
+ ((this rudel-obby-client-state-encryption-start))
+ "Handle net6 'encryption_begin' message."
+ ;; Start TLS encryption for the connection.
+ (with-slots (connection) this
+ (with-slots (socket) connection
+ (when (rudel-process-object socket :supports-tls)
+ (rudel-tls-start-tls socket)
+ (sit-for 1))))
+
+ ;; The connection is now established
+ 'joining)
+
+(defmethod rudel-obby/net6_encryption_failed
+ ((this rudel-obby-client-state-encryption-start))
+ "Handle net6 'encryption_failed' message."
+ ;; The connection is now established; without encryption though
+ 'joining)
+
+
+;;; Class rudel-obby-client-state-joining
+;;
+
+(defclass rudel-obby-client-state-joining
+ (rudel-obby-client-connection-state)
+ ()
+ "First state after the connection has been properly set up.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-joining))
+ "When entering this state, send a login request."
+ ;; Send login request with username and color. This can easily fail
+ ;; (resulting in response 'net6_login_failed') if the username or
+ ;; color is already taken.
+ (with-slots (info) (oref this connection)
+ (let ((username (plist-get info :username))
+ (color (plist-get info :color))
+ (global-password (plist-get info :global-password))
+ (user-password (plist-get info :user-password)))
+ (apply #'rudel-send
+ this
+ "net6_client_login"
+ username (rudel-obby-format-color color)
+ (append (when global-password
+ (list global-password))
+ (when (and global-password user-password)
+ (list user-password))))))
+ nil)
+
+(defmethod rudel-obby/obby_sync_init
+ ((this rudel-obby-client-state-joining) count)
+ "Handle obby 'sync_init' message."
+ ;; Switch to 'synching' state, passing the number of synchronization
+ ;; items.
+ (with-parsed-arguments ((count number))
+ (list 'session-synching count)))
+
+(defmethod rudel-obby/net6_login_failed
+ ((this rudel-obby-client-state-joining) reason)
+ "Handle net6 'login_failed' message."
+ (with-parsed-arguments ((reason number))
+ (with-slots (connection) this
+ (let ((error-data
+ (cond
+ ;; Invalid username
+ ((= reason rudel-obby-error-username-invalid)
+ (cons 'rudel-obby-username-invalid nil))
+ ;; Username in use
+ ((= reason rudel-obby-error-username-in-use)
+ (cons 'rudel-obby-username-in-use nil))
+ ;; Color in use
+ ((= reason rudel-obby-error-color-in-use)
+ (cons 'rudel-obby-color-in-use nil))
+ ;; Wrong global password
+ ((= reason rudel-obby-error-wrong-global-password)
+ (cons 'rudel-obby-wrong-global-password nil))
+ ;; Wrong user password
+ ((= reason rudel-obby-error-wrong-user-password)
+ (cons 'rudel-obby-wrong-user-password nil))
+ ;; Otherwise, signal a generic join error
+ (t (cons 'rudel-join-error nil)))))
+
+ ;; Switch to 'join-failed' state, pass the error data.
+ (list 'join-failed error-data))))
+ )
+
+
+;;; Class rudel-obby-client-state-join-failed
+;;
+
+(defclass rudel-obby-client-state-join-failed
+ (rudel-obby-client-connection-state)
+ ((error-symbol :initarg :error-symbol
+ :type symbol
+ :documentation
+ "Error symbol describing the reason for the
+login failure.")
+ (error-data :initarg :error-data
+ :type list
+ :documentation
+ "Additional error data describing the login
+failure."))
+ "State for failed login attempts.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-join-failed)
+ error)
+ "When the state is entered, store the error data passed in ERROR."
+ (with-slots (error-symbol error-data) this
+ (setq error-symbol (car error)
+ error-data (cdr error)))
+ nil)
+
+
+;;; Class rudel-obby-client-state idle
+;;
+
+(defclass rudel-obby-client-state-idle
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ()
+ "Default state of the connection.")
+
+(defmethod rudel-obby/net6_client_join
+ ((this rudel-obby-client-state-idle)
+ client-id name encryption user-id color)
+ "Handle net6 'client_join' message."
+ (with-parsed-arguments ((client-id number)
+ (user-id number)
+ (color color))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'eq #'rudel-id)))
+ (if user
+ ;; If we have such a user object, update its state.
+ (with-slots ((client-id1 client-id)
+ (color1 color)
+ connected
+ (encryption1 encryption)) user
+ (setq client-id1 client-id
+ color1 color
+ connected t
+ encryption1 (string= encryption "1"))
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook))
+ ;; Otherwise, create a new user object.
+ (let ((user (rudel-obby-user
+ name
+ :client-id client-id
+ :user-id user-id
+ :connected t
+ :encryption (string= encryption "1")
+ :color color)))
+ (rudel-add-user session user))))))
+ (message "Client joined: %s %s" name color))
+ nil)
+
+(defmethod rudel-obby/net6_client_part
+ ((this rudel-obby-client-state-idle) client-id)
+ "Handle net6 'client_part' message."
+ ;; Find the user object, associated to the client id. Remove the
+ ;; client id and change the user's state to disconnected.
+ (with-parsed-arguments ((client-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session client-id
+ #'eql #'rudel-client-id)))
+ (if user
+ (with-slots (client-id connected) user
+ ;; Set slot values.
+ (setq client-id nil
+ connected nil)
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook))
+ (display-warning
+ '(rudel obby)
+ (format "Cannot find user for client id: %d"
+ client-id)
+ :warning))))))
+ nil)
+
+(defmethod rudel-obby/obby_user_colour
+ ((this rudel-obby-client-state-idle) user-id color)
+ "Handle obby 'user_colour' message."
+ (with-parsed-arguments ((user-id number)
+ (color color))
+ ;; Find user object and set color.
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (with-slots ((name :object-name) (color1 :color)) user
+ ;; Set color in user object.
+ (setq color1 color)
+
+ ;; Run the change hook of the user object.
+ (object-run-hook-with-args user 'change-hook)
+
+ ;; Update overlays.
+ (rudel-overlay-set-face-attributes
+ (rudel-overlay-make-face-symbol 'author name)
+ color1))))))
+ nil)
+
+(defmethod rudel-obby/obby_document_create
+ ((this rudel-obby-client-state-idle)
+ owner-id doc-id name suffix encoding)
+ "Handle obby 'document_create' message."
+ (with-parsed-arguments ((owner-id number)
+ (doc-id number)
+ (suffix number)
+ (encoding coding-system))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((owner (rudel-find-user session owner-id
+ #'= #'rudel-id)))
+ (rudel-add-document session (rudel-obby-document
+ name
+ :subscribed (list owner)
+ :id doc-id
+ :owner-id owner-id
+ :suffix suffix))))
+ (message "New document: %s" name)))
+ nil)
+
+(defmethod rudel-obby/obby_document_remove
+ ((this rudel-obby-client-state-idle) doc-id)
+ "Handle obby 'document_remove' message."
+ (with-parsed-arguments ((doc-id document-id))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((document (rudel-find-document
+ session doc-id
+ #'equal #'rudel-both-ids)))
+ (if document
+ (progn
+ (rudel-remove-document session document)
+ (with-slots ((name :object-name)) document
+ (message "Document removed: %s" name)))
+ (display-warning
+ '(rudel obby)
+ (format "Document not found: %s" doc-id)
+ :warning))))))
+ nil)
+
+(defmethod rudel-obby/obby_document/rename
+ ((this rudel-obby-client-state-idle)
+ document user new-name new-suffix)
+ "Handle obby 'rename' submessage of the 'obby_document' message."
+ (with-parsed-arguments ((new-suffix number))
+ (with-slots ((name :object-name) suffix) document
+ (setq name new-name
+ suffix new-suffix)))
+ nil)
+
+(defmethod rudel-obby/obby_document/subscribe
+ ((this rudel-obby-client-state-idle)
+ document user-id)
+ "Handle 'subscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (rudel-add-user document user)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/unsubscribe
+ ((this rudel-obby-client-state-idle)
+ document user-id)
+ "Handle 'unsubscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection) this
+ (with-slots (session) connection
+ (let ((user (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (rudel-remove-user document user)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record
+ ((this rudel-obby-client-state-idle)
+ document user-id local-revision remote-revision
+ action &rest arguments)
+ "Handle 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number)
+ (local-revision number)
+ (remote-revision number))
+ ;; Locate the user.
+ (let ((user (with-slots (connection) this
+ (with-slots (session) connection
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))))
+ (if user
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch
+ this "rudel-obby/obby_document/record/" action
+ (append (list document user local-revision remote-revision)
+ arguments))
+ ;; Warn if we failed to locate or execute the
+ ;; method. Return nil in this case, so we remain in the
+ ;; current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s:%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby/obby_document/record/" action arguments)
+ :debug)
+ nil)))
+ ;; If we did not find the user, warn.
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "User not found: %d" user-id)
+ :warning)
+ nil))))
+ )
+
+(defmethod rudel-obby/obby_document/record/ins
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ position data)
+ "Handle 'ins' submessage of 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((position number))
+ (let ((operation (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :data data)))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/del
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ position length)
+ "Handle 'del' submessage of 'record' submessage of obby 'document' message."
+ (with-parsed-arguments ((position number)
+ (length number))
+ (let ((operation (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :to (+ position length))))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation))))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/split
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision
+ &rest operations)
+ "Handle 'split' submessage of 'record' submessage of obby 'document' message."
+ (let ((operation (rudel-message->operation
+ (cons "split" operations)
+ local-revision remote-revision)))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation)))
+ nil)
+
+(defmethod rudel-obby/obby_document/record/noop
+ ((this rudel-obby-client-state-idle)
+ document user local-revision remote-revision)
+ "Handle 'noop' submessage of 'record' submessage of obby 'document' message."
+ (let ((operation (jupiter-nop
+ (format "nop-%d-%d"
+ remote-revision local-revision))))
+ (with-slots (connection) this
+ (rudel-remote-operation connection
+ document user
+ remote-revision local-revision
+ operation)))
+ nil)
+
+(defmethod rudel-obby/obby_message ((this rudel-obby-client-state-idle)
+ sender text)
+ "Handle obby 'message' message"
+ (with-parsed-arguments ((sender number))
+ (with-slots (session) (oref this :connection)
+ (let ((sender (rudel-find-user session sender #'eq #'rudel-id)))
+ (rudel-chat-dispatch-message sender text))))
+ nil)
+
+
+;;; Class rudel-obby-client-state-session-synching
+;;
+
+(defclass rudel-obby-client-state-session-synching
+ (rudel-obby-client-connection-state)
+ ((all-items :initarg :all-items
+ :type (integer 0)
+ :documentation
+ "Total number of synchronization items expected
+ to receive from the server.")
+ (remaining-items :initarg :remaining-items
+ :type (integer 0)
+ :documentation
+ "Number of synchronization items not yet
+ received from the server.")
+ (have-self :initarg :have-self
+ :type boolean
+ :documentation
+ "Flag that remembers, whether the session has
+ a 'self' user object."))
+ "State used for synching session data.")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-session-synching)
+ num-items)
+ "When entering state, store number of expected items."
+ (with-slots (all-items remaining-items have-self) this
+ (setq all-items num-items
+ remaining-items num-items
+ have-self nil))
+ nil)
+
+(defmethod rudel-obby/net6_client_join
+ ((this rudel-obby-client-state-session-synching)
+ client-id name encryption user-id color)
+ "Handle net6 'client_join' message."
+ (with-parsed-arguments ((client-id number)
+ (user-id number)
+ (color color))
+ (with-slots (connection remaining-items have-self) this
+ (with-slots (session) connection
+ ;; Construct user object and add it to the session.
+ (let ((user (rudel-obby-user
+ name
+ :client-id client-id
+ :user-id user-id
+ :connected t
+ :encryption (string= encryption "1")
+ :color color)))
+ (rudel-add-user session user)
+
+ ;; The first user object describes the user of this client.
+ (unless have-self
+ (with-slots (self) session
+ (setq self user
+ have-self t)))))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_usertable_user
+ ((this rudel-obby-client-state-session-synching) user-id name color)
+ "Handle obby 'sync_usertable_user' message."
+ (with-parsed-arguments ((user-id number)
+ (color color))
+ (with-slots (connection remaining-items) this
+ (with-slots (session) connection
+ (rudel-add-user session (rudel-obby-user
+ name
+ :user-id user-id
+ :connected nil
+ :color color)))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_doclist_document
+ ((this rudel-obby-client-state-session-synching)
+ owner-id doc-id name suffix encoding &rest subscribed-user-ids)
+ "Handle obby 'sync_doclist_document' message."
+ (with-parsed-arguments ((doc-id number)
+ (owner-id number)
+ (suffix number)
+ (encoding coding-system))
+ (with-slots (connection remaining-items) this
+ (with-slots (session) connection
+ ;; Retrieve the subscribed users
+ (let ((subscribed-users
+ (mapcar
+ (lambda (user-id)
+ (with-parsed-arguments ((user-id number))
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ subscribed-user-ids)))
+
+ ;; Make a new document with the list of subscribed users.
+ (rudel-add-document session (rudel-obby-document
+ name
+ :subscribed subscribed-users
+ :id doc-id
+ :owner-id owner-id
+ :suffix suffix))))
+
+ ;; Decrease number of not yet received synchronization items.
+ (decf remaining-items)))
+ nil)
+
+(defmethod rudel-obby/obby_sync_final
+ ((this rudel-obby-client-state-session-synching))
+ "Handle obby 'sync_final' message."
+ 'idle)
+
+(defmethod object-print ((this rudel-obby-client-state-session-synching)
+ &rest strings)
+ "Append number of remaining items to string representation."
+ (with-slots (remaining-items) this
+ (call-next-method this (format " remaining: %d" remaining-items))))
+
+
+;;; Class rudel-obby-client-state-subscribing
+;;
+
+(defclass rudel-obby-client-state-subscribing
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ((document :initarg :document
+ :type rudel-obby-document-child
+ :documentation
+ ""))
+ "")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-subscribing)
+ user document)
+ "When entering this state, send a subscription request to the server."
+ (with-slots ((document1 :document)) this
+ (setq document1 document)
+
+ (with-slots ((doc-id :id) owner-id) document1
+ (with-slots (user-id) user
+ (rudel-send this "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "subscribe"
+ (format "%x" user-id)))))
+ nil)
+
+(defmethod rudel-obby/obby_document/sync_init
+ ((this rudel-obby-client-state-subscribing)
+ document num-bytes)
+ "Handle obby 'sync_init' message."
+ (with-parsed-arguments ((num-bytes number))
+ (with-slots (documents) this
+ (if (= num-bytes 0)
+ 'idle
+ (list 'document-synching document num-bytes))))
+ )
+
+
+;;; Class rudel-obby-client-state-document-synching
+;;
+
+(defclass rudel-obby-client-state-document-synching
+ (rudel-obby-client-connection-state
+ rudel-obby-document-handler)
+ ((document :initarg :document
+ :type rudel-obby-document-child
+ :documentation
+ "")
+ (all-bytes :initarg :all-bytes
+ :type (integer 0)
+ :documentation
+ "")
+ (remaining-bytes :initarg :remaining-bytes
+ :type (integer 0)
+ :documentation
+ ""))
+ "")
+
+(defmethod rudel-enter ((this rudel-obby-client-state-document-synching)
+ document num-bytes)
+ ""
+ (with-slots ((document1 :document) all-bytes remaining-bytes) this
+ (setq document1 document
+ all-bytes num-bytes
+ remaining-bytes num-bytes))
+ nil)
+
+(defmethod rudel-obby/obby_document/sync_chunk
+ ((this rudel-obby-client-state-document-synching)
+ document data user-id)
+ "Handle obby 'sync_chunk' message."
+ (with-parsed-arguments ((user-id number))
+ (with-slots (connection remaining-bytes) this
+ (with-slots (session) connection
+ (let* ((user (unless (zerop user-id)
+ (rudel-find-user session user-id
+ #'= #'rudel-id)))
+ (operation (rudel-insert-op "bulk-insert"
+ :from nil
+ :data data)))
+ (rudel-remote-operation document user operation)))
+
+ ;; After all bytes are transferred, go back to idle state.
+ (decf remaining-bytes (string-bytes data))
+ (if (= remaining-bytes 0)
+ 'idle
+ nil)))
+ )
+
+(defmethod object-print ((this rudel-obby-client-state-document-synching)
+ &rest strings)
+ "Append number of remaining items to string representation."
+ (with-slots (remaining-bytes) this
+ (call-next-method this (format " remaining: %d" remaining-bytes))))
+
+
+;;; Class rudel-obby-client-state-they-finalized
+;;
+
+(defclass rudel-obby-client-state-they-finalized
+ (rudel-obby-client-connection-state)
+ ()
+ "State used to indicate that the connection was closed by the peer.")
+
+
+;;; Client connection states.
+;;
+
+(defvar rudel-obby-client-connection-states
+ '((new . rudel-obby-client-state-new)
+ (encryption-negotiate . rudel-obby-client-state-encryption-negotiate)
+ (encryption-start . rudel-obby-client-state-encryption-start)
+ (joining . rudel-obby-client-state-joining)
+ (join-failed . rudel-obby-client-state-join-failed)
+ (idle . rudel-obby-client-state-idle)
+ (session-synching . rudel-obby-client-state-session-synching)
+ (subscribing . rudel-obby-client-state-subscribing)
+ (document-synching . rudel-obby-client-state-document-synching)
+ (they-finalized . rudel-obby-client-state-they-finalized))
+ "Name symbols and classes of connection states.")
+
+
+;;; Class rudel-obby-connection
+;;
+
+(defclass rudel-obby-connection (rudel-obby-socket-owner
+ rudel-connection
+ rudel-state-machine)
+ ((info :initarg :info
+ :type list
+ :documentation
+ "Stores connection information for later use.")
+ (contexts :initarg :contexts
+ :type hash-table
+ :documentation
+ "Contains jupiter context objects for all
+documents."))
+ "Class rudel-obby-connection ")
+
+(defmethod initialize-instance ((this rudel-obby-connection) &rest slots)
+ ;; Initialize slots of THIS
+ (when (next-method-p)
+ (call-next-method))
+
+ ;; Create a new hash-table object to hold jupiter contexts
+ ;; associated to documents.
+ (with-slots (contexts) this
+ (setq contexts (make-hash-table :test #'equal)))
+
+ ;; Register states.
+ (rudel-register-states this rudel-obby-client-connection-states)
+ )
+
+(defmethod rudel-register-state ((this rudel-obby-connection)
+ symbol state)
+ "Register SYMBOL and STATE and set connection slot of STATE."
+ ;; Associate THIS connection to STATE.
+ (oset state :connection this)
+
+ ;; Register STATE.
+ (when (next-method-p)
+ (call-next-method))
+ )
+
+(defmethod rudel-disconnect ((this rudel-obby-connection))
+ ""
+ (when (next-method-p)
+ (call-next-method)))
+
+(defmethod rudel-close ((this rudel-obby-connection))
+ ""
+ ;; Move the state machine into an error state.
+ (rudel-switch this 'they-finalized)
+
+ ;; Terminate the session.
+ (with-slots (session) this
+ (rudel-end session)))
+
+(defmethod rudel-find-context ((this rudel-obby-connection) document)
+ "Return the jupiter context associated to DOCUMENT in THIS connection."
+ (with-slots (contexts) this
+ (gethash (oref document :id) contexts)))
+
+(defmethod rudel-add-context ((this rudel-obby-connection) document)
+ "Add a jupiter context for DOCUMENT to THIS connection."
+ (with-slots (contexts) this
+ (with-slots ((doc-name :object-name) (doc-id :id)) document
+ (puthash doc-id
+ (jupiter-context (format "%s" doc-name))
+ contexts)))
+ )
+
+(defmethod rudel-remove-context ((this rudel-obby-connection) document)
+ "Remove the jupiter context associated to DOCUMENT from THIS connection."
+ (with-slots (contexts) this
+ (remhash (oref document :id) contexts)))
+
+(defmethod rudel-message ((this rudel-obby-connection) message)
+ "Dispatch MESSAGE to the current state of THIS object.
+If the state has no suitable method, generate a warning, but do
+nothing else."
+ ;; Dispatch message to state.
+ (rudel-accept this message))
+
+(defmethod rudel-change-color- ((this rudel-obby-connection) color)
+ ""
+ (rudel-send this "obby_user_colour"
+ (rudel-obby-format-color color)))
+
+(defmethod rudel-publish ((this rudel-obby-connection) document)
+ ""
+ ;; Create a new jupiter context for DOCUMENT.
+ (rudel-add-context this document)
+
+ ;; Announce the new document to the server.
+ (with-slots ((name :object-name) id buffer) document
+ (rudel-send this "obby_document_create"
+ (format "%x" id)
+ name
+ "UTF-8"
+ (with-current-buffer buffer
+ (buffer-string))))
+ )
+
+(defmethod rudel-unpublish ((this rudel-obby-connection) document)
+ "Remove DOCUMENT from the obby session THIS is connected to."
+ ;; Request removal of DOCUMENT.
+ (with-slots ((doc-id :id) owner-id) document
+ (rudel-send this "obby_document_remove"
+ (format "%x %x" owner-id doc-id)))
+
+ ;; Remove the jupiter context for DOCUMENT.
+ (rudel-remove-context this document)
+ )
+
+(defmethod rudel-subscribe-to ((this rudel-obby-connection) document)
+ ""
+ ;; Create a new jupiter context for DOCUMENT.
+ (rudel-add-context this document)
+
+ ;; Switch to subscribing state and wait until the state goes back to
+ ;; idle.
+ (with-slots (session) this
+ (with-slots (self) session
+ (rudel-switch this 'subscribing self document)))
+
+ (lexical-let ((reporter (make-progress-reporter "Subscribing " 0.0 1.0)))
+ (flet ((display-progress (state)
+ (cond
+ ;; Syncing document content, we can provide detailed progress.
+ ((and (consp state)
+ (eq (car state) 'document-synching))
+ (with-slots (all-bytes remaining-bytes) (cdr state)
+ (progress-reporter-force-update
+ reporter
+ (- 1.0 (/ (float remaining-bytes) (float all-bytes)))
+ (format "Subscribing (%s) " (car state)))))
+
+ ;; For other states, we just spin.
+ ((consp state)
+ (progress-reporter-force-update
+ reporter 0.5
+ (format "Subscribing (%s) " (car state))))
+
+ ;; Done
+ (t
+ (progress-reporter-force-update reporter 1.0 "Subscribing ")
+ (progress-reporter-done reporter)))))
+ (rudel-state-wait this '(idle) '(they-finalized) #'display-progress)))
+
+ ;; We receive a notification of our own subscription from the
+ ;; server. Consequently we do not add SELF to the list of subscribed
+ ;; users of DOCUMENT.
+ )
+
+(defmethod rudel-unsubscribe-from ((this rudel-obby-connection) document)
+ ""
+ ;; Delete the jupiter context for DOCUMENT.
+ (rudel-remove-context this document)
+
+ ;; Announce the end of our subscription to the server.
+ (with-slots (session) this
+ (with-slots (user-id) (oref session :self)
+ (with-slots ((doc-id :id) owner-id) document
+ (rudel-send this "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "unsubscribe"
+ (format "%x" user-id)))))
+
+ ;; We receive a notification of the end of our own subscription from
+ ;; the server. Consequently we do not remove SELF from the list of
+ ;; subscribed users of DOCUMENT.
+ )
+
+(defmethod rudel-local-insert ((this rudel-obby-connection)
+ document position data)
+ ""
+ (rudel-local-operation
+ this
+ document
+ (jupiter-insert "insert" :from position :data data)))
+
+(defmethod rudel-local-delete ((this rudel-obby-connection)
+ document position length)
+ ""
+ (rudel-local-operation
+ this
+ document
+ (jupiter-delete "delete" :from position :to (+ position length))))
+
+(defmethod rudel-local-operation ((this rudel-obby-connection)
+ document operation)
+ "Handle OPERATION performed on DOCUMENT by sending a message through THIS connection."
+ ;; Convert character positions in OPERATION to byte positions, since
+ ;; the obby protocol works with byte positions, but Emacs uses
+ ;; character positions.
+ (with-slots (buffer) document
+ (rudel-obby-char->byte operation buffer))
+
+ ;; Find jupiter context for DOCUMENT.
+ (let ((context (rudel-find-context this document)))
+
+ ;; Notify the server of the operation.
+ (with-slots (owner-id (doc-id :id)) document
+ (with-slots (local-revision remote-revision) context
+ (apply #'rudel-send
+ this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "record"
+ (format "%x" local-revision)
+ (format "%x" remote-revision)
+ (rudel-operation->message operation))))
+
+ ;; Submit the operation to the jupiter context.
+ (jupiter-local-operation context operation))
+ )
+
+(defmethod rudel-remote-operation ((this rudel-obby-connection)
+ document user
+ remote-revision local-revision
+ operation)
+ "Handle OPERATION received through THIS connection performed by USER on DOCUMENT."
+ (let* (;; Find jupiter context for DOCUMENT.
+ (context (rudel-find-context this document))
+ ;; And transform the operation.
+ (transformed (jupiter-remote-operation
+ context
+ remote-revision local-revision
+ operation)))
+
+ ;; Convert byte positions in OPERATION to character positions,
+ ;; since the obby protocol works with byte positions, but Emacs
+ ;; uses character positions.
+ (with-slots (buffer) document
+ (rudel-obby-byte->char transformed buffer)) ;; TODO operation's responsibility?
+
+ ;; Apply the transformed operation to the document.
+ (rudel-remote-operation document user transformed))
+ )
+
+(provide 'rudel-obby-client)
+;;; rudel-obby-client.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-debug.el b/emacs.d/lisp/rudel/obby/rudel-obby-debug.el
new file mode 100644
index 0000000..8f5f168
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-debug.el
@@ -0,0 +1,122 @@
+;;; rudel-obby-debug.el --- Debugging functions for obby backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, debugging
+;; X-RCS: $Id:$
+;;
+;; 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 3 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, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Debugging functions for the obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-debug)
+
+(require 'rudel-obby-util)
+
+
+;;; Variables
+;;
+
+(defvar rudel-obby-debug-old-state nil
+ "Saves state of state machines across one function call.")
+
+
+;;; Functions
+;;
+
+(defmethod rudel-send :before ((this rudel-obby-socket-owner)
+ name &rest arguments)
+ "Print NAME and ARGUMENTS to debug stream."
+ (let ((message (apply #'rudel-obby-assemble-message
+ name arguments)))
+
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :sent
+ (concat (substring message 0 (min (length message) 100))
+ (when (> (length message) 100)
+ "..."))
+ (append (list name) arguments))))
+ )
+
+(defmethod rudel-receive :before ((this rudel-obby-socket-owner) data)
+ "Print DATA to debug stream."
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :received
+ (concat (substring data 0 (min (length data) 100))
+ (when (> (length data) 100)
+ "..."))))
+ )
+
+(defmethod rudel-message :before ((this rudel-obby-socket-owner)
+ message)
+ "Print DATA to debug stream."
+ (let ((data (apply #'rudel-obby-assemble-message message)))
+
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :received-processed
+ (concat (substring data 0 (min (length data) 100))
+ (when (> (length data) 100)
+ "..."))
+ message)
+ ))
+ )
+
+(defmethod rudel-switch :before ((this rudel-obby-socket-owner)
+ state &rest arguments)
+ "Store name of STATE for later printing."
+ (with-slots (state) this
+ (setq rudel-obby-debug-old-state
+ (if state
+ (object-name-string state)
+ "#start")))
+ )
+
+(defmethod rudel-switch :after ((this rudel-obby-socket-owner)
+ state &rest arguments)
+ "Print STATE and ARGUMENTS to debug stream."
+ (with-slots (socket state) this
+ (let ((old-state rudel-obby-debug-old-state)
+ (new-state (object-name-string state)))
+ (unless (string= old-state new-state)
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :special
+ (if arguments
+ (format "%s -> %s %s" old-state new-state arguments)
+ (format "%s -> %s" old-state new-state))))))
+ )
+
+(provide 'rudel-obby-debug)
+;;; rudel-obby-debug.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-errors.el b/emacs.d/lisp/rudel/obby/rudel-obby-errors.el
new file mode 100644
index 0000000..689d4a8
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-errors.el
@@ -0,0 +1,65 @@
+;;; rudel-obby-errors.el --- Error data used in the obby Rudel backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, errors
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains definitions of error conditions and numeric
+;; error codes used in the Rudel obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+
+;;; Obby protocol error codes
+;;
+
+(defconst rudel-obby-error-username-invalid #x0001
+ "Error code for invalid username.")
+
+(defconst rudel-obby-error-username-in-use #x0002
+ "Error code for username already in use.")
+
+(defconst rudel-obby-error-color-in-use #x0100
+ "Error code for color already in use.")
+
+(defconst rudel-obby-error-wrong-global-password #x0101
+ "Error code for wrong global password.")
+
+(defconst rudel-obby-error-wrong-user-password #x0102
+ "Error code for wrong user password.")
+
+(defconst rudel-obby-error-protocol-version-mismatch #x0103
+ "Error code for protocol version mismatch.")
+
+(defconst rudel-obby-error-not-encrypted #x0104
+ "Error code for not encrypted.")
+
+(provide 'rudel-obby-errors)
+;;; rudel-obby-errors.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-server.el b/emacs.d/lisp/rudel/obby/rudel-obby-server.el
new file mode 100644
index 0000000..5bf1158
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-server.el
@@ -0,0 +1,798 @@
+;;; rudel-obby-server.el --- Server component of the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, server
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the server part of the obby backend for Rudel.
+;;
+;; It is implemented using one state machine (class
+;; `rudel-obby-client') for each client connection. These state
+;; machines have the following states:
+;;
+;; + new `rudel-obby-server-state-new'
+;; + encryption-negotiate `rudel-obby-server-state-encryption-negotiate'
+;; + before-join `rudel-obby-server-state-before-join'
+;; + idle `rudel-obby-server-state-idle'
+
+
+;;; History:
+;;
+;; 0.2 - State machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'jupiter)
+
+(require 'rudel-state-machine)
+
+(require 'rudel-obby-errors)
+(require 'rudel-obby-util)
+(require 'rudel-obby-state)
+
+
+;;; Class rudel-obby-server-state-new
+;;
+
+(defclass rudel-obby-server-state-new
+ (rudel-obby-server-connection-state)
+ ()
+ "State in which new connections start out.")
+
+(defmethod rudel-enter ((this rudel-obby-server-state-new))
+ "Sends welcome messages to the client and starts the session
+timeout timer."
+ ;; Send greeting sequence to the client.
+ (rudel-send this
+ "obby_welcome"
+ (number-to-string rudel-obby-protocol-version))
+
+ ;; Switch to encryption negotiation state.
+ 'encryption-negotiate)
+
+
+;;; Class rudel-obby-server-state-encryption-negotiate
+;;
+
+(defclass rudel-obby-server-state-encryption-negotiate
+ (rudel-obby-server-connection-state)
+ ()
+ "Encryption negotiation state.")
+
+(defmethod rudel-enter ((this rudel-obby-server-state-encryption-negotiate))
+ "Send net6 'encryption' message requesting to not enable encryption."
+ (rudel-send this "net6_encryption" "0")
+ nil)
+
+(defmethod rudel-obby/net6_encryption_ok
+ ((this rudel-obby-server-state-encryption-negotiate))
+ "Handle net6 'encryption_ok' message.
+Even if the client requests an encrypted connection, we cancel
+the negotiation."
+ (rudel-send this "net6_encryption_failed")
+ 'before-join)
+
+(defmethod rudel-obby/net6_encryption_failed
+ ((this rudel-obby-server-state-encryption-negotiate))
+ "Handle net6 'encryption_failed' message.
+No action has to be taken, since the client simply proceeds after
+failed encryption negotiation."
+ 'before-join)
+
+
+;;; Class rudel-obby-server-state-before-join
+;;
+
+(defclass rudel-obby-server-state-before-join
+ (rudel-obby-server-connection-state)
+ ()
+ "Waiting for client request joining the session.")
+
+(defmethod rudel-obby/net6_client_login
+ ((this rudel-obby-server-state-before-join) username color
+ &optional global-password user-password)
+ "Handle net6 'client_login' message."
+ (with-parsed-arguments ((color color))
+ (with-slots (server
+ (client-id :id)
+ user
+ encryption) (oref this :connection)
+ ;; Make sure USERNAME and COLOR are valid.
+ (let ((error (rudel-check-username-and-color
+ server username color)))
+ (if error
+ ;; If USERNAME or COLOR are invalid, send the error code
+ ;; to the client and stay in the current state.
+ (progn
+ (rudel-send this
+ "net6_login_failed"
+ (format "%x" error))
+ nil)
+
+ ;; Create a user object for this client and add it to the
+ ;; server.
+ (setq user (rudel-make-user
+ server
+ username client-id color encryption))
+ (rudel-add-user server user)
+
+ ;; Broadcast the join event to all clients (including the
+ ;; new one).
+ (with-slots ((name :object-name) color (user-id :user-id)) user
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "net6_client_join"
+ (format "%x" client-id)
+ name
+ "0"
+ (format "%x" user-id)
+ (rudel-obby-format-color color)))
+
+ ;; Get the new client up to date:
+ ;; - transmit user list
+ ;; - connected users
+ ;; - disconnected users
+ ;; - transmit document list
+ (with-slots (users clients documents) server
+ ;; Send number of synchronization items: sum of numbers of
+ ;; offline users and documents.
+ (let ((number-of-items (+ (length users) (length documents))))
+ (rudel-send this
+ "obby_sync_init"
+ (format "%x" number-of-items)))
+
+ ;; Transmit list of connected users.
+ (dolist (client clients)
+ (with-slots ((client-id :id) user) client
+ (when user
+ (with-slots ((name :object-name)
+ color
+ (user-id :user-id)) user
+ (rudel-send this
+ "net6_client_join"
+ (format "%x" client-id)
+ name
+ "0"
+ (format "%x" user-id)
+ (rudel-obby-format-color color))))))
+
+ ;; Transmit list of disconnected users.
+ (let ((offline-users (remove-if #'rudel-connected users)))
+ (dolist (user offline-users)
+ (with-slots ((name :object-name) user-id color) user
+ (rudel-send this
+ "obby_sync_usertable_user"
+ (format "%x" user-id)
+ name
+ (rudel-obby-format-color color)))))
+
+ ;; Transmit document list
+ (dolist (document documents)
+ (with-slots ((name :object-name)
+ (doc-id :id)
+ owner-id
+ suffix
+ subscribed) document
+ (apply #'rudel-send
+ this
+ "obby_sync_doclist_document"
+ (format "%x" owner-id)
+ (format "%x" doc-id)
+ name
+ (format "%x" suffix)
+ "UTF-8"
+ (mapcar
+ (lambda (user1) ;; TODO we could use `user' here, but there is a bug in cl
+ (format "%x" (rudel-id user1)))
+ subscribed)))))
+
+ (rudel-send this "obby_sync_final")
+ 'idle))))
+ )
+
+
+;;; Class rudel-obby-server-state-idle
+;;
+
+(defclass rudel-obby-server-state-idle
+ (rudel-obby-server-connection-state)
+ ()
+ "Idle state of a server connection.
+
+The connection enters this state when all setup work is finished,
+the client has joined the session and no operation is in
+progress. In this state, the connection waits for new messages
+from the client that initiate operations. Simple (which means
+stateless in this case) operations are performed without leaving
+the idle state.")
+
+(defmethod rudel-obby/obby_user_colour
+ ((this rudel-obby-server-state-idle) color-)
+ "Handle obby 'user_colour' message.
+This method is called when the connected user requests a change
+of her color to COLOR."
+ (with-parsed-arguments ((color- color))
+ (with-slots (user) (oref this :connection)
+ (with-slots (color (user-id :user-id)) user
+ ;; Set color slot value.
+ (setq color color-)
+
+ ;; Run change hook.
+ (object-run-hook-with-args user 'change-hook)
+
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "obby_user_colour"
+ (format "%x" user-id)
+ (rudel-obby-format-color color)))))
+ nil)
+
+(defmethod rudel-obby/obby_document_create
+ ((this rudel-obby-server-state-idle)
+ doc-id name encoding content)
+ "Handle obby 'document_create' message."
+ (with-parsed-arguments ((doc-id number)
+ (encoding coding-system))
+ (with-slots (user server) (oref this :connection)
+ (with-slots ((user-id :user-id)) user
+ ;; Create a (hidden) buffer for the new document.
+ (let* ((buffer (get-buffer-create
+ (generate-new-buffer-name
+ (concat " *" name "*"))))
+ ;; Create the new document object
+ (document (rudel-obby-document
+ name
+ :buffer buffer
+ :subscribed (list user)
+ :id doc-id
+ :owner-id user-id
+ :suffix 1)))
+
+ ;; Initialize the buffer's content
+ (with-current-buffer buffer
+ (insert content))
+
+ (with-slots (suffix) document
+ ;; Determine an appropriate suffix to provide an unique
+ ;; name for the new document.
+ (while (rudel-find-document server
+ (if (= suffix 1)
+ name
+ (format "%s<%d>" name suffix))
+ #'string= #'rudel-unique-name)
+ (incf suffix))
+
+ ;; Add the document to the server's document list
+ (rudel-add-document server document)
+
+ ;; Maybe notify the creating client of the changed suffix.
+ (unless (= suffix 1)
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" user-id doc-id)
+ "rename"
+ (format "%x" user-id)
+ name
+ (format "%x" suffix)))
+
+ ;; Notify other clients of the new document
+ (rudel-broadcast this (list 'exclude (oref this :connection))
+ "obby_document_create"
+ (format "%x" user-id)
+ (format "%x" doc-id)
+ name
+ (format "%x" suffix)
+ (upcase (symbol-name encoding))))
+
+ ;; Add a jupiter context for (THIS DOCUMENT).
+ (rudel-add-context server (oref this :connection) document))))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document
+ ((this rudel-obby-server-state-idle) doc-id action &rest arguments)
+ "Handle obby 'document' messages."
+ (with-parsed-arguments ((doc-id document-id))
+ ;; Locate the document based on owner id and document id
+ (let ((document (with-slots (server) (oref this :connection)
+ (rudel-find-document server doc-id
+ #'equal #'rudel-both-ids))))
+ (rudel-obby-dispatch this action
+ (append (list document) arguments)
+ "rudel-obby/obby_document/")))
+ )
+
+(defmethod rudel-obby/obby_document/subscribe
+ ((this rudel-obby-server-state-idle) document user-id)
+ "Handle 'subscribe' submessage of obby 'document' message."
+ (with-parsed-arguments ((user-id number))
+ (let ((user (with-slots (server) (oref this :connection)
+ (rudel-find-user server user-id
+ #'= #'rudel-id))))
+ (with-slots (owner-id (doc-id :id) subscribed buffer) document
+
+ ;; Track subscription, handle duplicate subscription requests.
+ (when (memq user subscribed)
+ (error "User `%s' already subscribed to document `%s'"
+ (object-name user) (object-name document)))
+ (rudel-add-user document user)
+
+ ;; Synchronize the buffer content to the client.
+ (with-current-buffer buffer
+ ;; Send overall buffer size
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "sync_init"
+ (format "%x" (1- (position-bytes (point-max)))))
+
+ ;; Send buffer chunks with author ids
+ (dolist (chunk (rudel-chunks document))
+ (multiple-value-bind (from to author) chunk
+ (let ((string (buffer-substring (+ from 1) (+ to 1))))
+ (rudel-send this
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "sync_chunk"
+ string
+ (format "%x"
+ (if author
+ (oref author :user-id)
+ 0)))))))
+
+ ;; Notify clients of the new subscription (including our own
+ ;; client, who requested the subscription).
+ (with-slots ((user-id :user-id)) user
+ (rudel-broadcast this nil
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "subscribe"
+ (format "%x" user-id)))))
+
+ ;; Add a jupiter context for (THIS document).
+ (with-slots (server) (oref this :connection)
+ (rudel-add-context server (oref this :connection) document))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/unsubscribe
+ ((this rudel-obby-server-state-idle) document user-id)
+ "Handle 'unsubscribe' submessage of 'obby_document' message."
+ (with-parsed-arguments ((user-id number))
+ (let ((user (with-slots (server) (oref this :connection)
+ (rudel-find-user server user-id
+ #'= #'rudel-id))))
+ (with-slots (owner-id (doc-id :id) subscribed) document
+
+ ;; Track subscription, handle invalid unsubscribe requests
+ (unless (memq user subscribed)
+ (error "User `%s' not subscribed to document `%s'"
+ (object-name user) (object-name document)))
+ (rudel-remove-user document user)
+
+ ;; Notify clients of the canceled subscription (including our
+ ;; own client, who requested being unsubscribed).
+ (with-slots ((user-id :user-id)) user
+ (rudel-broadcast this nil
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "unsubscribe"
+ (format "%x" user-id))))
+
+ ;; Remove jupiter context for (THIS DOCUMENT).
+ (with-slots (server) (oref this :connection)
+ (rudel-remove-context server (oref this :connection) document)))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/record
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision action &rest arguments)
+ "Handle 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((local-revision number)
+ (remote-revision number))
+ ;; Dispatch to specialized operation handlers.
+ (rudel-obby-dispatch
+ this action
+ (append (list document local-revision remote-revision)
+ arguments)
+ "rudel-obby/obby_document/record/"))
+ )
+
+(defmethod rudel-obby/obby_document/record/ins
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision position data)
+ "Handle 'ins' submessage of 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((position number))
+ ;; Construct the operation object and process it.
+ (rudel-remote-operation
+ (oref this :connection) document
+ remote-revision local-revision
+ (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :data data))
+ nil)
+ )
+
+(defmethod rudel-obby/obby_document/record/del
+ ((this rudel-obby-server-state-idle)
+ document local-revision remote-revision position length)
+ "Handle 'del' submessage of 'record' submessages of 'obby_document' message."
+ (with-parsed-arguments ((position number)
+ (length number))
+ ;; Construct the operation object and process it.
+ (rudel-remote-operation
+ (oref this :connection) document
+ remote-revision local-revision
+ (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position
+ :to (+ position length)))
+ nil)
+ )
+
+
+;;; Client connection states.
+;;
+
+(defvar rudel-obby-server-connection-states
+ '((new . rudel-obby-server-state-new)
+ (encryption-negotiate . rudel-obby-server-state-encryption-negotiate)
+ (before-join . rudel-obby-server-state-before-join)
+ (idle . rudel-obby-server-state-idle))
+ "Name symbols and classes of connection states.")
+
+
+;;; Class rudel-obby-client
+;;
+
+(defclass rudel-obby-client (rudel-obby-socket-owner
+ rudel-state-machine)
+ ((server :initarg :server
+ :type rudel-obby-server
+ :documentation
+ "")
+ (id :initarg :id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "")
+ (user :initarg :user
+ :type (or rudel-obby-user null)
+ :initform nil
+ :documentation
+ "")
+ (encryption :initarg :encryption
+ :type boolean
+ :documentation
+ ""))
+ "Each object of this class represents one client, that is
+connected to the server. This object handles all direct
+communication with the client, while broadcast messages are
+handled by the server.")
+
+(defmethod initialize-instance ((this rudel-obby-client) &rest slots)
+ "Initialize slots of THIS and register state machine states."
+ ;; Initialize slots of THIS
+ (when (next-method-p)
+ (call-next-method))
+
+ ;; Register states.
+ (rudel-register-states this rudel-obby-server-connection-states)
+ )
+
+(defmethod rudel-register-state ((this rudel-obby-client) symbol state)
+ "Register SYMBOL and STATE and set connection slot of STATE."
+ ;; Associate THIS connection to STATE.
+ (oset state :connection this)
+
+ ;; Register STATE.
+ (call-next-method))
+
+(defmethod rudel-end ((this rudel-obby-client))
+ ""
+ (rudel-disconnect this))
+
+(defmethod rudel-close ((this rudel-obby-client))
+ ""
+ (with-slots (server) this
+ (rudel-remove-client server this)))
+
+(defmethod rudel-message ((this rudel-obby-client) message)
+ "Dispatch MESSAGE to the active state of THIS state machine."
+ ;; Dispatch message to state
+ (rudel-accept this message))
+
+(defmethod rudel-broadcast ((this rudel-obby-client)
+ receivers name &rest arguments)
+ "Broadcast message NAME with arguments ARGUMENTS to RECEIVERS."
+ (with-slots (server) this
+ (apply #'rudel-broadcast server receivers name arguments)))
+
+(defmethod rudel-remote-operation ((this rudel-obby-client)
+ document
+ local-revision remote-revision
+ operation)
+ "Execute and relay OPERATION on DOCUMENT."
+ (with-slots (server user) this
+ ;; Transform OPERATION and find clients that need to receive
+ ;; notifications.
+ (let* ((context (rudel-find-context server this document))
+ (transformed (jupiter-remote-operation
+ context
+ local-revision remote-revision
+ operation))
+ (receivers (rudel-subscribed-clients-not-self
+ this document)))
+
+ ;; Relay change notification to other clients. We use
+ ;; TRANSFORMED before the byte -> char conversion which is what
+ ;; the receivers expect.
+ (with-slots (user-id) user
+ (with-slots (owner-id (doc-id :id)) document
+ ;; Construct and send messages to all receivers individually
+ ;; since the contents of the messages depends on the state
+ ;; of the jupiter context associated the respective
+ ;; receiver.
+ (dolist (receiver receivers)
+
+ ;; Find the jupiter context for RECEIVER and use its
+ ;; revision information.
+ (let ((context (rudel-find-context server receiver document)))
+ ;; Construct and send one message.
+ (with-slots (local-revision remote-revision) context
+ (apply #'rudel-send
+ receiver
+ "obby_document"
+ (format "%x %x" owner-id doc-id)
+ "record"
+ (format "%x" user-id)
+ (format "%x" local-revision)
+ (format "%x" remote-revision)
+ (rudel-operation->message transformed)))
+
+ ;; Submit the operation to the jupiter context.
+ (jupiter-local-operation context transformed)))))
+
+ ;; Incorporate change into DOCUMENT (the server-side
+ ;; document). We have to convert bytes -> chars before we can do
+ ;; this.
+ (with-slots (buffer) document
+ (rudel-obby-byte->char transformed buffer))
+
+ (rudel-remote-operation document user transformed)))
+ )
+
+(defmethod rudel-subscribed-clients-not-self ((this rudel-obby-client)
+ document)
+ "Return a list of clients subscribed to DOCUMENT excluding THIS."
+ (with-slots (clients) (oref this :server)
+ (with-slots (subscribed) document
+ (remove-if
+ (lambda (client)
+ (with-slots (user) client
+ (or (eq client this)
+ (not (memq user subscribed)))))
+ clients)))
+ )
+
+
+;;; Class rudel-obby-server
+;;
+
+(defclass rudel-obby-server (rudel-server-session
+ rudel-socket-owner)
+ ((clients :initarg :clients
+ :type list
+ :initform nil
+ :documentation
+ "")
+ (next-client-id :initarg :next-client-id
+ :type integer
+ :initform 1
+ :documentation
+ "")
+ (next-user-id :initarg :next-user-id
+ :type integer
+ :initform 1
+ :documentation
+ "")
+ (contexts :initarg :contexts
+ :type hash-table
+ :documentation
+ ""))
+ "Class rudel-obby-server ")
+
+(defmethod initialize-instance ((this rudel-obby-server) &rest slots)
+ ""
+ (when (next-method-p)
+ (call-next-method))
+
+ (with-slots (contexts) this
+ (setq contexts (make-hash-table :test 'equal))))
+
+(defmethod rudel-end ((this rudel-obby-server))
+ ""
+ (rudel-disconnect this))
+
+(defmethod rudel-broadcast ((this rudel-obby-server)
+ receivers name &rest arguments)
+ "Send a message of type NAME with arguments ARGUMENTS to RECEIVERS.
+
+RECEIVERS can be a object derived from rudel-obby-client, a list
+of such objects or a list with car 'exclude and cdr a list of
+such objects derived from rudel-obby-client."
+ ;; Construct list of receivers.
+ (let ((receiver-list
+ (cond
+ ;; If RECEIVERS is nil, the message should be broadcast to
+ ;; all clients.
+ ((null receivers) (oref this :clients))
+ ;; If RECEIVERS is a (non-empty) list of rudel-obby-client
+ ;; (or derived) objects, treat it as a list of receivers.
+ ((and (listp receivers)
+ (rudel-obby-client-child-p (car receivers)))
+ receivers)
+ ;; If RECEIVERS is a (non-empty) list with cdr equal to
+ ;; 'exclude treat it as a list of receivers to exclude.
+ ((and (listp receivers)
+ (eq (car receivers) 'exclude))
+ (with-slots (clients) this
+ (set-difference clients (cdr receivers)
+ :key #'rudel-id)))
+ ;; If RECEIVERS is a single rudel-obby-client (or derived)
+ ;; object, send the message to that client.
+ ((rudel-obby-client-child-p receivers)
+ (list receivers))
+ ;;
+ (t (signal 'wrong-type-argument (type-of receivers))))))
+
+ ;; Send message to receivers.
+ (dolist (receiver receiver-list)
+ (apply #'rudel-send receiver name arguments)))
+ )
+
+(defmethod rudel-make-user ((this rudel-obby-server)
+ name client-id color encryption)
+ ""
+ (with-slots (next-user-id) this
+ (let ((user (rudel-obby-user name
+ :color color
+ :client-id client-id
+ :user-id next-user-id
+ :connected t
+ :encryption encryption)))
+ (incf next-user-id)
+ user))
+ )
+
+(defmethod rudel-check-username-and-color ((this rudel-obby-server)
+ username color)
+ "Check whether USERNAME and COLOR are valid.
+USERNAME must not be empty and must not be used by another
+user. COLOR has to be sufficiently different from used colors."
+ (cond
+ ;; The empty user name is not allowed
+ ((string= username "")
+ rudel-obby-error-username-invalid)
+
+ ;; Make sure the user name is not already in use.
+ ((rudel-find-user this username
+ #'string= #'object-name-string)
+ rudel-obby-error-username-in-use)
+
+ ;; Make sure the color is sufficiently dissimilar to all used
+ ;; colors.
+ ((rudel-find-user this color
+ (lambda (left right)
+ (< (color-distance left right) 20000)) ;; TODO constant
+ #'rudel-color)
+ rudel-obby-error-color-in-use))
+ )
+
+(defmethod rudel-add-client ((this rudel-obby-server)
+ client-socket)
+ ""
+ (with-slots (next-client-id clients) this
+ (let ((client (rudel-obby-client (process-name client-socket)
+ :server this
+ :socket client-socket
+ :id next-client-id
+ :encryption nil)))
+ (push client clients))
+ (incf next-client-id))
+ )
+
+(defmethod rudel-remove-client ((this rudel-obby-server)
+ client)
+ ""
+ (with-slots ((client-id :id) user) client
+ ;; Broadcast the part event to all remaining clients.
+ (rudel-broadcast this (list 'exclude client)
+ "net6_client_part"
+ (format "%x" client-id))
+
+ ;; If the client has an associated user object, set the status of
+ ;; the user object to offline.
+ (when user
+ ;; Set slot value.
+ (with-slots (connected) user
+ (setq connected nil))
+
+ ;; Run change hook.
+ (object-run-hook-with-args user 'change-hook)))
+
+ (object-remove-from-list this :clients client)
+ )
+
+(defmethod rudel-find-context ((this rudel-obby-server) client document)
+ "Return the jupiter context associated to (CLIENT DOCUMENT) in THIS."
+ (with-slots (contexts) this
+ (gethash (rudel-obby-context-key client document) contexts)))
+
+(defmethod rudel-add-context ((this rudel-obby-server) client document)
+ "Add a jupiter context for (CLIENT DOCUMENT) to THIS."
+ (with-slots (contexts) this
+ (with-slots ((client-id :id)) client
+ (with-slots ((doc-name :object-name)) document
+ (puthash
+ (rudel-obby-context-key client document)
+ (jupiter-context (format "%d-%s" client-id doc-name))
+ contexts))))
+ )
+
+(defmethod rudel-remove-context ((this rudel-obby-server) client document)
+ "Remove the jupiter context associated to (CLIENT DOCUMENT) from THIS."
+ (with-slots (contexts) this
+ (remhash
+ (rudel-obby-context-key client document)
+ contexts)))
+
+(defun rudel-obby-context-key (client document)
+ "Generate hash key based on CLIENT and DOCUMENT."
+ (with-slots ((client-id :id)) client
+ (with-slots ((doc-id :id)) document
+ (list client-id doc-id))))
+
+(defmethod object-print ((this rudel-obby-server) &rest strings)
+ "Print THIS with number of clients."
+ (with-slots (clients) this
+ (apply #'call-next-method
+ this
+ (format " clients: %d"
+ (length clients))
+ strings))
+ )
+
+(provide 'rudel-obby-server)
+;;; rudel-obby-server.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-state.el b/emacs.d/lisp/rudel/obby/rudel-obby-state.el
new file mode 100644
index 0000000..a190967
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-state.el
@@ -0,0 +1,169 @@
+;;; rudel-obby-state.el --- Base class for states used in the obby backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, state machine
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a base class for finite state machine states
+;; used in the obby backend.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-util)
+(require 'rudel-state-machine)
+
+(require 'rudel-obby-util)
+
+
+;;; Class rudel-obby-state
+;;
+
+(defclass rudel-obby-state (rudel-state)
+ ((connection :initarg :connection
+ :type rudel-obby-socket-owner
+ :documentation
+ "Connection object that uses the state."))
+ "Base class for state classes used in the obby backend."
+ :abstract t)
+
+(defmethod rudel-enter ((this rudel-obby-state))
+ "Default behavior is doing nothing when entering a state."
+ nil)
+
+(defmethod rudel-leave ((this rudel-obby-state))
+ "Default behavior is doing nothing when leaving a state.")
+
+(defmethod rudel-accept ((this rudel-obby-state) message)
+ "Dispatch to appropriate handler based on MESSAGE.
+Display a warning if no such handler is found."
+ ;; Try to dispatch to the correct message handler. If there is none,
+ ;; warn.
+ (let ((name (car message))
+ (arguments (cdr message)))
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch this "rudel-obby/" name arguments)
+ ;; Warn if we failed to locate or execute the method. Return nil
+ ;; in this case, so we remain in the current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s/%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby" name arguments)
+ :debug)
+ nil))))
+ )
+
+(defmethod rudel-send ((this rudel-obby-state) &rest args)
+ "Send ARGS through the connection associated with THIS."
+ (with-slots (connection) this
+ (apply #'rudel-send connection args)))
+
+
+;;; Class rudel-obby-client-connection-state
+;;
+
+(defclass rudel-obby-client-connection-state (rudel-obby-state)
+ ()
+ "Base class for state classes used by obby client connections."
+ :abstract t)
+
+(defmethod rudel-obby/net6_ping ((this rudel-obby-client-connection-state))
+ "Handle net6 'ping' message."
+ (rudel-send this "net6_pong")
+ nil)
+
+
+;;; Class rudel-obby-server-connection-state
+;;
+
+(defclass rudel-obby-server-connection-state (rudel-obby-state)
+ ()
+ "Base class for server connection states."
+ :abstract t)
+
+(defmethod rudel-broadcast ((this rudel-obby-server-connection-state)
+ receivers name &rest arguments)
+ "Broadcast message NAME with arguments ARGUMENTS to RECEIVERS."
+ (with-slots (connection) this
+ (apply #'rudel-broadcast connection receivers name arguments)))
+
+
+;;; Class rudel-obby-document-handler
+;;
+
+(defclass rudel-obby-document-handler ()
+ ()
+ "Mixin class that provides ability to process submessages of
+ obby 'document' messages.")
+
+(defmethod rudel-obby/obby_document
+ ((this rudel-obby-document-handler) doc-id action &rest arguments)
+ "Handle obby 'document' message family."
+ ;; Try to dispatch to the correct message handler. If there is none,
+ ;; warn.
+ (with-parsed-arguments ((doc-id document-id))
+ ;; Locate the document based on owner id and document id.
+ (let ((document (with-slots (connection) this
+ (with-slots (session) connection
+ (rudel-find-document session doc-id
+ #'equal #'rudel-both-ids)))))
+ (if document
+ (condition-case error
+ ;; Try to dispatch
+ (rudel-dispatch this "rudel-obby/obby_document/" action
+ (cons document arguments))
+ ;; Warn if we failed to locate or execute the
+ ;; method. Return nil in this case, so we remain in the
+ ;; current state.
+ (rudel-dispatch-error
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "%s: no method (%s: %s): `%s:%s'; arguments: %s"
+ (object-print this) (car error) (cdr error)
+ "rudel-obby/obby_document/" action arguments)
+ :debug)
+ nil)))
+ ;; If we did not find the document, warn.
+ (progn
+ (display-warning
+ '(rudel obby)
+ (format "Document not found: %s" doc-id)
+ :debug)
+ nil))))
+ )
+
+(provide 'rudel-obby-state)
+;;; rudel-obby-state.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby-util.el b/emacs.d/lisp/rudel/obby/rudel-obby-util.el
new file mode 100644
index 0000000..faefe70
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby-util.el
@@ -0,0 +1,314 @@
+;;; rudel-obby-util.el --- Miscellaneous functions for the Rudel obby backend
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, miscellaneous
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;;
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel)
+(require 'rudel-util)
+
+(require 'jupiter)
+
+
+;;; Class rudel-obby-socket-owner
+;;
+
+(defclass rudel-obby-socket-owner (rudel-socket-owner)
+ ((buffer :initarg :buffer
+ :type (or null string)
+ :initform nil
+ :documentation
+ "Stores message fragments until complete messages can
+be assembled."))
+ "This class adds functions for sending and receiving obby
+messages to the base class rudel-socket-owner.")
+
+(defmethod rudel-send ((this rudel-obby-socket-owner)
+ name &rest arguments)
+ "Send obby message NAME with arguments ARGUMENTS through the socket associated to THIS."
+ (with-slots (socket) this
+ (rudel-obby-send socket name arguments)))
+
+(defmethod rudel-receive ((this rudel-obby-socket-owner) data)
+ "Reassemble lines in DATA received on the socket associated with THIS and call message handler."
+ ;; Assemble fragmented lines.
+ (with-slots (buffer) this
+ (rudel-assemble-line-fragments data buffer))
+
+ ;; Process all available lines.
+ (rudel-loop-lines data line
+ ;; `rudel-message' has to dispatch message to an appropriate
+ ;; handler.
+ (let ((message (rudel-obby-parse-message line)))
+ (rudel-message this message)))
+ )
+
+(defgeneric rudel-message ((this rudel-obby-socket-owner) message)
+ "Called when a message arrives.
+Should be implemented in derived classes.")
+
+
+;;; Message serialization
+;;
+
+(defgeneric rudel-operation->message ((this jupiter-operation))
+ "Generate a list obby message components from THIS operation.")
+
+(defmethod rudel-operation->message ((this jupiter-insert))
+ "Serialize THIS insert operation."
+ (with-slots (from data) this
+ (list "ins" (format "%x" from) data)))
+
+(defmethod rudel-operation->message ((this jupiter-delete))
+ "Serialize THIS delete operation."
+ (with-slots (from length) this
+ (list "del" (format "%x" from) (format "%x" length))))
+
+(defmethod rudel-operation->message ((this jupiter-compound))
+ "Serialize THIS compound operation."
+ (with-slots (children) this
+ (apply #'append
+ (list "split" )
+ (mapcar #'rudel-operation->message children))))
+
+(defmethod rudel-operation->message ((this jupiter-nop))
+ "Serialize THIS nop operation."
+ (list "nop"))
+
+(defun rudel-message->operation (message local-revision remote-revision)
+ "Construct an operation object from MESSAGE and LOCAL-REVISION and REMOTE-REVISION.
+LOCAL-REVISION and REMOTE-REVISION are only used in the
+construction of the name of the new operation. "
+ (let ((type (car message)))
+ (cond
+
+ ;; Insert operation
+ ((string= type "ins")
+ (let ((position-numeric (string-to-number (nth 1 message) 16))
+ (data (nth 2 message)))
+ (jupiter-insert
+ (format "insert-%d-%d"
+ remote-revision local-revision)
+ :from position-numeric
+ :data data)))
+
+ ;; Delete operation
+ ((string= type "del")
+ (let ((position-numeric (string-to-number (nth 1 message) 16))
+ (length-numeric (string-to-number (nth 2 message) 16)))
+ (jupiter-delete
+ (format "delete-%d-%d"
+ remote-revision local-revision)
+ :from position-numeric
+ :to (+ position-numeric length-numeric))))
+
+ ;; Compound operation
+ ((string= type "split")
+ (let* ((rest (cdr message))
+ (offset (position-if
+ (lambda (item)
+ (member* item '("ins" "del" "nop")
+ :test #'string=))
+ rest
+ :start 1))
+ (first (subseq rest 0 offset))
+ (second (subseq rest offset)))
+ (jupiter-compound
+ (format "compound-%d-%d"
+ remote-revision local-revision)
+ :children
+ (list (rudel-message->operation
+ first local-revision remote-revision)
+ (rudel-message->operation
+ second local-revision remote-revision)))))
+
+ ;; No operation
+ ((string= type "nop")
+ (jupiter-nop
+ (format "nop-%d-%d"
+ remote-revision local-revision)))
+
+ ;; Unknown operation type
+ (t (error "Unknown document record type: `%s'" type))))
+ )
+
+
+;;; Character <-> byte position conversion
+;;
+
+(defgeneric rudel-obby-char->byte ((this jupiter-operation) buffer)
+ "Convert character positions and lengths in THIS to bytes.")
+
+(defmethod rudel-obby-char->byte ((this jupiter-insert) buffer)
+ "Convert character positions and lengths in THIS insert to bytes."
+ (with-slots (from) this
+ (with-current-buffer buffer
+ (setq from (- (position-bytes (+ from 1)) 1)))))
+
+(defmethod rudel-obby-char->byte ((this jupiter-delete) buffer)
+ "Convert character positions and lengths in THIS delete to bytes."
+ (with-slots (from to length) this
+ (let ((old-from (+ from 1))
+ (old-to (+ to 1)))
+ (with-current-buffer buffer
+ (destructuring-bind (change-from change-to string)
+ rudel-buffer-change-workaround-data
+ (setq from (- (position-bytes old-from) 1)
+ length (string-bytes
+ (substring string
+ (- old-from change-from)
+ (- old-to change-from))))))))
+ )
+
+(defmethod rudel-obby-char->byte ((this jupiter-compound) buffer)
+ "Convert character positions and lengths in THIS compound to bytes.."
+ (with-slots (children) this
+ (mapc
+ (lambda (child)
+ (rudel-obby-char->byte child buffer))
+ children))
+ )
+
+(defmethod rudel-obby-char->byte ((this jupiter-nop) buffer)
+ "Nothing to convert if THIS is a nop.")
+
+(defgeneric rudel-obby-byte->char ((this jupiter-operation) buffer)
+ "Convert byte positions and lengths in THIS to character positions.")
+
+(defmethod rudel-obby-byte->char ((this jupiter-insert) buffer)
+ "Convert byte positions and lengths in THIS insert to character positions."
+ (with-slots (from) this
+ (with-current-buffer buffer
+ (setq from (- (byte-to-position (+ from 1)) 1)))))
+
+(defmethod rudel-obby-byte->char ((this jupiter-delete) buffer)
+ "Convert byte positions and lengths in THIS delete to character positions."
+ (with-slots (from to length) this
+ (let ((old-from from)
+ (old-length length))
+ (with-current-buffer buffer
+ (setq from (- (byte-to-position (+ old-from 1)) 1)
+ to (- (byte-to-position (+ old-from old-length 1)) 1)))))
+ )
+
+(defmethod rudel-obby-byte->char ((this jupiter-compound) buffer)
+ "Convert byte positions and lengths in THIS compound to character positions."
+ (with-slots (children) this
+ (mapc
+ (lambda (child)
+ (rudel-obby-byte->char child buffer))
+ children))
+ )
+
+(defmethod rudel-obby-byte->char ((this jupiter-nop) buffer)
+ "Nothing to convert if THIS is a nop.")
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-obby-dispatch (object name arguments &optional prefix)
+ "Call method starting with PREFIX and ending in NAME of OBJECT with ARGUMENTS.
+When PREFIX is not specified, \"rudel-obby/\" is used."
+ ;; Default prefix.
+ (unless prefix
+ (setq prefix "rudel-obby/"))
+
+ ;; Construct a matching symbol.
+ (let ((method (intern-soft (concat prefix name))))
+ ;; If we found a suitable method, run it; Otherwise warn and do
+ ;; nothing.
+ (unless (and method
+ (condition-case error
+ ;; Try to call METHOD. If successful, always
+ ;; return t.
+ (progn
+ (apply method object arguments)
+ t)
+ ;; Warn only when the condition is
+ ;; 'no-method-definition' and refers to METHOD,
+ ;; otherwise continue unwinding.
+ (no-method-definition
+ (if (eq method (cadr error))
+ nil
+ (signal (car error) (cdr error))))))
+ (display-warning
+ '(rudel obby)
+ (format "%s: in context `%s': no method: `%s'; arguments: %s"
+ (object-name-string object) prefix name arguments)
+ :debug)))
+ )
+
+(defmacro with-parsed-arguments (specs &rest forms)
+ "Execute FORMS with variable bindings according to SPECS.
+SPECS is structured as follows:
+SPECS ::= (BINDING*)
+BINDING ::= (VAR TYPE)
+VAR is a symbol and TYPE is one of number, color, document-id and
+coding-system."
+ (declare (indent 1)
+ (debug (listp &rest form)))
+ (let ((bindings
+ (mapcar
+ (lambda (spec)
+ (destructuring-bind (var type) spec
+ (list var
+ (case type
+ ;; Number
+ (number
+ `(string-to-number ,var 16))
+ ;; Color
+ (color
+ `(rudel-obby-parse-color ,var))
+ ;; Document Id
+ (document-id
+ `(mapcar
+ (lambda (string)
+ (string-to-number string 16))
+ (split-string ,var " " t)))
+ ;; Coding System
+ (coding-system
+ `(rudel-get-coding-system (downcase ,var)))))))
+ specs)))
+ `(let (,@bindings)
+ ,@forms))
+ )
+
+(provide 'rudel-obby-util)
+;;; rudel-obby-util.el ends here
diff --git a/emacs.d/lisp/rudel/obby/rudel-obby.el b/emacs.d/lisp/rudel/obby/rudel-obby.el
new file mode 100644
index 0000000..a09c0d3
--- /dev/null
+++ b/emacs.d/lisp/rudel/obby/rudel-obby.el
@@ -0,0 +1,488 @@
+;;; rudel-obby.el --- An obby backend for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, obby, backend, implementation
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel protocol backend, which implements the
+;; obby protocol (used by the Gobby collaborative editor until version
+;; 0.5).
+
+
+;;; History:
+;;
+;; 0.2 - Refactored client and server to employ state machine.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel)
+(require 'rudel-backend)
+(require 'rudel-protocol)
+(require 'rudel-util)
+(require 'rudel-icons)
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Constants
+;;
+
+(defconst rudel-obby-version '(0 2)
+ "Version of the obby backend for Rudel.")
+
+(defconst rudel-obby-protocol-version 8
+ "Version of the obby protocol this library understands.")
+
+(defvar rudel-obby-long-message-threshold 32768
+ "Threshold for message size, above which messages are sent in
+multiple chunks.")
+
+(defvar rudel-obby-long-message-chunk-size 16384
+ "Chunk size used, when chunking long messages.")
+
+
+;;; Class rudel-obby-backend
+;;
+
+;;;###autoload
+(defclass rudel-obby-backend (rudel-protocol-backend)
+ ((capabilities :initform '(join host
+ change-color
+ track-subscriptions)))
+ "Main class of the Rudel obby backend. Creates obby client
+connections and creates obby servers.")
+
+(defmethod initialize-instance ((this rudel-obby-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-obby-version))
+
+(defmethod rudel-ask-connect-info ((this rudel-obby-backend) &optional info)
+ "Ask user for the information required to connect to an obby server."
+ ;; Read server host and port.
+ (let ((host (or (and info (plist-get info :host))
+ (read-string "Server: ")))
+ (port (or (and info (plist-get info :port))
+ (read-number "Port: " 6522)))
+ ;; Read desired username and color
+ (username (or (and info (plist-get info :username))
+ (read-string "Username: " user-login-name)))
+ (color (or (and info (plist-get info :color))
+ (read-color "Color: " t)))
+ (encryption (if (and info (member :encryption info))
+ (plist-get info :encryption)
+ (y-or-n-p "Use encryption? ")))
+ (global-password (if (and info (member :global-password info))
+ (plist-get info :global-password)
+ (read-string "Global password: " "")))
+ (user-password (if (and info (member :user-password info))
+ (plist-get info :user-password)
+ (read-string "User password: " ""))))
+ (append (list :host host
+ :port port
+ :username username
+ :color color
+ :encryption encryption
+ :global-password (unless (string= global-password "")
+ global-password)
+ :user-password (unless (string= user-password "")
+ user-password))
+ info))
+ )
+
+(defmethod rudel-connect ((this rudel-obby-backend) info)
+ "Connect to an obby server using the information INFO.
+Return the connection object."
+ ;; Before we start, load the client functionality.
+ (require 'rudel-obby-client)
+
+ ;; Create the network process
+ (let* ((session (plist-get info :session))
+ (host (plist-get info :host))
+ (port (plist-get info :port))
+ (encryption (plist-get info :encryption))
+ ;; Create the network process
+ (socket (funcall
+ (if encryption
+ (progn
+ (require 'rudel-tls)
+ #'rudel-tls-make-process)
+ #'make-network-process)
+ :name host
+ :host host
+ :service port
+ ;; Install connection filter to redirect data to
+ ;; the connection object
+ :filter #'rudel-filter-dispatch
+ ;; Install connection sentinel to redirect state
+ ;; changes to the connection object
+ :sentinel #'rudel-sentinel-dispatch
+ ;; Do not start receiving immediately since the
+ ;; filter function is not yet setup properly.
+ :stop t))
+ (connection (rudel-obby-connection
+ host
+ :session session
+ :socket socket
+ :info info)))
+
+ ;; Now start receiving and wait until the basic session setup is
+ ;; complete.
+ (continue-process socket)
+
+ ;; Wait for the connection to reach one of the states idle,
+ ;; join-failed and they-finalized.
+ (condition-case error
+ (lexical-let ((reporter (make-progress-reporter "Joining ")))
+ (flet ((display-progress (state)
+ (cond
+ ;; For all states, just spin.
+ ((consp state)
+ (progress-reporter-force-update
+ reporter nil (format "Joining (%s)" (car state))))
+
+ ;; Done
+ (t
+ (progress-reporter-force-update reporter nil "Joining ")
+ (progress-reporter-done reporter)))))
+
+ (rudel-state-wait connection
+ '(idle) '(join-failed they-finalized)
+ #'display-progress)))
+
+ (rudel-entered-error-state
+ (destructuring-bind (symbol . state) (cdr error)
+ (if (eq (rudel-find-state connection 'join-failed) state)
+ (with-slots (error-symbol error-data) state
+ (signal 'rudel-join-error
+ (append (list error-symbol) error-data)))
+ (signal 'rudel-join-error nil)))))
+
+ ;; The connection is now usable; return it.
+ connection)
+ )
+
+(defmethod rudel-ask-host-info ((this rudel-obby-backend))
+ "Ask user for information required to host an obby session."
+ (let ((port (read-number "Port: " 6522)))
+ (list :port port)))
+
+(defmethod rudel-host ((this rudel-obby-backend) info)
+ "Host an obby session using the information INFO.
+Return the created server."
+ ;; Before we start, we load the server functionality.
+ (require 'rudel-obby-server)
+
+ ;; Create the network process.
+ (let* ((port (plist-get info :port))
+ ;; Make a server socket
+ (socket (make-network-process
+ :name "obby-server"
+ :host "0.0.0.0"
+ :service port
+ :server t
+ :filter #'rudel-filter-dispatch
+ :sentinel #'rudel-sentinel-dispatch
+ ;;
+ :log
+ (lambda (server-process client-process message)
+ (let ((server (rudel-process-object server-process)))
+ (rudel-add-client server client-process)))))
+ ;; Construct server object.
+ (server (rudel-obby-server "obby-server"
+ :backend this
+ :socket socket)))
+
+ ;; Return the constructed server.
+ server)
+ )
+
+(defmethod rudel-make-document ((this rudel-obby-backend)
+ name session)
+ "Make a new document in SESSION named NAME.
+Return the new document."
+ ;; Find an unused document id and create a document with that id.
+ (let ((id (rudel-available-document-id this session)))
+ (with-slots (user-id) (oref session :self)
+ (rudel-obby-document name
+ :session session
+ :id id
+ :owner-id user-id
+ :suffix 1)))
+ )
+
+(defmethod rudel-available-document-id ((this rudel-obby-backend)
+ session)
+ "Return a document id, which is not in use in SESSION."
+ ;; Look through some candidates until an unused id is hit.
+ (let* ((used-ids (with-slots (documents) session
+ (mapcar 'rudel-id documents)))
+ (test-ids (number-sequence 0 (length used-ids))))
+ (car (sort (set-difference test-ids used-ids) '<)))
+ )
+
+
+;;; Class rudel-obby-user
+;;
+
+(defclass rudel-obby-user (rudel-user)
+ ((client-id :initarg :client-id
+ :type (or null integer) ;; We allow nil instead of making
+ :accessor rudel-client-id ;; the slot unbound, to be able to
+ :initform nil ;; search with test `rudel-client-id
+ :documentation ;; without headaches
+ "Id of the client connection, which the user used to log in.
+The value is an integer, if the user is connected, and nil
+otherwise.")
+ (user-id :initarg :user-id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "")
+ (connected :initarg :connected
+ :type boolean
+ :accessor rudel-connected
+ :documentation
+ "")
+ (encryption :initarg :encryption ;; TODO maybe we should use unbound when the user is not connected
+ :type boolean
+ :documentation
+ ""))
+ "Class rudel-obby-user ")
+
+(defmethod eieio-speedbar-description ((this rudel-obby-user))
+ "Provide a speedbar description for THIS."
+ (let ((connected (oref this :connected))
+ (encryption (if (slot-boundp this :encryption)
+ (oref this :encryption)
+ nil)))
+ (format "User %s (%s, %s)" (object-name-string this)
+ (if connected "Online" "Offline")
+ (if encryption "Encryption" "Plain")))
+ )
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-obby-user))
+ "Return a string to use as a speedbar button for THIS."
+ (rudel-display-string this))
+
+(defmethod rudel-display-string ((this rudel-obby-user)
+ &optional use-images align)
+ "Return a textual representation of THIS for user interface stuff."
+ (with-slots (connected color) this
+ (let ((encryption (and (slot-boundp this :encryption)
+ (oref this :encryption)))
+ (name-string (call-next-method)))
+ (concat
+ ;; Name bit
+ (cond
+ ((numberp align) (format (format "%-%ds" align) name-string))
+ ((eq align t) (format "%-12s" name-string))
+ (t name-string))
+
+ ;; Connection status bit
+ (apply
+ #'propertize
+ (if connected "c" "-")
+ 'help-echo (format (if connected
+ "%s is connected"
+ "%s is not connected")
+ name-string)
+ 'face (list :background color)
+ (when use-images
+ (list 'display (if connected
+ rudel-icon-connected
+ rudel-icon-disconnected))))
+
+ ;; Encryption bit
+ (apply
+ #'propertize
+ (if encryption "e" "-")
+ 'help-echo (format (if encryption
+ "%s's connection is encrypted"
+ "%s's connection is not encrypted")
+ name-string)
+ 'face (list :background color)
+ (when use-images
+ (list 'display (if encryption
+ rudel-icon-encrypted
+ rudel-icon-plaintext)))))))
+ )
+
+
+;;; Class rudel-obby-document
+;;
+
+(defclass rudel-obby-document (rudel-document)
+ ((id :initarg :id
+ :type integer
+ :accessor rudel-id
+ :documentation
+ "The id of this document.
+The id has to be unique only with respect to the other documents
+owned by the owner.")
+ (owner-id :initarg :owner-id
+ :type integer
+ :documentation
+ "")
+ (suffix :initarg :suffix
+ :type integer
+ :documentation
+ "A counter used to distinguish identically named
+documents."))
+ "Objects of the class rudel-obby-document represent shared
+documents in obby sessions.")
+
+(defmethod rudel-both-ids ((this rudel-obby-document))
+ "Return a list consisting of document and owner id of THIS document."
+ (with-slots ((doc-id :id) owner-id) this
+ (list owner-id doc-id)))
+
+(defmethod rudel-unique-name ((this rudel-obby-document))
+ "Generate a unique name for THIS based on the name and the suffix."
+ (with-slots (suffix) this
+ (concat (when (next-method-p)
+ (call-next-method))
+ (when (> suffix 1)
+ (format "<%d>" suffix))))
+ )
+
+(defmethod eieio-speedbar-description ((this rudel-obby-document))
+ "Construct a description for from the name of document object THIS."
+ (format "Document %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-obby-document))
+ "Return a string to use as a speedbar button for OBJECT."
+ (with-slots (subscribed) this
+ (format "%-12s %s" (object-name-string this)
+ (if subscribed "s" "-")))
+ )
+
+
+;;; Obby message functions
+;;
+
+(defun rudel-obby-replace-in-string (string replacements)
+ "Replace elements of REPLACEMENTS in STRING.
+REPLACEMENTS is a list of conses whose car is the pattern and
+whose cdr is the replacement for the pattern."
+ (let ((result string))
+ (dolist (replacement replacements)
+ (let ((from (car replacement))
+ (to (cdr replacement)))
+ (setq result (replace-regexp-in-string
+ from to result nil t))))
+ result)
+ )
+
+(defun rudel-obby-escape-string (string)
+ "Replace meta characters in STRING with their escape sequences."
+ (rudel-obby-replace-in-string
+ string
+ '(("\\\\" . "\\b") ("\n" . "\\n") (":" . "\\d")))
+ )
+
+(defun rudel-obby-unescape-string (string)
+ "Replace escaped versions of obby meta characters in STRING with the actual meta characters."
+ (rudel-obby-replace-in-string
+ string
+ '(("\\\\n" . "\n") ("\\\\d" . ":") ("\\\\b" . "\\")))
+ )
+
+(defun rudel-obby-parse-color (color)
+ "Parse the obby color string COLOR into an Emacs color."
+ (let* ((color-numeric (string-to-number color 16))
+ (color-string (format "#%04X%04X%04X"
+ (lsh (logand #xff0000 color-numeric) -08)
+ (lsh (logand #x00ff00 color-numeric) -00)
+ (lsh (logand #x0000ff color-numeric) 08))))
+ color-string)
+ )
+
+(defun rudel-obby-format-color (color)
+ "Format the Emacs color COLOR as obby color string."
+ (multiple-value-bind (red green blue) (color-values color)
+ (format "%02x%02x%02x" (lsh red -8) (lsh green -8) (lsh blue -8))))
+
+(defun rudel-obby-assemble-message (name &rest arguments)
+ ""
+ (concat (mapconcat
+ (lambda (part)
+ (if (and (not (null part)) (stringp part))
+ (rudel-obby-escape-string part)
+ part))
+ (cons name arguments) ":")
+ "\n")
+ )
+
+(defun rudel-obby-parse-message (message)
+ "Split MESSAGE at `:' and unescape resulting parts.
+
+The terminating `\n' should be removed from MESSAGE before
+calling this function."
+ (mapcar #'rudel-obby-unescape-string (split-string message ":")))
+
+(defun rudel-obby-send (socket name arguments)
+ "Send an obby message NAME with arguments ARGUMENTS through SOCKET."
+ ;; First, assemble the message string.
+ (let ((message (apply #'rudel-obby-assemble-message
+ name arguments)))
+ (if (>= (length message) rudel-obby-long-message-threshold)
+ ;; For huge messages, chunk the message data and transmit the
+ ;; chunks
+ (let ((total (/ (length message)
+ rudel-obby-long-message-chunk-size))
+ (current 0)
+ (reporter (make-progress-reporter "Sending data " 0.0 1.0)))
+ (rudel-loop-chunks message chunk rudel-obby-long-message-chunk-size
+ (progress-reporter-update reporter (/ (float current) total))
+ (process-send-string socket chunk)
+ (incf current))
+ (progress-reporter-done reporter))
+ ;; Send small messages in one chunk
+ (process-send-string socket message)))
+ )
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'protocol)
+ 'obby 'rudel-obby-backend)
+
+;;;###autoload
+(eval-after-load 'rudel-zeroconf
+ '(rudel-zeroconf-register-service "_lobby._tcp" 'obby))
+
+(provide 'rudel-obby)
+;;; rudel-obby.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-backend.el b/emacs.d/lisp/rudel/rudel-backend.el
new file mode 100644
index 0000000..79cfef6
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-backend.el
@@ -0,0 +1,305 @@
+;;; rudel-backend.el --- A generic backend management mechanism for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, factory
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a generic mechanism that handles registration,
+;; query and instantiation of Rudel backends for any number of
+;; functional categories.
+;;
+;; The class and collaboration design is as follows: for each
+;; category, which is identified by a symbol, there is a factory
+;; object (an instance of `rudel-backend-factory') that is responsible
+;; for creating backend objects of the category. Examples of
+;; categories are 'transport', 'protocol' and 'session-initiation'.
+;; In addition to creating backend object, factories also allow
+;; querying backends based on desired capabilities and load backend
+;; implementations only when required.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+
+;;; Class rudel-backend
+;;
+
+(defclass rudel-backend ()
+ ((version :initarg :version
+ :type list
+ :documentation
+ "A list of the form (MAJOR MINOR [MICRO
+WHATEVER*]) describing the version of the backend.")
+ (capabilities :initarg :capabilities
+ :type list
+ :initform nil
+ :documentation
+ "A list of symbols, or lists whose car is a
+symbol, that each describe one capability of the backend."))
+ "Base class for backend classes."
+ :abstract t)
+
+(defmethod rudel-capable-of-p ((this rudel-backend) capability)
+ "Return t if the backend THIS is capable of CAPABILITY."
+ (with-slots (capabilities) this
+ (member capability capabilities)))
+
+
+;;; Class rudel-backend-factory
+;;
+
+(defclass rudel-backend-factory ()
+ ((backends :initarg :backends
+ :type hash-table
+ :documentation
+ "Mapping of symbolic names to classes (prior to
+instantiation) or objects (after instantiation) for all backends
+known to the factory object.")
+ (factories :type hash-table
+ :allocation :class
+ :documentation
+ "Mapping of backend categories to responsible
+factory objects."))
+ "Factory class that holds an object for each known backend
+category. Objects manage backend implementation for one backend
+category each.")
+(oset-default rudel-backend-factory factories
+ (make-hash-table :test #'eq))
+
+(defmethod initialize-instance ((this rudel-backend-factory) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+ (oset this :backends (make-hash-table :test #'eq)))
+
+;;;###autoload
+(defmethod rudel-get-factory :static ((this rudel-backend-factory)
+ category)
+ "Return the factory responsible for CATEGORY.
+If there is no responsible factory, create one and return it."
+ (with-slots (factories) this
+ (or (gethash category factories)
+ (puthash category (rudel-backend-factory category) factories)))
+ )
+
+;;;###autoload
+(defmethod rudel-add-backend ((this rudel-backend-factory)
+ name class &optional replace)
+ "Add factory class CLASS with name NAME to THIS.
+if REPLACE is non-nil, replace a registered implementation of the
+same name."
+ (with-slots (backends) this
+ (when (or (not (gethash name backends))
+ replace)
+ (puthash name class backends))))
+
+(defmethod rudel-get-backend ((this rudel-backend-factory) name)
+ "Return backend object for name NAME or nil if there is none.
+The returned backend is of the form (NAME . OBJECT).
+
+Backends are loaded, if necessary."
+ ;; Load all available backends
+ (rudel-load-backends this)
+
+ ;; Find the backend and return it.
+ (with-slots (backends) this
+ (let ((backend (gethash name backends)))
+ (when backend
+ (cons name backend))))
+ )
+
+(defmethod rudel-all-backends ((this rudel-backend-factory))
+ "Return a list of all backends registered with THIS.
+Each list element is of the form (NAME . CLASS-OR-OBJECT)."
+ (let ((backend-list))
+ (with-slots (backends) this
+ (maphash (lambda (name class)
+ (push (cons name class) backend-list))
+ backends))
+ backend-list)
+ )
+
+(defmethod rudel-suitable-backends ((this rudel-backend-factory) predicate)
+ "Return a list of backends which satisfy PREDICATE.
+Each list element is of the form (NAME . OBJECT).
+Backends are loaded, if necessary."
+ ;; Load all available backends
+ (rudel-load-backends this)
+
+ ;; Retrieve and return all backends, possibly filtering the list
+ ;; using PREDICATE.
+ (if predicate
+ (remove-if-not
+ (lambda (cell)
+ (and (object-p (cdr cell))
+ (funcall predicate (cdr cell))))
+ (rudel-all-backends this))
+ (rudel-all-backends this))
+ )
+
+(defmethod rudel-load-backends ((this rudel-backend-factory))
+ "Load backends in THIS factory if necessary.
+Loading errors are not reported explicitly, but can be detected
+by checking for backends that still are classes rather than
+objects."
+ ;; Map lambda that loads unloaded backends over all backends. Store
+ ;; objects back after loading.
+ (with-slots (backends) this
+ (maphash
+ (lambda (name class)
+ (unless (object-p class)
+ (condition-case error
+ (puthash name (make-instance
+ class (symbol-name name)) backends)
+ (error (display-warning
+ '(rudel backend)
+ (format "Could not load backend `%s': %s"
+ name
+ (error-message-string error))
+ :warning)))))
+ backends))
+ )
+
+
+;;; High-level frontend functions
+;;
+
+(defsubst rudel-backend-cons-p (cell)
+ "Check whether CELL is a cons of a backend name and object."
+ (and (consp cell)
+ (symbolp (car cell))
+ (object-p (cdr cell))))
+
+;;;###autoload
+(defun rudel-backend-get (category name)
+ "A shortcut for getting backend NAME of category CATEGORY.
+The returned backend is of the form (NAME . OBJECT)."
+ (rudel-get-backend (rudel-backend-get-factory category) name))
+
+;;;###autoload
+(defun rudel-backend-get-factory (category)
+ "A shortcut for getting the factory object for CATEGORY."
+ (rudel-get-factory rudel-backend-factory category))
+
+(defun rudel-backend-suitable-backends (category predicate)
+ "Return backends from category CATEGORY that satisfy PREDICATE.
+Each list element is of the form (NAME . OBJECT)."
+ (rudel-suitable-backends
+ (rudel-backend-get-factory category)
+ predicate))
+
+(defun rudel-backend-choose (category &optional predicate)
+ "Choose a backend from CATEGORY satisfying PREDICATE automatically or by asking the user.
+The returned backend is of the form (NAME . CLASS-OR-OBJECT)."
+ (let ((backends (rudel-backend-suitable-backends
+ category predicate)))
+ (unless backends
+ (error "No backends available"))
+
+ (if (= (length backends) 1)
+ ;; If there is only one backend, we can choose that one right
+ ;; away displaying a message to avoid confusing the user.
+ (let ((backend (nth 0 backends)))
+ (message "Using backend `%s'" (symbol-name (car backend)))
+ (sit-for 0.5)
+ backend)
+
+ ;; When we have more than one backend, we have to ask the user,
+ ;; which one she wants.
+ (require 'rudel-interactive)
+ (rudel-read-backend backends nil 'object)))
+ )
+
+
+;;; User interaction functions
+;;
+
+(defun rudel-backend-dump (&optional load)
+ "Create display information about backends in a buffer.
+If LOAD is non-nil, load all backends before display. This makes
+available information available for the backends"
+ (interactive "p")
+ (save-excursion
+ ;; Setup a new buffer.
+ (set-buffer (get-buffer-create "*Rudel Backends*"))
+ (erase-buffer)
+ (set-window-buffer nil (current-buffer))
+ (maphash
+ (lambda (category factory)
+ ;; Load backends if requested.
+ (unless (zerop load)
+ (rudel-load-backends factory))
+
+ ;; Insert header for this category.
+ (insert (propertize
+ (format "Category %s\n" category)
+ 'face 'bold))
+ (insert (apply #'format
+ " %-20s %-6s %-7s %s\n"
+ (mapcar
+ (lambda (header)
+ (propertize header 'face 'italic))
+ '("name" "loaded" "version" "capabilities"))))
+
+ ;; Insert all backends provided by this factory.
+ (dolist (backend (rudel-all-backends factory))
+ (insert (format " %-20s %-6s %-7s (%s)\n"
+ (propertize
+ (symbol-name (car backend))
+ 'face 'font-lock-type-face)
+ (propertize
+ (prin1-to-string (object-p (cdr backend)))
+ 'face 'font-lock-variable-name-face)
+ (propertize
+ (if (object-p (cdr backend))
+ (mapconcat #'prin1-to-string
+ (oref (cdr backend) :version)
+ ".")
+ "?")
+ 'face 'font-lock-constant-face)
+ (propertize
+ (if (object-p (cdr backend))
+ (mapconcat #'prin1-to-string
+ (oref (cdr backend) :capabilities)
+ " ")
+ "?")
+ 'face 'font-lock-constant-face))))
+
+ ;; One empty line between backend categories.
+ (insert "\n"))
+ (oref rudel-backend-factory factories)))
+ )
+
+(provide 'rudel-backend)
+;;; rudel-backend.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-chat.el b/emacs.d/lisp/rudel/rudel-chat.el
new file mode 100644
index 0000000..c7e992f
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-chat.el
@@ -0,0 +1,103 @@
+;;; rudel-chat.el --- Handling of chat messages
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, chat, message
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains some functions that deal with incoming chat
+;; messages. Backends that support receiving chat message should
+;; dispatch them using `rudel-chat-dispatch-message'. Chat messages
+;; will be processed in a customizable way from there.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+
+;;; Customization
+;;
+
+(defcustom rudel-chat-handler-function #'rudel-chat-handle-buffer
+ "A function that is called when chat messages arrive."
+ :group 'rudel
+ :type '(choice (const :tag "Display messages in the echo area"
+ rudel-chat-handle-message)
+ (const :tag "Log messages into a buffer"
+ rudel-chat-handle-buffer)
+ (function :tag "Other function"))
+ )
+
+
+;;; Variables and constants
+;;
+
+(defconst rudel-chat-buffer-name "*rudel-chat-log*"
+ "Name of the buffer into which received chat message should be
+inserted.")
+
+
+;;; Interface functions
+;;
+
+(defun rudel-chat-dispatch-message (sender message)
+ "Dispatch SENDER and MESSAGE to customizable handler function."
+ (funcall rudel-chat-handler-function sender message))
+
+
+;;; Handler functions
+;;
+
+(defun rudel-chat-handle-message (sender text)
+ "Display SENDER and MESSAGE in the echo area."
+ (message "%s says: %s"
+ (rudel-chat-format-sender sender)
+ text))
+
+(defun rudel-chat-handle-buffer (sender text)
+ "Insert SENDER and MESSAGE in a buffer."
+ (let ((buffer (or (get-buffer rudel-chat-buffer-name)
+ (pop-to-buffer rudel-chat-buffer-name))))
+ (with-current-buffer buffer
+ (goto-char (point-min))
+ (insert (format "%s: %s\n"
+ (rudel-chat-format-sender sender)
+ text))))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-chat-format-sender (user)
+ "Format USER handling nil values."
+ (if user
+ (object-name-string user)
+ "<unknown sender>"))
+
+(provide 'rudel-chat)
+;;; rudel-chat.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-compat.el b/emacs.d/lisp/rudel/rudel-compat.el
new file mode 100644
index 0000000..630496c
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-compat.el
@@ -0,0 +1,158 @@
+;;; rudel-compat.el --- Compatibility code for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;; Copyright (C) 2009 Phil Hagelberg
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Phil Hagelberg <phil@enigma>
+;; Keywords: rudel, compatibility
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains compatibility code required to make Rudel work
+;; with different versions of Emacs.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(unless (fboundp 'read-color)
+ (defun read-color (prompt &rest ignored)
+ "Poor man's read color without completion.
+You have to take care to only enter valid color names."
+ (read-string prompt)))
+
+
+;;; Spinner Progress Reporter
+;;
+
+(unless (functionp 'progress-reporter-spin)
+ (defvar progress-spinner-values ["-" "\\" "|" "/"])
+
+ (defsubst progress-reporter-update (reporter &optional value)
+ "Report progress of an operation in the echo area.
+
+The first parameter, REPORTER, should be the result of a call to
+`make-progress-reporter'. For reporters for which the max value
+is known, the second argument determines the actual progress of
+operation; it must be between MIN-VALUE and MAX-VALUE as passed
+to `make-progress-reporter'.
+
+However, if the change since last echo area update is too small
+or not enough time has passed, then do nothing (see
+`make-progress-reporter' for details).
+
+In this case, this function is very inexpensive, you need not
+care how often you call it."
+ (if (progress-reporter-spinner-p reporter)
+ (progress-reporter-spin reporter)
+ (when (>= value (car reporter))
+ (progress-reporter-do-update reporter value))))
+
+ (defun make-progress-reporter (message &optional min-value max-value
+ current-value min-change min-time)
+ "Return progress reporter object to be used with `progress-reporter-update'.
+
+MESSAGE is shown in the echo area. When at least 1% of operation
+is complete, the exact percentage will be appended to the
+MESSAGE. When you call `progress-reporter-done', word \"done\"
+is printed after the MESSAGE. You can change MESSAGE of an
+existing progress reporter with `progress-reporter-force-update'.
+
+If provided, MIN-VALUE and MAX-VALUE designate starting (0%
+complete) and final (100% complete) states of operation. The
+latter should be larger; if this is not the case, then simply
+negate all values. Optional CURRENT-VALUE specifies the progress
+by the moment you call this function. You should omit it or set
+it to nil in most cases since it defaults to MIN-VALUE.
+
+Optional MIN-CHANGE determines the minimal change in percents to
+report (default is 1%.) Optional MIN-TIME specifies the minimal
+time before echo area updates (default is 0.2 seconds.) If
+`float-time' function is not present, then time is not tracked
+at all. If OS is not capable of measuring fractions of seconds,
+then this parameter is effectively rounded up.
+
+If MIN-VALUE and MAX-VALUE are unknown, they may be omitted to
+return a \"pulsing\" progress reporter."
+ (unless min-time
+ (setq min-time 0.2))
+ (let ((reporter
+ (cons min-value ;; Force a call to `message' now
+ (vector (if (and (fboundp 'float-time)
+ (>= min-time 0.02))
+ (float-time) nil)
+ (or min-value 0)
+ max-value
+ message
+ (if min-change (max (min min-change 50) 1) 1)
+ min-time))))
+ (progress-reporter-update reporter (or current-value min-value))
+ reporter))
+
+ (defun progress-reporter-force-update (reporter &optional value new-message)
+ "Report progress of an operation in the echo area unconditionally.
+
+First two parameters are the same as for
+`progress-reporter-update'. Optional NEW-MESSAGE allows you to
+change the displayed message."
+ (let ((parameters (cdr reporter)))
+ (when new-message
+ (aset parameters 3 new-message))
+ (when (aref parameters 0)
+ (aset parameters 0 (float-time)))
+ (if (progress-reporter-spinner-p reporter)
+ (progress-reporter-spin reporter)
+ (progress-reporter-do-update reporter value))))
+
+ (defun progress-reporter-spinner-p (reporter)
+ "Return t if REPORTER has an unknown max value."
+ (null (aref (cdr reporter) 2)))
+
+ (defun progress-reporter-spin (reporter)
+ "Advance indicator of spinning REPORTER."
+ (let* ((parameters (cdr reporter))
+ (index (+ (aref parameters 1) 1)))
+ (aset parameters 1 index)
+ (let ((message-log-max nil)) ; No logging
+ (message "%s %s"
+ (aref progress-spinner-values (mod index 4))
+ (aref parameters 3))))))
+
+(unless (functionp 'string-match-p)
+ (defsubst string-match-p (regexp string &optional start)
+ "Same as `string-match' except this function does not change the match data"
+ (let ((inhibit-changing-match-data t))
+ (string-match regexp string start))))
+
+(defun rudel-get-coding-system (name)
+ (if (functionp 'coding-system-from-name)
+ (coding-system-from-name name)
+ ;; May need to try a little harder here for Emacs 22 depending on
+ ;; what kind of encoding names are given us.
+ (intern name)))
+
+(provide 'rudel-compat)
+;;; rudel-compat.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-compile.el b/emacs.d/lisp/rudel/rudel-compile.el
new file mode 100644
index 0000000..aeba765
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-compile.el
@@ -0,0 +1,46 @@
+;;; rudel-compile.el --- Byte-compile Rudel
+;;
+;; Copyright (C) 2009 Phil Hagelberg
+;;
+;; Author: Phil Hagelberg <phil@enigma>
+;; Keywords: Rudel, compile
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Press M-x eval-buffer to byte-compile Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(let ((rudel-dir (file-name-directory
+ (or (buffer-file-name) load-file-name))))
+ ;; Adjust load path for compilation.
+ (dolist (dir '("." "jupiter" "obby" "zeroconf"))
+ (let ((d (concat rudel-dir "/" dir)))
+ (add-to-list 'load-path d)))
+
+ ;; Byte compile everything.
+ (byte-recompile-directory rudel-dir 0))
diff --git a/emacs.d/lisp/rudel/rudel-debug.el b/emacs.d/lisp/rudel/rudel-debug.el
new file mode 100644
index 0000000..747bf68
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-debug.el
@@ -0,0 +1,215 @@
+;;; rudel-debug.el --- Debugging functions for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, debugging
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Debugging functions for Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'data-debug)
+(require 'eieio-datadebug)
+
+(require 'rudel-util)
+
+
+;;; Customization
+;;
+
+(defgroup rudel-debug nil
+ "Customization options related to Rudel's debugging functions."
+ :group 'rudel)
+
+(defface rudel-debug-sent-data-face
+ '((default (:background "orange")))
+ "Face used for sent data."
+ :group 'rudel-debug)
+
+(defface rudel-debug-received-data-face
+ '((default (:background "light sky blue")))
+ "Face used for received (but not yet processed) data."
+ :group 'rudel-debug)
+
+(defface rudel-debug-received-processed-data-face
+ '((default (:background "DeepSkyBlue1")))
+ "Face used for received data after processing."
+ :group 'rudel-debug)
+
+(defface rudel-debug-state-face
+ '((default (:background "light gray")))
+ "Face used when indicating state changes."
+ :group 'rudel-debug)
+
+(defface rudel-debug-special-face
+ '((default (:background "light sea green")))
+ "Face used for additional information."
+ :group 'rudel-debug)
+
+(defvar rudel-debug-tag-faces
+ '((:sent . (rudel-debug-sent-data-face "< "))
+ (:received . (rudel-debug-received-data-face "> "))
+ (:received-processed . (rudel-debug-received-processed-data-face ">> "))
+ (:state . (rudel-debug-state-face "| "))
+ (:special . (rudel-debug-special-face "; ")))
+ "Associate tag to faces and prefixes.")
+
+
+;;; Data debug functions
+;;
+
+(defun rudel-adebug-session ()
+ "Analyze current session in data debug buffer."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-current-buffer (data-debug-new-buffer "RUDEL-SESSION")
+ (data-debug-insert-thing rudel-current-session "# " "")))
+
+(defun rudel-adebug-server (server)
+ "Analyze server in data debug buffer."
+ (interactive)
+
+ (with-current-buffer (data-debug-new-buffer "RUDEL-SERVER")
+ (data-debug-insert-thing server "# " "")))
+
+
+;;; Advice stuff
+;;
+
+(defadvice rudel-join-session (after rudel-debug last activate)
+ "Run data-debug inspection on newly created session objects."
+ (require 'rudel-debug)
+ (rudel-adebug-session))
+
+(defadvice rudel-host-session (after rudel-debug last activate)
+ "Run data-debug inspection on newly created server objects."
+ (require 'rudel-debug)
+ (rudel-adebug-server ad-return-value))
+
+
+;;; Network functions
+;;
+
+(defun rudel-suspend-session-socket ()
+ "Suspend the socket associated to the current session."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (connection) rudel-current-session
+ (with-slots (socket) connection
+ (stop-process socket))))
+
+(defun rudel-resume-session-socket ()
+ "Resume the socket associated to the current session."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (connection) rudel-current-session
+ (with-slots (socket) connection
+ (continue-process socket))))
+
+
+;;; Reset functions
+;;
+
+(defun rudel-kill-processes ()
+ "TODO"
+ (interactive)
+ (mapc #'delete-process (process-list)))
+
+(defun rudel-reset ()
+ "TODO"
+ (interactive)
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-buffer-document
+ (setq rudel-buffer-document nil))))
+ (rudel-kill-processes)
+ (setq rudel-current-session nil))
+
+
+;;; Socket debugging
+;;
+
+(defmethod rudel-state-change :before ((this rudel-socket-owner)
+ state message)
+ "Print STATE and MESSAGE to debug stream."
+ (with-slots (socket) this
+ (rudel-debug-stream-insert
+ (rudel-debug-stream-name socket)
+ :state
+ (format "connection state changed to %s: \"%s\""
+ (upcase (symbol-name state))
+ ;; MESSAGE ends with a newline; remove it
+ (substring message 0 -1))))
+ )
+
+
+;;; Utility functions
+;;
+
+(defun rudel-debug-stream-name (socket)
+ "Return debug stream name for SOCKET."
+ (process-name socket))
+
+(defun rudel-debug-stream-insert (stream tag data &optional object)
+ "Insert DATA and possibly OBJECT into stream using TAG as style."
+ (let* ((buffer-name (format "*%s stream*" stream))
+ (buffer (or (get-buffer buffer-name)
+ (data-debug-new-buffer buffer-name)))
+ (appearance (cdr (assoc tag rudel-debug-tag-faces)))
+ (face (when appearance
+ (or (nth 0 appearance)
+ 'default)))
+ (prefix (or (nth 1 appearance)
+ "")))
+ (save-excursion
+ (set-buffer buffer)
+ (goto-char 0)
+ (insert prefix
+ (propertize data 'face face)
+ (if (string= (substring data -1) "\n")
+ "" "\n"))
+ (when object
+ (data-debug-insert-thing object prefix ""))))
+ )
+
+(provide 'rudel-debug)
+;;; rudel-debug.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-errors.el b/emacs.d/lisp/rudel/rudel-errors.el
new file mode 100644
index 0000000..9811511
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-errors.el
@@ -0,0 +1,66 @@
+;;; rudel-errors.el --- Error data used in Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, errors, conditions
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; The following condition hierarchy is defined:
+;;
+;; error
+;; +- rudel-error
+;; +- rudel-join-error
+;; +- rudel-host-error
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+;; rudel-join-error
+
+(intern "rudel-join-error")
+
+(put 'rudel-join-error 'error-conditions
+ '(error
+ rudel-error rudel-join-error))
+
+(put 'rudel-join-error 'error-message
+ "Could not join session")
+
+;; rudel-host-error
+
+(intern "rudel-host-error")
+
+(put 'rudel-host-error 'error-conditions
+ '(error
+ rudel-error rudel-host-error))
+
+(put 'rudel-host-error 'error-message
+ "Could not host session")
+
+(provide 'rudel-errors)
+;;; rudel-errors.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-hooks.el b/emacs.d/lisp/rudel/rudel-hooks.el
new file mode 100644
index 0000000..0cc9a3e
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-hooks.el
@@ -0,0 +1,252 @@
+;;; rudel-hooks.el --- Hooks for Rudel events
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, hook
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains all global hooks (as opposed to hooks provided
+;; by individual objects) provided by Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+
+;;; Hook variables
+;;
+
+(defvar rudel-session-start-hook nil
+ "This hook is run when a new session is started.
+The only argument is the session object.")
+
+(defvar rudel-session-end-hook nil
+ "This hook is run when a session ends.
+The only argument is the session object.")
+
+(defvar rudel-session-add-user-hook nil
+ "This hook is run when a user is added to a session.
+The arguments are the session and the user.")
+
+(defvar rudel-session-remove-user-hook nil
+ "This hook is run when a user is removed from a session.
+The arguments are the session and the user.")
+
+(defvar rudel-session-add-document-hook nil
+ "This hook is run when a document is added to a session.
+The arguments are the session and the document.")
+
+(defvar rudel-session-remove-document-hook nil
+ "This hook is run when a document is removed from a session.
+The arguments are the session and the document.")
+
+
+(defvar rudel-user-change-hook nil
+ "This hooks is run when a user object changes.
+The only argument is the user object.")
+
+
+(defvar rudel-document-attach-hook nil
+ "This hook is run when a document is attached to a buffer.
+The arguments are the document and the buffer.")
+
+(defvar rudel-document-detach-hook nil
+ "This hook is run when document is detached from its buffer.
+The arguments are the document and the buffer.")
+
+
+;;; Handlers
+;;
+
+(defun rudel-hooks--session-start (session)
+ "Watch SESSION for added/removed users and documents."
+ ;; Install handlers for the hooks of the session.
+ (with-slots (users documents) session
+
+ ;; Watch for session end.
+ (object-add-hook session 'end-hook
+ #'rudel-hooks--session-end)
+
+ ;; Watch all users in the session.
+ (dolist (user users)
+ (rudel-hooks--session-add-user session user))
+
+ ;; Watch session for added/removed users.
+ (object-add-hook
+ session 'add-user-hook
+ #'rudel-hooks--session-add-user)
+ (object-add-hook
+ session 'remove-user-hook
+ #'rudel-hooks--session-remove-user)
+
+ ;; Watch all documents in the session.
+ (dolist (document documents)
+ (rudel-hooks--session-add-document session document))
+
+ ;; Watch session for added/removed documents.
+ (object-add-hook
+ session 'add-document-hook
+ #'rudel-hooks--session-add-document)
+ (object-add-hook
+ session 'remove-document-hook
+ #'rudel-hooks--session-remove-document))
+ )
+
+(defun rudel-hooks--session-end (session)
+ "Stop watching SESSION for added/removed users and documents."
+ ;; Remove handlers from the session.
+ (with-slots (users documents) session
+
+ ;; Stop watching for session end.
+ (object-remove-hook session 'end-hook
+ #'rudel-hooks--session-end)
+
+ ;; Stop watching all users in the session.
+ (dolist (user users)
+ (rudel-hooks--session-remove-user session user))
+
+ ;; Stop watching session for added/removed users.
+ (object-remove-hook
+ session 'add-user-hook
+ #'rudel-hooks--session-add-user)
+ (object-remove-hook
+ session 'remove-user-hook
+ #'rudel-hooks--session-remove-user)
+
+ ;; Stop watching all documents in the session.
+ (dolist (document documents)
+ (rudel-hooks--session-remove-document session document))
+
+ ;; Stop watching session for added/removed documents.
+ (object-remove-hook
+ session 'add-document-hook
+ #'rudel-hooks--session-add-document)
+ (object-remove-hook
+ session 'remove-document-hook
+ #'rudel-hooks--session-remove-document))
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-end-hook session)
+ )
+
+(defun rudel-hooks--session-add-user (session user)
+ "Watch USER for changes and run `rudel-session-add-user-hook'."
+ ;; Watch USER.
+ (object-add-hook user 'change-hook #'rudel-hooks--user-change)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-add-user-hook session user))
+
+(defun rudel-hooks--session-remove-user (session user)
+ "Stop watching USER and run `rudel-session-remove-user-hook'"
+ ;; Stop watching USER.
+ (object-remove-hook user 'change-hook #'rudel-hooks--user-change)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-remove-user-hook
+ session user))
+
+(defun rudel-hooks--session-add-document (session document)
+ "Watch DOCUMENT and run `rudel-session-add-document-hook'."
+ ;; Watch document for attach/detach.
+ (object-add-hook document 'attach-hook
+ #'rudel-hooks--document-attach)
+ (object-add-hook document 'detach-hook
+ #'rudel-hooks--document-detach)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-add-document-hook
+ session document)
+ )
+
+(defun rudel-hooks--session-remove-document (session document)
+ "Stop watching DOCUMENT and run `rudel-session-remove-document-hook'."
+ ;; Stop watching DOCUMENT for attach/detach.
+ (object-remove-hook
+ document 'attach-hook #'rudel-hooks--document-attach)
+ (object-remove-hook
+ document 'detach-hook #'rudel-hooks--document-detach)
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-remove-document-hook
+ session document)
+ )
+
+
+(defun rudel-hooks--user-change (user)
+ "Run `rudel-user-change-hook' with argument USER."
+ (run-hook-with-args 'rudel-user-change-hook user))
+
+
+(defun rudel-hooks--document-attach (document buffer)
+ "Run `rudel-document-attach-hook' with arguments DOCUMENT and BUFFER."
+ (run-hook-with-args 'rudel-document-attach-hook
+ document buffer))
+
+(defun rudel-hooks--document-detach (document buffer)
+ "Run `rudel-document-detach-hook' with arguments DOCUMENT and BUFFER."
+ (run-hook-with-args 'rudel-document-detach-hook
+ document buffer))
+
+
+;;; Initialization
+;;
+
+(defun rudel-hooks--install-handlers ()
+ "Install handlers for session start/end."
+ ;; Install handlers for already started sessions.
+ (when (boundp 'rudel-current-session)
+ (mapc
+ #'rudel-hooks--session-start
+ (when rudel-current-session
+ (list rudel-current-session))))
+
+ ;; Watch for session start/end.
+ (add-hook 'rudel-session-start-hook
+ #'rudel-hooks--session-start)
+ )
+
+(defun rudel-hooks--uninstall-handlers ()
+ "Uninstall handlers for session start/end."
+ ;; Stop watching session start/end.
+ (remove-hook 'rudel-session-start-hook
+ #'rudel-hooks--session-start)
+
+ ;; Uninstall handlers for already started sessions.
+ (when (boundp 'rudel-current-session)
+ (mapc
+ #'rudel-hooks--session-end
+ (when rudel-current-session
+ (list rudel-current-session))))
+ )
+
+(rudel-hooks--install-handlers)
+
+(provide 'rudel-hooks)
+;;; rudel-hooks.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-icons.el b/emacs.d/lisp/rudel/rudel-icons.el
new file mode 100644
index 0000000..9bb35b5
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-icons.el
@@ -0,0 +1,90 @@
+;;; rudel-icons.el --- Icons used by Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, icons
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file loads all icons used in Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'image)
+
+
+;;; Image constants
+;;
+
+(defconst rudel-icons-image-formats '(svg png)
+ "Image formats to try (in that order) when loading Rudel icons.")
+
+(defconst rudel-icons-directory
+ (file-name-as-directory
+ (concat (file-name-directory
+ (locate-library "rudel-icons.el"))
+ "icons"))
+ "Directory that holds Rudel icon files.")
+
+
+;;; Helper macro
+;;
+
+(defmacro rudel-defimage (name &optional docstring)
+ "Load image from Rudel icon directory and define image named NAME.
+Optional argument DOCSTRING is the documentation string to
+associate with the image."
+ (declare (doc-string 2))
+ (let ((icon (intern (format "rudel-icon-%s" name)))
+ (specs (mapcar
+ (lambda (type)
+ `(:type ,type
+ :ascent center
+ :mask heuristic
+ :file ,(concat rudel-icons-directory
+ name "." (symbol-name type))))
+ rudel-icons-image-formats)))
+ `(defimage ,icon
+ (,@specs)
+ ,(or docstring
+ (format "%s icon." (capitalize name)))))
+ )
+
+
+;;; Image definitions
+;;
+
+(rudel-defimage "person")
+(rudel-defimage "document")
+(rudel-defimage "connected")
+(rudel-defimage "disconnected")
+(rudel-defimage "plaintext")
+(rudel-defimage "encrypted")
+
+(provide 'rudel-icons)
+;;; rudel-icons.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-interactive.el b/emacs.d/lisp/rudel/rudel-interactive.el
new file mode 100644
index 0000000..5dda752
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-interactive.el
@@ -0,0 +1,181 @@
+;;; rudel-interactive.el --- User interaction functions for Rudel.
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, user, interface, interaction
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Functions for user interactions commonly used in Rudel components.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Function for reading Rudel objects from the user.
+;;
+
+(defun rudel-read-backend (backends &optional prompt return)
+ "Read a backend name from BACKENDS and return that name or the actual backend depending on RETURN.
+If RETURN is 'object, return the backend object which is of the
+form (NAME . CLASS-OR-OBJECT); Otherwise return the name as
+string."
+ (unless prompt
+ (setq prompt "Backend: "))
+ (let* ((backend-names (mapcar (lambda (cell)
+ (symbol-name (car cell)))
+ backends))
+ (backend-name (completing-read prompt backend-names nil t)))
+ (cond
+ ((eq return 'object)
+ (assoc (intern backend-name) backends))
+ (t backend-name)))
+ )
+
+(defun rudel-read-session (sessions &optional prompt return)
+ "Read a session name from SESSIONS and return that name or the session info depending on RETURN.
+If PROMPT is non-nil use as prompt string.
+If RETURN is 'object, return the session object; Otherwise return
+the name as string."
+ (unless prompt
+ (setq prompt "Session: "))
+ ;; For presentation and identification of sessions, use the :name
+ ;; property.
+ (flet ((to-string (session)
+ (if (rudel-backend-cons-p session)
+ (symbol-name (car session))
+ (plist-get session :name))))
+ ;; Read a session by name, then return that name or the
+ ;; corresponding session info.
+ (let ((session-name (completing-read prompt
+ (mapcar #'to-string sessions)
+ nil t)))
+ (cond
+ ((eq return 'object)
+ (find session-name sessions
+ :key #'to-string :test #'string=))
+ (t session-name))))
+ )
+
+(defun rudel-read-user-name ()
+ "Read a username.
+The default is taken from `rudel-default-username'."
+ (read-string "Username: " rudel-default-username))
+
+(defun rudel-read-user-color ()
+ "Read a color."
+ (read-color "Color: " t))
+
+(defun rudel-read-user (&optional users prompt return)
+ "Read a user name from USERS and return that name or the actual user depending on RETURN.
+If USERS is nil, use the user list of `rudel-current-session'.
+If RETURN. is 'object, return the user object; Otherwise return
+the name as string."
+ ;; If no user list is provided, the user list of the current session
+ ;; is used.
+ (unless users
+ (if rudel-current-session
+ (setq users (oref rudel-current-session :users))
+ (error "No user list and no active Rudel session")))
+ (unless prompt
+ (setq prompt "User: "))
+ ;; Construct a list of user name, read a name with completion and
+ ;; return a user name of object.
+ (let* ((user-names (mapcar 'object-name-string users))
+ (user-name (completing-read prompt user-names nil t)))
+ (cond
+ ((eq return 'object)
+ (find user-name users
+ :test 'string= :key 'object-name-string))
+ (t user-name)))
+ )
+
+(defun rudel-read-document (&optional documents prompt return)
+ "Read a document name from DOCUMENTS and return that name or the actual document depending on RETURN.
+If RETURN. is 'object, return the backend object; Otherwise
+return the name as string."
+ (unless documents
+ (if rudel-current-session
+ (setq documents (oref rudel-current-session :documents))
+ (error "No document list and no active Rudel session")))
+ (unless documents
+ (error "No documents")) ; TODO error is a bit harsh
+ (unless prompt
+ (setq prompt "Document: "))
+
+ ;; Construct list of names, read one name and return that name or
+ ;; the named object.
+ (let* ((document-names (mapcar #'rudel-unique-name documents))
+ (document-name (completing-read prompt document-names nil t)))
+ (cond
+ ((eq return 'object)
+ (find document-name documents
+ :test #'string= :key #'rudel-unique-name))
+ (t document-name)))
+ )
+
+
+;;; Buffer allocation functions
+;;
+
+(defun rudel-allocate-buffer-clear-existing (name)
+ "When the requested buffer NAME exists, clear its contents and use it."
+ (let ((buffer (get-buffer name)))
+ (if buffer
+ (progn
+ ;; Ask the user whether it is OK to erase the contents of
+ ;; the buffer.
+ (unless (yes-or-no-p (format
+ "Buffer `%s' already exists; Erase contents? "
+ name))
+ (error "Buffer `%s' already exists" name)) ;; TODO throw or signal; not error
+ ;; When the buffer is attached to a different document, ask
+ ;; whether it is OK to detach the buffer.
+ (let ((document (rudel-buffer-document buffer)))
+ (unless (or (not document)
+ (yes-or-no-p (format
+ "Buffer `%s' is attached to the document `%s'; Detach? "
+ name
+ (rudel-unique-name document))))
+ (error "Buffer `%s' already attached to a document" name)))
+ ;; Delete buffer contents; maybe detach buffer first.
+ (when (rudel-buffer-has-document-p buffer)
+ (rudel-unpublish-buffer buffer))
+ (with-current-buffer buffer
+ (erase-buffer)))
+ (setq buffer (get-buffer-create name)))
+ buffer)
+ )
+
+(defun rudel-allocate-buffer-make-unique (name)
+ "When the requested buffer NAME exists, create another buffer."
+ (get-buffer-create (generate-new-buffer-name name)))
+
+(provide 'rudel-interactive)
+;;; rudel-interactive.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-loaddefs.el b/emacs.d/lisp/rudel/rudel-loaddefs.el
new file mode 100644
index 0000000..9de8708
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-loaddefs.el
@@ -0,0 +1,23 @@
+;;; rudel-loaddefs.el
+
+(autoload 'rudel-join-session "rudel" "Start a collaborative Rudel session" t)
+(autoload 'rudel-host-session "rudel" "Host a collaborative Rudel session" t)
+(autoload 'rudel-speedbar "rudel-speedbar"
+ "Show connected users and documents for the Rudel session in speedbar" t)
+(autoload 'global-rudel-minor-mode "rudel-mode"
+ "Bindings for rudel session-level commands" t)
+
+(global-set-key (kbd "C-c c j") 'rudel-join-session)
+
+(setq rudel-dir (file-name-directory (or (buffer-file-name) load-file-name)))
+
+(dolist (dir '("." "jupiter" "obby" "zeroconf"))
+ (add-to-list 'load-path (concat rudel-dir "/" dir)))
+
+(eval-after-load 'rudel
+ '(progn (global-rudel-minor-mode)
+ (require 'rudel-obby)
+ (when (require 'zeroconf nil t)
+ (require 'rudel-zeroconf))))
+
+(provide 'rudel-loaddefs) \ No newline at end of file
diff --git a/emacs.d/lisp/rudel/rudel-mode.el b/emacs.d/lisp/rudel/rudel-mode.el
new file mode 100644
index 0000000..182188a
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-mode.el
@@ -0,0 +1,621 @@
+;;; rudel-mode.el --- Global and buffer-local Rudel minor modes
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, mode
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the following global and buffer-local Rudel
+;; minor modes:
+;;
+;; + `rudel-header-subscriptions-minor-mode': Display subscribed users
+;; and their respective status in the header line
+;; + `rudel-mode-line-publish-state-minor-mode': Display publication
+;; state of buffers in their mode lines
+;; + `global-rudel-minor-mode': Installs a keymap and a Rudel menu
+
+
+;;; History:
+;;
+;; 0.4 - Display buffer publication state in mode line.
+;;
+;; 0.3 - Display subscriptions in header line.
+;;
+;; 0.2 - Use define-minor-mode.
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'easy-mmode)
+(require 'easymenu)
+
+(require 'rudel)
+(require 'rudel-hooks)
+
+
+;;; Customization Options
+;;
+
+(defcustom rudel-header-subscriptions-use-images t
+ "Use images when displaying subscribed users in header-line."
+ :group 'rudel
+ :type 'boolean
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-header-subscriptions--options-changed))))
+
+(defcustom rudel-header-subscriptions-separator " "
+ "String used to separate indicator strings of subscribed users."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-header-subscriptions--options-changed))))
+
+(defcustom rudel-mode-line-publish-state-unpublished-string "-"
+ "String used to indicate not published state in the mode line."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-mode-line-publish-state--options-changed))))
+
+(defcustom rudel-mode-line-publish-state-published-string "P"
+ "String used to indicate published state in the mode line."
+ :group 'rudel
+ :type 'string
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-mode)
+ (rudel-mode-line-publish-state--options-changed))))
+
+(dolist (v '(rudel-header-subscriptions-use-images
+ rudel-header-subscriptions-separator
+ rudel-mode-line-publish-state-unpublished-string
+ rudel-mode-line-publish-state-published-string))
+ (put v 'save-local-variable t))
+
+
+;;; Header line subscriptions helper functions
+;;
+
+(defun rudel-header-subscriptions--make-format (document)
+ "Return a Lisp object usable as `header-line-format' generated from DOCUMENT."
+ (with-slots (subscribed) document
+ (mapconcat
+ (lambda (user)
+ (rudel-display-string
+ user rudel-header-subscriptions-use-images))
+ subscribed rudel-header-subscriptions-separator)))
+
+(defun rudel-header-subscriptions--update-from-document (document)
+ "Update header-line of the buffer attached to DOCUMENT."
+ (with-slots (buffer) document
+ (when buffer
+ (with-current-buffer buffer
+ (setq header-line-format
+ (rudel-header-subscriptions--make-format document))
+ (force-mode-line-update)))))
+
+(defun rudel-header-subscriptions--update-from-buffer ()
+ "Update header-line of the current buffer from associated document."
+ (setq header-line-format
+ (when (rudel-buffer-document)
+ (rudel-header-subscriptions--make-format
+ (rudel-buffer-document))))
+ (force-mode-line-update))
+
+(defun rudel-header-subscriptions--options-changed ()
+ "Update headers in buffers that have header subscriptions mode enabled."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-header-subscriptions-minor-mode
+ (rudel-header-subscriptions--update-from-buffer)))))
+
+
+;;; Header line indication of users' status and activities
+;;
+
+(defun rudel-header-subscriptions--user-change (document user)
+ "Update header line after USER changed."
+ ;; Update the header line to reflect the changes to USER.
+ (rudel-header-subscriptions--update-from-document document))
+
+(defun rudel-header-subscriptions--add-user (document user)
+ "Start monitoring USER and update header line."
+ ;; Monitor USER.
+ (lexical-let ((document document))
+ (object-add-hook user 'change-hook
+ (lambda (user)
+ (rudel-header-subscriptions--user-change
+ document user))))
+
+ ;; Update the header line once to get the user added.
+ (rudel-header-subscriptions--update-from-document document)
+ )
+
+(defun rudel-header-subscriptions--remove-user (document user)
+ "Stop monitoring USER and update header line."
+ ;; TODO Stop monitoring USER.
+ ;; (object-remove-hook user 'change-hook
+
+ ;; Update the header line once to get the user removed.
+ (rudel-header-subscriptions--update-from-document document)
+ )
+
+;;;###autoload
+(define-minor-mode rudel-header-subscriptions-minor-mode
+ "Toggle Rudel header subscriptions minor mode.
+
+This mode displays users subscribed to the document associated
+with the buffer in the header-line. Depending on the kind of
+session, additional information like connection status,
+encryption or activity indication may be displayed with each
+user.
+
+If ARG is null, toggle Rudel header subscriptions mode.
+If ARG is a number greater than zero, turn on Rudel header
+subscriptions mode; otherwise, turn it off."
+ :init-value nil
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq rudel-header-subscriptions-minor-mode nil))
+
+ ;; Mode is being enabled and the buffer has an attached document.
+ ((and rudel-header-subscriptions-minor-mode
+ (rudel-buffer-document))
+ (let ((document (rudel-buffer-document)))
+
+ ;; Monitor all users that already are subscribed to the
+ ;; document.
+ (with-slots (subscribed) document
+ (dolist (user subscribed)
+ (rudel-header-subscriptions--add-user document user)))
+
+ ;; Monitor future (un)subscribe events.
+ (object-add-hook document 'subscribe-hook
+ #'rudel-header-subscriptions--add-user)
+ (object-add-hook document 'unsubscribe-hook
+ #'rudel-header-subscriptions--remove-user))
+
+ ;; Update header line.
+ (rudel-header-subscriptions--update-from-buffer))
+
+ ;; Mode is being disabled, but the buffer has an attached document.
+ ((and (not rudel-header-subscriptions-minor-mode)
+ (rudel-buffer-document))
+ (let ((document (rudel-buffer-document)))
+
+ ;; Stop monitoring all users that are subscribed to the
+ ;; document.
+ (with-slots (subscribed) document
+ (dolist (user subscribed)
+ (rudel-header-subscriptions--remove-user document user)))
+
+ ;; Stop monitoring (un)subscribe events.
+ (object-remove-hook document 'subscribe-hook
+ #'rudel-header-subscriptions--add-user)
+ (object-remove-hook document 'unsubscribe-hook
+ #'rudel-header-subscriptions--remove-user))
+
+ ;; Reset header line to default format.
+ (setq header-line-format default-header-line-format)
+ (force-mode-line-update)) ;; TODO remove all handlers
+
+ ;; No buffer document
+ (t
+ ;; Ensure the mode is disabled.
+ (setq rudel-header-subscriptions-minor-mode nil)
+
+ ;; Reset header line to default format.
+ (setq header-line-format default-header-line-format)
+ (force-mode-line-update)))
+ )
+
+
+;;; Global header subscriptions mode
+;;
+
+;; Tracking stuff for the global mode
+
+(defun rudel-header-subscriptions--attach (document buffer)
+ "Activate header subscriptions mode for BUFFER."
+ (with-current-buffer buffer
+ (rudel-header-subscriptions-minor-mode 1)))
+
+(defun rudel-header-subscriptions--detach (document buffer)
+ "Deactivate header subscriptions mode for BUFFER."
+ (with-current-buffer buffer
+ (rudel-header-subscriptions-minor-mode 0)))
+
+(defun rudel-header-subscriptions--add-document (session document)
+ "Watch DOCUMENT for attach/detach events."
+ ;; When document is attached to a buffer, turn the mode on.
+ (with-slots (buffer) document
+ (when buffer
+ (rudel-header-subscriptions--attach document buffer)))
+
+ ;; Watch document for attaching and detaching.
+ (object-add-hook
+ document 'attach-hook #'rudel-header-subscriptions--attach)
+ (object-add-hook
+ document 'detach-hook #'rudel-header-subscriptions--detach))
+
+(defun rudel-header-subscriptions--remove-document (session document)
+ "Stop watching DOCUMENT for attach/detach events."
+ ;; When document is attached to a buffer, turn the mode off.
+ (with-slots (buffer) document
+ (when buffer
+ (rudel-header-subscriptions--detach document buffer)))
+
+ ;; Stop watching document for attaching and detaching.
+ (object-remove-hook
+ document 'attach-hook #'rudel-header-subscriptions--attach)
+ (object-remove-hook
+ document 'detach-hook #'rudel-header-subscriptions--detach))
+
+(defun rudel-header-subscriptions--session-start (session)
+ "Watch SESSION documents and watch for added/removed documents."
+ ;; Watch all documents in the session.
+ (with-slots (documents) session
+ (dolist (document documents)
+ (rudel-header-subscriptions--add-document session document)))
+
+ ;; Watch session for added/removed documents.
+ (object-add-hook
+ session 'add-document-hook
+ #'rudel-header-subscriptions--add-document)
+ (object-add-hook
+ session 'remove-document-hook
+ #'rudel-header-subscriptions--remove-document)
+ )
+
+(defun rudel-header-subscriptions--session-end (session)
+ "Stop watching SESSION for added/removed documents."
+ ;; Stop watching all documents in the session.
+ (with-slots (documents) session
+ (dolist (document documents)
+ (rudel-header-subscriptions--remove-document session document)))
+
+ ;; Stop watching session for added/removed documents.
+ (object-remove-hook
+ session 'add-document-hook
+ #'rudel-header-subscriptions--add-document)
+ (object-remove-hook
+ session 'remove-document-hook
+ #'rudel-header-subscriptions--remove-document)
+ )
+
+;;;###autoload
+(define-globalized-minor-mode global-rudel-header-subscriptions-mode
+ rudel-header-subscriptions-minor-mode
+ rudel-header-subscriptions-minor-mode
+ :group 'rudel)
+
+(defadvice global-rudel-header-subscriptions-mode
+ (around track-subscriptions activate)
+ "Start/stop tracking subscriptions when the mode is (de)activated."
+ (let ((value ad-do-it))
+ (if value
+
+ ;; Add handlers to session start and end hooks and run the
+ ;; start handler on already started sessions.
+ (progn
+
+ ;; Go through all existing sessions.
+ (mapc #'rudel-header-subscriptions--session-start
+ (when rudel-current-session
+ (list rudel-current-session)))
+
+ ;; Watch for new/ended sessions.
+ (add-hook 'rudel-session-start-hook
+ #'rudel-header-subscriptions--session-start)
+ (add-hook 'rudel-session-end-hook
+ #'rudel-header-subscriptions--session-end))
+
+ ;; Remove handlers from session start and end hooks and run the
+ ;; end handler on active sessions.
+ (mapc #'rudel-header-subscriptions--session-end
+ (when rudel-current-session
+ (list rudel-current-session)))
+
+ (remove-hook 'rudel-session-start-hook
+ #'rudel-header-subscriptions--session-start)
+ (remove-hook 'rudel-session-end-hook
+ #'rudel-header-subscriptions--session-end)))
+ )
+
+
+;;; Mode line indication of buffer state
+;;
+
+(defvar rudel-mode-line-publish-state-string
+ (propertize
+ "-"
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is not published")
+ "Contains a mode line fragment indicating the publication state
+of the buffer.")
+(make-variable-buffer-local 'rudel-mode-line-publish-state-string)
+(put 'rudel-mode-line-publish-state-string 'risky-local-variable t)
+
+(defun rudel-mode-line-publish-state--add-indicator-to-mode-line ()
+ "Add Rudel publish state indicator to mode line."
+ (let* ((new-format (copy-list mode-line-format))
+ (format-rest (nthcdr
+ (position 'mode-line-modified mode-line-format)
+ new-format))
+ (format-rest-cdr (cdr format-rest)))
+ (setcdr format-rest (cons 'rudel-mode-line-publish-state-string
+ format-rest-cdr))
+ (setq mode-line-format new-format))
+ (force-mode-line-update))
+
+(defun rudel-mode-line-publish-state--remove-indicator-from-mode-line ()
+ "Remove Rudel publish state indicator from mode line."
+ (let ((format-rest (nthcdr
+ (position 'mode-line-remote mode-line-format)
+ mode-line-format)))
+ ;; Only change the mode line if our indicator is present.
+ (when (eq (second format-rest) 'rudel-mode-line-publish-state-string)
+ (setcdr format-rest (cddr format-rest))
+ (force-mode-line-update))))
+
+(defun rudel-mode-line-publish-state--update-string ()
+ "Update variable `rudel-mode-line-publish-state-string'."
+ ;; Update `rudel-mode-line-publish-state-string' with appropriate
+ ;; propertized indicator string.
+ (setq rudel-mode-line-publish-state-string
+ (cond
+ ((rudel-buffer-document)
+ (propertize
+ rudel-mode-line-publish-state-published-string
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is published"))
+ (t
+ (propertize
+ rudel-mode-line-publish-state-unpublished-string
+ 'mouse-face 'mode-line-highlight
+ 'help-echo "Buffer is not published"))))
+
+ ;; Update the mode line.
+ (force-mode-line-update)
+ )
+
+(defun rudel-mode-line-publish-state--document-attach (document buffer)
+ "Handle attaching of DOCUMENT to BUFFER.
+When `rudel-mode-line-publish-state-minor-mode' is enabled in
+BUFFER, update the state string."
+ ;; Only act when BUFFER has the minor mode enabled.
+ (with-current-buffer buffer
+ (when rudel-mode-line-publish-state-minor-mode
+ ;; Update the mode line.
+ (rudel-mode-line-publish-state--update-string)
+
+ ;; Watch for detaching of DOCUMENT from BUFFER.
+ (object-add-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)))
+ )
+
+(defun rudel-mode-line-publish-state--document-detach (document buffer)
+ "Handle detaching of DOCUMENT from BUFFER."
+ ;; Update the mode line of BUFFER.
+ (with-current-buffer buffer
+ (rudel-mode-line-publish-state--update-string))
+
+ ;; Stop watching for detaching of DOCUMENT from BUFFER. It (or a
+ ;; different document) has to attach again first, before the next
+ ;; detaching can occur.
+ (object-remove-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)
+ )
+
+(defun rudel-mode-line-publish-state--options-changed ()
+ "Update mode lines in buffers that have mode line publish state mode enabled."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when rudel-mode-line-publish-state-minor-mode
+ (rudel-mode-line-publish-state--update-string)))))
+
+;;;###autoload
+(define-minor-mode rudel-mode-line-publish-state-minor-mode
+ "Toggle Rudel mode line publish state minor mode.
+
+This mode displays an indicator of the buffer's state with
+respect to an associated Rudel document in the mode line. If the
+buffer has an attached document, the string \"P\" is displayed
+after the remote file indicator. Otherwise, the string \"-\" is
+displayed.
+
+If ARG is null, toggle Rudel mode line publish state minor mode.
+If ARG is a number greater than zero, turn on Rudel minor mode
+line publish state mode; otherwise, turn it off."
+ :init-value nil
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq rudel-mode-line-publish-state-minor-mode nil))
+
+ ;; Mode is enabled
+ (rudel-mode-line-publish-state-minor-mode
+ ;; Extend and update the mode line, no matter whether the buffer
+ ;; has a document or not.
+ (rudel-mode-line-publish-state--add-indicator-to-mode-line)
+ (rudel-mode-line-publish-state--update-string)
+
+ ;; Watch document, if available or attach events, when a document
+ ;; is not available.
+ (let ((document (rudel-buffer-document)))
+ (if document
+ ;; Handle detaching of the document from the buffer.
+ (object-add-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)
+ ;; Handle attaching of documents to buffers. We use the global
+ ;; hook here, installing the handler twice is prevented by
+ ;; `add-hook'.
+ (add-hook 'rudel-document-attach-hook
+ #'rudel-mode-line-publish-state--document-attach))))
+
+ ;; Mode is disabled
+ (t
+ ;; Maybe stop watching for the document detaching from the buffer.
+ (let ((document (rudel-buffer-document)))
+ (when document
+ (object-remove-hook
+ document 'detach-hook
+ #'rudel-mode-line-publish-state--document-detach)))
+
+ ;; Remove the indicator from the mode line.
+ (rudel-mode-line-publish-state--remove-indicator-from-mode-line)))
+ )
+
+
+;;; Global mode line publish state mode
+;;
+
+;;;###autoload
+(define-globalized-minor-mode global-rudel-mode-line-publish-state-mode
+ rudel-mode-line-publish-state-minor-mode
+ rudel-mode-line-publish-state-minor-mode
+ :group 'rudel)
+
+
+;;; Global Rudel mode, menu and keymap
+;;
+
+(defvar rudel-minor-keymap
+ (let ((map (make-sparse-keymap))
+ (sub-map (make-sparse-keymap)))
+ ;; Define sub keymap
+ (define-key sub-map "j" #'rudel-join-session)
+ (define-key sub-map "h" #'rudel-host-session)
+ (define-key sub-map "e" #'rudel-end-session)
+
+ (define-key sub-map "c" #'rudel-change-color)
+
+ (define-key sub-map "p" #'rudel-publish-buffer)
+ (define-key sub-map "u" #'rudel-unpublish-buffer)
+ (define-key sub-map "s" #'rudel-subscribe)
+
+ ;; Bind the sub keymap into map
+ (define-key map "\C-cc" sub-map)
+ map)
+ "Keymap used in Rudel minor mode.")
+
+(when rudel-minor-keymap
+ (easy-menu-define
+ rudel-minor-menu rudel-minor-keymap "Rudel Minor Mode Menu"
+ '("Rudel"
+ [ "Join Session" rudel-join-session
+ (not rudel-current-session) ]
+ [ "Leave Session" rudel-end-session
+ rudel-current-session ]
+ "---"
+ [ "Host a Session" rudel-host-session
+ t ]
+ "---"
+ [ "Change Color" rudel-change-color
+ (and rudel-current-session
+ (rudel-capable-of-p
+ (oref rudel-current-session :backend)
+ 'change-color)) ] ; TODO bulky
+ "---"
+ [ "Publish current Buffer" rudel-publish-buffer
+ (and rudel-current-session
+ (not (rudel-buffer-has-document-p))) ]
+ [ "Unpublish current Buffer" rudel-unpublish-buffer
+ (rudel-buffer-has-document-p) ]
+ [ "Subscribe to Document" rudel-subscribe
+ rudel-current-session ]
+ "---"
+ [ "Rudel Overview" rudel-speedbar
+ t ]
+ "---"
+ ( "Options"
+ [ "Highlight Contributions in Authors' Colors"
+ (lambda ()
+ (interactive)
+ (setq rudel-overlay-author-display
+ (not rudel-overlay-author-display))
+ (rudel-overlay-options-changed))
+ :style toggle
+ :selected rudel-overlay-author-display ]
+ ( "Show subscribed Users"
+ [ "In this Buffer"
+ rudel-header-subscriptions-minor-mode
+ :style toggle
+ :selected rudel-header-subscriptions-minor-mode ]
+ [ "Globally"
+ global-rudel-header-subscriptions-mode
+ :style toggle
+ :selected global-rudel-header-subscriptions-mode ] )
+ ( "Show Status in mode line"
+ [ "In this Buffer"
+ rudel-mode-line-publish-state-minor-mode
+ :style toggle
+ :selected rudel-mode-line-publish-state-minor-mode ]
+ [ "Globally"
+ global-rudel-mode-line-publish-state-mode
+ :style toggle
+ :selected global-rudel-mode-line-publish-state-mode ] ) ) )
+ )
+ )
+
+;;;###autoload
+(define-minor-mode global-rudel-minor-mode
+ "Toggle global Rudel minor mode (No modeline indicator).
+
+If ARG is null, toggle global Rudel mode.
+If ARG is a number greater than zero, turn on global Rudel mode;
+otherwise, turn it off."
+ :init-value nil
+ :keymap rudel-minor-keymap
+ :global t
+ :group 'rudel
+ (cond
+ ;; Emacs session is not interactive
+ (noninteractive
+ (setq global-rudel-minor-mode nil))
+
+ ;; Mode is enabled
+ (global-rudel-minor-mode
+ )
+
+ ;; Mode is disabled
+ (t
+ ))
+ )
+
+(provide 'rudel-mode)
+;;; rudel-mode.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-operations.el b/emacs.d/lisp/rudel/rudel-operations.el
new file mode 100644
index 0000000..3637303
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-operations.el
@@ -0,0 +1,133 @@
+;;; rudel-operations.el --- Rudel domain operations
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, operations
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains classes representing operations like insertions
+;; and deletions, that are import for Rudel's domain of collaborative
+;; editing.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+
+;;; Class rudel-operation
+;;
+
+(defclass rudel-operation ()
+ ()
+ "Abstract base class for operations."
+ :abstract t)
+
+(defgeneric rudel-apply ((this rudel-operation) object)
+ "Apply the change represented by THIS to OBJECT.")
+
+
+;;; Class rudel-insert-op
+;;
+
+;; TODO should be rudel-insert but there is a method of the same name
+(defclass rudel-insert-op (rudel-operation)
+ ((from :initarg :from
+ :type (or null (integer 0))
+ :documentation
+ "Start of the region affected by this operation or
+nil. nil means end of buffer")
+ (data :initarg :data
+ :type string
+ :documentation
+ "The inserted string."))
+ "Objects of this class represent insertion operations.")
+
+(defmethod rudel-apply ((this rudel-insert-op) object)
+ "Apply THIS to OBJECT by inserting the associated data."
+ (with-slots (from data) this
+ (rudel-insert object from data)))
+
+(defmethod slot-missing ((this rudel-insert-op)
+ slot-name operation &optional new-value)
+ "Simulate read-only slots :length and :to."
+ (cond
+ ;; Slot :length
+ ((and (or (eq slot-name :length)
+ (eq slot-name 'length))
+ (eq operation 'oref))
+ (with-slots (data) this
+ (length data)))
+ ;; Slot :to
+ ((and (or (eq slot-name :to)
+ (eq slot-name 'to))
+ (eq operation 'oref))
+ (with-slots (from length) this
+ (+ from length)))
+ ;; Call next method
+ (t (call-next-method)))
+ )
+
+
+;;; Class rudel-delete-op
+;;
+
+;; TODO should be rudel-delete but there is a method of the same name
+(defclass rudel-delete-op (rudel-operation)
+ ((from :initarg :from
+ :type (integer 0)
+ :documentation
+ "Start of the region affected by this operation.")
+ (to :initarg :to
+ :type (integer 0)
+ :documentation
+ "End of the region affected by this operation."))
+ "Objects of this class represent deletion operations.")
+
+(defmethod rudel-apply ((this rudel-delete-op) object)
+ "Apply THIS to OBJECT by deleting the associated region."
+ (with-slots (from length) this
+ (rudel-delete object from length)))
+
+(defmethod slot-missing ((this rudel-delete-op)
+ slot-name operation &optional new-value)
+ "Simulate slot :length"
+ (cond
+ ;; Slot :length
+ ((or (eq slot-name :length)
+ (eq slot-name 'length))
+ (with-slots (from to) this
+ (if (eq operation 'oref)
+ (- to from)
+ (setq to (+ from new-value)))))
+ ;; Call next method
+ (t (call-next-method)))
+ )
+
+(provide 'rudel-operations)
+;;; rudel-operations.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-operators.el b/emacs.d/lisp/rudel/rudel-operators.el
new file mode 100644
index 0000000..e51982e
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-operators.el
@@ -0,0 +1,172 @@
+;;; rudel-operators.el --- Sets of modification operators for Rudel objects
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, operators
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Collections of operations on specific objects are collected into
+;; classes. Current there are
+;;
+;; - rudel-document-operators: realize operations on document objects
+;;
+;; - rudel-connection-operators: realize operations on connection
+;; objects
+;;
+;; - rudel-overlay-operators: realize operations by altering the
+;; overlays of buffer objects
+;;
+;; - rudel-hook-operators: realize operations by calling hooks
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-overlay)
+
+
+;;; Class rudel-document-operators
+;;
+
+(defclass rudel-document-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "Document to which modification operators are
+applied."))
+ "Provides operation methods which modify an associated document.")
+
+(defmethod rudel-insert ((this rudel-document-operators) position data)
+ "Insert DATA at POSITION into the document attached to THIS."
+ (with-slots (document) this
+ (rudel-insert document position data)))
+
+(defmethod rudel-delete ((this rudel-document-operators) position length)
+ "Delete a region of LENGTH characters at POSITION from the document attached to THIS."
+ (with-slots (document) this
+ (rudel-delete document position length)))
+
+
+;;; Class rudel-connection-operators
+;;
+
+(defclass rudel-connection-operators ()
+ ((connection :initarg :connection
+ :type rudel-connection-child
+ :documentation
+ "Connection on which the operations are
+performed.")
+ (document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "Document object to which operations refer."))
+ "Provides operation methods which affect an associated
+connection.")
+
+(defmethod rudel-insert ((this rudel-connection-operators) position data)
+ "Notify the connection associated to THIS of the insertion of DATA at POSITION."
+ (with-slots (connection document) this
+ (rudel-local-insert connection document position data)))
+
+(defmethod rudel-delete ((this rudel-connection-operators) position length)
+ "Notify the connection associated to THIS of a deletion of LENGTH at POSITION."
+ (with-slots (connection document) this
+ (rudel-local-delete connection document position length)))
+
+
+;;; Class rudel-overlay-operators
+;;
+
+(defclass rudel-overlay-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "The document to the overlays of which the
+operations are applied")
+ (user :initarg :user
+ :type rudel-user-child
+ :documentation
+ "The user object associated to operations."))
+ "Provides operation methods which affect the overlays of a
+buffer.")
+
+(defmethod rudel-insert ((this rudel-overlay-operators) position data)
+ "Update the overlays associated to THIS to incorporate an insertion of DATA at POSITION."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+
+ ;; Since we inserted something, (point-max) is at least the
+ ;; length of the insertion + 1. So we can safely subtract the
+ ;; length of the insertion and 1.
+ (unless position
+ (with-current-buffer buffer
+ (setq position (- (point-max) (length data) 1))))
+
+
+ (rudel-update-author-overlay-after-insert
+ buffer (+ position 1) (length data) user)))
+ )
+
+(defmethod rudel-delete ((this rudel-overlay-operators) position length)
+ "Update the overlays associated to THIS to incorporate a deletion of LENGTH at POSITION."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (rudel-update-author-overlay-after-delete
+ buffer (+ position 1) length user))))
+
+
+;;; Class rudel-hook-operators
+;;
+
+(defclass rudel-hook-operators ()
+ ((document :initarg :document
+ :type rudel-document-child
+ :documentation
+ "The document object to which operations refer.")
+ (user :initarg :user
+ :type rudel-user-child
+ :documentation
+ "The user object associated to operations."))
+ "Provides operation methods which cause corresponding hooks to
+be called.")
+
+(defmethod rudel-insert ((this rudel-hook-operators) position data)
+ "Call insert hook associated to THIS with POSITION and DATA."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (run-hook-with-args 'rudel-insert-hook buffer user position data))))
+
+(defmethod rudel-delete ((this rudel-hook-operators) position length)
+ "Call delete hook associated to THIS with POSITION and LENGTH."
+ (with-slots (document user) this
+ (with-slots (buffer) document
+ (run-hook-with-args 'rudel-delete-hook buffer user position length))))
+
+(provide 'rudel-operators)
+;;; rudel-operators.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-overlay.el b/emacs.d/lisp/rudel/rudel-overlay.el
new file mode 100644
index 0000000..093afdf
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-overlay.el
@@ -0,0 +1,275 @@
+;;; rudel-overlay.el --- Overlay functions for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, overlay
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'custom)
+
+(eval-when-compile
+ (require 'cl))
+
+
+;;; Rudel overlay faces
+;;
+
+(defcustom rudel-overlay-author-display t
+ "Indicate authorship by setting text color to user color."
+ :group 'rudel
+ :type 'boolean
+ :set (lambda (symbol value)
+ (set-default symbol value)
+ (when (featurep 'rudel-overlay)
+ (rudel-overlay-options-changed))))
+
+(put 'rudel-overlay-author-display 'safe-local-variable t)
+
+(defface rudel-author-overlay-face
+ '((default (:background "black")))
+ "*Face used to highlight contributions according to their authors.
+Attributes involving color are not applied literally. Instead the
+color is replaced with the color associated with the respective
+author."
+ :group 'rudel)
+
+
+;;; General overlay functions
+;;
+
+(defun rudel-overlay-p (overlay)
+ "Non-nil if OVERLAY is a Rudel overlay."
+ (overlay-get overlay :rudel))
+
+(defun rudel-overlay-length (overlay)
+ "Distance between end and start of OVERLAY."
+ (- (overlay-end overlay) (overlay-start overlay)))
+
+(defun rudel-overlay-user (overlay)
+ "User object associated to OVERLAY."
+ (overlay-get overlay :user))
+
+(defun rudel-overlays (&optional predicate)
+ "Return a list of Rudel-related overlays or overlays satisfying PREDICATE.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+
+ (let* ((overlay-lists (overlay-lists))
+ (overlays (append (car overlay-lists)
+ (cdr overlay-lists))))
+ (remove-if-not predicate overlays))
+ )
+
+(defun rudel-overlays-at (position &optional predicate)
+ "Return a list of Rudel-related overlays at POSITION.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+ (remove-if-not predicate (overlays-at position)))
+
+(defun rudel-overlays-in (start end &optional predicate)
+ "Return a list of Rudel-related overlays in the range START to END.
+If PREDICATE is non-nil returned overlays satisfy PREDICATES;
+Otherwise all Rudel-related overlays are returned."
+ (unless predicate
+ (setq predicate #'rudel-overlay-p))
+ (remove-if-not predicate (overlays-in start end)))
+
+(defun rudel-overlays-remove-all ()
+ "Remove all Rudel overlays from the current buffer."
+ (mapc #'delete-overlay (rudel-overlays)))
+
+
+;;; Author overlay
+;;
+
+(defun rudel-author-overlay-p (overlay)
+ "Predicate for author overlays."
+ (eq (overlay-get overlay :rudel) 'author))
+
+(defun rudel-author-overlays ()
+ "Return the list of author overlays in the current buffer."
+ (rudel-overlays #'rudel-author-overlay-p))
+
+(defun rudel-author-overlay-at (position &optional author)
+ ""
+ (let ((overlays (rudel-overlays-at
+ position #'rudel-author-overlay-p)))
+ ;; There can only be one rudel overlay at any given position
+ (when overlays
+ (when (or (not author)
+ (eq (rudel-overlay-user (car overlays)) author))
+ (car overlays))))
+ )
+
+(defun rudel-author-overlays-in (start end &optional author)
+ ""
+ (rudel-overlays-in
+ start end
+ (lambda (overlay)
+ (and (rudel-overlay-p overlay)
+ (or (not author)
+ (eq (rudel-overlay-user overlay) author)))))
+ )
+
+(defun rudel-make-author-overlay (buffer from to author)
+ "Make and return an overlay for the range FROM to TO in BUFFER suitable for contributions by AUTHOR.
+AUTHOR has to be an object of type rudel-user-child."
+ (let ((overlay (make-overlay from to buffer t)))
+ (rudel-overlay-author-set-properties overlay author)
+ overlay))
+
+(defun rudel-overlay-author-set-properties (overlay author)
+ "Set properties of OVERLAY according to slots of AUTHOR.
+AUTHOR has to be an object of type rudel-user-child."
+ (with-slots ((name :object-name) color) author
+ (overlay-put overlay :rudel 'author)
+ (overlay-put overlay :user author)
+ (overlay-put overlay 'face (when rudel-overlay-author-display
+ (rudel-overlay-make-face
+ (rudel-overlay-make-face-symbol
+ 'author name)
+ 'rudel-author-overlay-face
+ color)))
+ (overlay-put overlay 'help-echo (when rudel-overlay-author-display
+ (format "Written by %s" name))))
+ )
+
+(defun rudel-overlay-author-update (overlay)
+ "Update properties of OVERLAY from its attached user object."
+ (let ((author (rudel-overlay-user overlay)))
+ (rudel-overlay-author-set-properties overlay author)))
+
+
+;;; Update functions for author overlays
+;;
+
+(defun rudel-update-author-overlay-after-insert (buffer position length author)
+ "Update author overlays in BUFFER to incorporate an insertion of length LENGTH at POSITION by AUTHOR.
+POSITION refers to an Emacs buffer position.
+AUTHOR has to be an object of type rudel-author-child."
+ (when author
+ (with-current-buffer buffer
+ (let* ((end (+ position length))
+ (before (when (> position 1)
+ (rudel-author-overlay-at (- position 1) author)))
+ (at (rudel-author-overlay-at position))
+ (after (when (< end (point-max))
+ (rudel-author-overlay-at (+ end 1) author))))
+ (cond
+ ;; If there is an overlay, we have to split it unless the
+ ;; author is AUTHOR or we are on its boundary.
+ (at
+ (unless (eq (rudel-overlay-user at) author)
+ (let* ((on-start (= (overlay-start at) position))
+ (on-end (= (- (overlay-end at) 1) position))
+ (before (unless on-start
+ (if on-end at (copy-overlay at))))
+ (after (unless on-end at)))
+ (when before
+ (move-overlay before (overlay-start before) position))
+ (when after
+ (move-overlay after end (overlay-end after)))
+ (rudel-make-author-overlay buffer position end author))))
+ ;; There is no overlay under the insert, but there are
+ ;; overlays of the same author immediately before and after
+ ;; the insert. We merge these two into one large overlay
+ ;; including the insert.
+ ((and before after)
+ (let ((end (overlay-end after)))
+ (delete-overlay after)
+ (move-overlay before (overlay-start before) end)))
+ ;; If there is an overlay of the same author before the
+ ;; insert, we extend it.
+ (before
+ (move-overlay before (overlay-start before) end))
+ ;; If there is an overlay of the same author after the
+ ;; insert, we extend it.
+ (after
+ (move-overlay after position (overlay-end after)))
+ ;; If there are no overlays at all, we create a suitable one.
+ (t
+ (rudel-make-author-overlay buffer position end author))))))
+ )
+
+(defun rudel-update-author-overlay-after-delete (buffer position length author)
+ "Update author overlays in BUFFER to incorporate a deletion of length LENGTH at POSITION by AUTHOR.
+POSITION refers to an Emacs buffer position.
+AUTHOR has to be an object of type rudel-author-child."
+ (with-current-buffer buffer
+ (mapc
+ (lambda (overlay)
+ (when (zerop (rudel-overlay-length overlay))
+ (delete-overlay overlay)))
+ (rudel-author-overlays-in position position)))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-overlay-make-face-symbol (category name)
+ "Allocate a symbol for a face for CATEGORY and NAME."
+ (intern (format "rudel-%s-overlay-%s-face"
+ (if (stringp category)
+ category
+ (symbol-name category))
+ name)))
+
+(defun rudel-overlay-make-face (face template color)
+ "Copy TEMPLATE to FACE and replace color attributes with COLOR.
+TEMPLATE has to be a face. FACE can be nil or a face. In the
+latter case, FACE is returned unmodified."
+ (unless (facep face)
+ (make-face face)
+ (copy-face template face)
+ (rudel-overlay-set-face-attributes face color))
+ face)
+
+(defun rudel-overlay-set-face-attributes (face color)
+ "Set color-related attributes of FACE with respect to COLOR."
+ (when (facep face)
+ (dolist (property '(:foreground :background :underline :overline))
+ (unless (eq (face-attribute face property) 'unspecified)
+ (set-face-attribute face nil property color)))))
+
+(defun rudel-overlay-options-changed ()
+ "Update Rudel overlays after a change of customization options."
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (mapc #'rudel-overlay-author-update (rudel-overlays)))))
+
+(provide 'rudel-overlay)
+;;; rudel-overlay.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-protocol.el b/emacs.d/lisp/rudel/rudel-protocol.el
new file mode 100644
index 0000000..c60718c
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-protocol.el
@@ -0,0 +1,83 @@
+;;; rudel-protocol.el --- Interface implemented by Rudel protocol backends
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, protocol
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the interface for Rudel protocol backends. This
+;; interface consists of the following functions:
+;;
+;; + joining sessions
+;; + `rudel-ask-join-info'
+;; + `rudel-join'
+;; + hosting sessions
+;; + `rudel-ask-host-info'
+;; + `rudel-host'
+;; + factory functions
+;; + `rudel-make-document'
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Class rudel-protocol-backend
+;;
+
+(defclass rudel-protocol-backend (rudel-backend)
+ ()
+ "Interface implemented by protocol backends."
+ :abstract t)
+
+(defgeneric rudel-ask-join-info ((this rudel-protocol-backend))
+ "Retrieve information for joining a session from user.
+Return a property list that contains the collected information.")
+
+(defgeneric rudel-join ((this rudel-protocol-backend) info)
+ "Create a new connection according to the data in the property list INFO.
+Implementations can rely on the fact that the property :session
+contains the `rudel-session' object to which the new connection
+will be associated.")
+
+(defgeneric rudel-ask-host-info ((this rudel-protocol-backend))
+ "Retrieve information for hosting a session from user.
+Return a property list that contains the collected information.")
+
+(defgeneric rudel-host ((this rudel-protocol-backend) info)
+ "Create a new session according to the property list INFO.")
+
+(defgeneric rudel-make-document ((this rudel-protocol-backend)
+ name session)
+ "Create a new document object named NAME for SESSION.")
+
+(provide 'rudel-protocol)
+;;; rudel-protocol.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-session-initiation.el b/emacs.d/lisp/rudel/rudel-session-initiation.el
new file mode 100644
index 0000000..395ab07
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-session-initiation.el
@@ -0,0 +1,352 @@
+;;; rudel-session-initiation.el --- Session discovery and advertising functions
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, session, initiation, service, discovery, advertising
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Interfaces for session initiation and discovery.
+;;
+;; The central interface is
+;; `rudel-session-initiation-backend'. Backends implementing this
+;; interface can provide methods to discover sessions, to advertise
+;; sessions, or both.
+;;
+;; The client programming interface consists of a priority which is
+;; one of:
+;;
+;; + `primary'
+;; + `fallback'
+;;
+;; and the following functions:
+;;
+;; + `rudel-session-initiation-discover'
+;; + `rudel-session-initiation-advertise'
+;; + `rudel-session-initiation-withdraw'
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Customization options
+;;
+
+(defcustom rudel-configured-sessions nil
+ "List of configured sessions.
+
+Each session is described as a plist (a list of keys and values
+see Info node `(elisp)Property Lists'). Keys are specified using
+keywords and look like this: :host, :username, :color. Values are
+mostly strings, but symbols and numbers are possible as well.
+
+The following keys are required for any session:
+
+* :name (string)
+* :backend (string or symbol)
+
+Other keys are optional and depend on the selected
+backend. Required keys for which no value is specified will be
+prompted for when selecting the session. The values of the :name
+properties have to be distinct for all configured sessions.
+
+Additional keys required by most backends:
+
+* :host (string)
+* :port (number)
+* :username (string)
+* :color (string)
+
+Here is a complete example of customized values for the obby
+backend:
+
+* :name \"sonian\"
+* :backend obby
+* :host \"sobby\"
+* :port 6522
+* :encryption t
+* :username \"phil\"
+* :color \"white\"
+* :global-password \"\" (this means \"no password\")
+* :user-password \"\"
+
+The programmatic equivalent looks like this:
+
+(add-to-list
+ 'rudel-configured-sessions
+ (list :name \"myserver\"
+ :backend 'obby
+ :host \"my.sobby-server.net\"
+ :username user-login-name
+ ;; Use M-x list-colors-display to see color choices.
+ :color \"white\"
+ :encryption t
+ :port 6522
+ ;; empty string means no password
+ :global-password \"\"
+ :user-password \"\"))"
+ :group 'rudel
+ :type '(repeat :tag "Connections"
+ (plist :tag "Connection"
+ :options ((:name string)
+ (:backend symbol)
+ (:username string)
+ (:color color))))
+ )
+
+
+;;; Variables and constants
+;;
+
+(defvar rudel-session-discovered-hook nil
+ "This hook is run when collaboration sessions are discovered.")
+
+(defvar rudel-session-vanished-hook nil
+ "This hook is run when previously discovered collaboration
+session disappear.")
+
+
+;;; Class rudel-session-initiation-backend
+;;
+
+(defclass rudel-session-initiation-backend (rudel-backend)
+ ((priority :initarg :priority
+ :type symbol
+ :accessor rudel-priority
+ :documentation
+ "Priority of the session initiation method
+implemented by this backend. Has to be either 'primary or
+'fallback"))
+ "Interface implemented by session initiation backends."
+ :abstract t)
+
+(defgeneric rudel-discover ((this rudel-session-initiation-backend))
+ "Return a list of discovered sessions.
+Each list element is a connect info property list. See
+`rudel-join-session' for a description of the format of this
+list.
+
+The presence of an implementation of this generic function should
+be indicated by the presence of the 'discover' capability.")
+
+(defgeneric rudel-advertise ((this rudel-session-initiation-backend) info)
+ "Advertise session described by INFO.
+INFO is a connect info property list. See `rudel-host-session'
+for a description of the format of this list.
+
+The presence of an implementation of this generic function should
+be indicated by the presence of the 'advertise' capability.")
+
+
+;;; Client programming interface functions.
+;;
+
+(defun rudel-session-initiation-suitable-backends (capability)
+ "Return primary and fallback backends that have CAPABILITY.
+The returned list is of the form (PRIMARY FALLBACK), where
+PRIMARY and FALLBACK are lists of backends of the respective
+priority."
+ (let* (;; Select all backends, which can discover sessions
+ (suitable-backends (rudel-backend-suitable-backends
+ 'session-initiation
+ (lambda (backend)
+ (rudel-capable-of-p backend capability))))
+ ;; Select primary backends
+ (primary-backends (remove*
+ 'fallback suitable-backends
+ :key (lambda (backend)
+ (rudel-priority (cdr backend)))))
+ ;; Select fallback backends
+ (fallback-backends (remove*
+ 'primary suitable-backends
+ :key (lambda (backend)
+ (rudel-priority (cdr backend))))))
+ (list primary-backends fallback-backends))
+ )
+
+(defun rudel-session-initiation-discover (&optional backend-name)
+ "Return a list of session using BACKEND-NAME when non-nil.
+BACKEND-NAME is a symbol. When it is non-nil, only the specified
+backend is used to discover session.
+
+The returned list is of the form (INFO-1 ... INFO-N FALLBACK-1
+... FALLBACK-M) where INFO-I are connect info property lists (see
+`rudel-join-session') and FALLBACK-I are conses of the form (NAME
+. CLASS-OR-OBJECT) that specify fallback backends."
+ (multiple-value-bind (primary-backends fallback-backends)
+ (rudel-session-initiation-suitable-backends 'discover)
+ ;; Retrieve session list from primary backend and fall back to
+ ;; fallback backends if the list is empty.
+ (if backend-name
+ (let ((backend (find backend-name fallback-backends :key #'car)))
+ (rudel-discover (cdr backend)))
+ (let ((primary-results
+ (remove-if #'null
+ (apply #'append
+ (mapcar #'rudel-discover
+ (mapcar #'cdr primary-backends))))))
+ (append primary-results fallback-backends))))
+ )
+
+(defun rudel-session-initiation-advertise (info)
+ "Advertise the session described by INFO.
+INFO is a connect info property list. See `rudel-host-session'
+for a description of the format of this list.
+
+Primary backends are tried first. If none succeeds, fallback
+backends are tried.
+
+The result is non-nil if at least one backend was able to
+advertise the session."
+ (multiple-value-bind (primary-backends fallback-backends)
+ (rudel-session-initiation-suitable-backends 'advertise)
+ (or ;; Try to advertise the session using primary backends.
+ (some (mapcar (lambda (backend)
+ (rudel-advertise backend info))
+ (mapcar #'cdr primary-backends)))
+ ;; When the primary backends fail, try to advertise the
+ ;; session using fallback backends
+ (some (mapcar (lambda (backend)
+ (rudel-advertise backend info))
+ (mapcar #'cdr fallback-backends)))))
+ )
+
+
+;;; Class rudel-ask-protocol-backend
+;;
+
+(defconst rudel-ask-protocol-version '(0 1)
+ "Version of the ask-protocol backend for Rudel.")
+
+;;;###autoload
+(defclass rudel-ask-protocol-backend (rudel-session-initiation-backend)
+ ((capabilities :initform (discover))
+ (priority :initform fallback))
+ "This fallback backend can \"discover\" sessions by letting the
+user select a suitable backend and asking for connect information
+required by the chosen backend.")
+
+(defmethod initialize-instance ((this rudel-ask-protocol-backend)
+ &rest slots)
+ "Set backend version."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-ask-protocol-version))
+
+(defmethod rudel-discover ((this rudel-ask-protocol-backend))
+ "\"Discover\" sessions by asking the user about the backend to use and the connect info."
+ (let ((backend (rudel-backend-choose
+ 'protocol
+ (lambda (backend)
+ (rudel-capable-of-p backend 'join)))))
+ (list (append (list :name "asked"
+ :backend backend)
+ (rudel-ask-connect-info (cdr backend)))))
+ )
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'ask-protocol 'rudel-ask-protocol-backend)
+
+
+;;; Class rudel-configured-sessions-backend
+;;
+
+(defconst rudel-configured-sessions-version '(0 1)
+ "Version of the configured-sessions backend for Rudel.")
+
+;;;###autoload
+(defclass rudel-configured-sessions-backend
+ (rudel-session-initiation-backend)
+ ((capabilities :initform (discover))
+ (priority :initform primary))
+ "This fallback backend can \"discover\" sessions the user has
+configured using customization.")
+
+(defmethod initialize-instance ((this rudel-configured-sessions-backend)
+ &rest slots)
+ "Set backend version."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-configured-sessions-version))
+
+(defmethod rudel-discover ((this rudel-configured-sessions-backend))
+ "\"Discover\" sessions the has configured."
+ ;; Iterate over all configured sessions in order to make
+ ;; adjustments.
+ (mapcar #'rudel-session-initiation-adjust-info
+ rudel-configured-sessions))
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'configured-sessions 'rudel-configured-sessions-backend)
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-session-initiation-adjust-info (info)
+ "Resolve arguments that need resolving in INFO."
+ ;; Start with a new, empty property list.
+ (let ((adjusted-info)
+ (key (car info))
+ (value (cadr info))
+ (rest info))
+ ;; Iterate over all properties in INFO.
+ (while rest
+ (setq rest (cddr rest))
+ (cond
+ ;; Resolve backend arguments.
+ ((eq key :backend)
+ (let ((backend (rudel-backend-get 'protocol
+ (if (stringp value)
+ (intern value)
+ value))))
+ (push backend adjusted-info)
+ (push key adjusted-info)))
+ ;; Keep other arguments unmodified.
+ (t
+ (push value adjusted-info)
+ (push key adjusted-info)))
+ ;; Advance to next key value pair.
+ (setq key (car rest)
+ value (cadr rest)))
+ ;; Return the transformed session information.
+ adjusted-info)
+ )
+
+(provide 'rudel-session-initiation)
+;;; rudel-session-initiation.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-speedbar.el b/emacs.d/lisp/rudel/rudel-speedbar.el
new file mode 100644
index 0000000..8c2caa8
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-speedbar.el
@@ -0,0 +1,214 @@
+;;; rudel-speedbar.el --- Speedbar rendering of Rudel objects
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, collaboration, speedbar
+;; X-RCS: $Id: rudel-speedbar.el,v 1.32 2008/10/10 21:47:28 zappo Exp $
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+;;; Commentary:
+;;
+;; This implements rendering of Rudel objects in speedbar.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'speedbar)
+(require 'eieio-speedbar)
+
+
+;;; Class rudel-user methods
+;;
+
+(defmethod eieio-speedbar-description ((this rudel-user))
+ "Provide a speedbar description for OBJ."
+ (format "User %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-user))
+ "Return a string to use as a speedbar button for OBJECT."
+ (format "%s" (object-name-string this)))
+
+
+;;; Class rudel-document methods
+;;
+
+(defmethod eieio-speedbar-description ((this rudel-document))
+ "Construct a description for from the name of document object THIS."
+ (format "Document %s" (object-name-string this)))
+
+(defmethod eieio-speedbar-object-buttonname ((this rudel-document))
+ "Return a string to use as a speedbar button for OBJECT."
+ (rudel-unique-name this))
+
+;;; Speedbar support mode
+;;
+(defun rudel-speedbar-make-map ()
+ "Make the generic object based speedbar keymap."
+ (speedbar-make-specialized-keymap))
+
+(defvar rudel-speedbar-key-map
+ (rudel-speedbar-make-map)
+ "A Generic object based speedbar display keymap.")
+
+(defvar rudel-speedbar-menu
+ '([ "Compile" rudel-speedbar-compile-line t])
+ "Menu part in easymenu format used in speedbar while browsing objects.")
+
+(defun rudel-speedbar-toplevel-buttons (dir)
+ "Return a list of objects to display in speedbar.
+Argument DIR is the directory from which to derive the list of objects."
+ (when rudel-current-session
+ (with-slots (users documents) rudel-current-session
+ (append users documents))))
+
+(eieio-speedbar-create 'rudel-speedbar-make-map
+ 'rudel-speedbar-key-map
+ 'rudel-speedbar-menu
+ "Collaboration Session"
+ 'rudel-speedbar-toplevel-buttons)
+
+;;;###autoload
+(defun rudel-speedbar ()
+ "Show connected users and available documents of Rudel session in speedbar."
+ (interactive)
+ (speedbar-frame-mode 1)
+ (speedbar-change-initial-expansion-list "Collaboration Session")
+ (speedbar-get-focus))
+
+;;; Speedbar Project Methods
+;;
+;; (defun rudel-find-nearest-file-line ()
+;; "Go backwards until we find a file."
+;; (save-excursion
+;; (beginning-of-line)
+;; (looking-at "^\\([0-9]+\\):")
+;; (let ((depth (string-to-number (match-string 1))))
+;; (while (not (re-search-forward "[]] [^ ]"
+;; (save-excursion (end-of-line)
+;; (point))
+;; t))
+;; (re-search-backward (format "^%d:" (1- depth)))
+;; (setq depth (1- depth)))
+;; (speedbar-line-token))))
+;;
+;; (defmethod eieio-speedbar-derive-line-path ((obj rudel-session) &optional depth)
+;; "Return the path to OBJ.
+;; Optional DEPTH is the depth we start at."
+;; "session" ;(file-name-directory (oref obj file))
+;; )
+;;
+;; (defmethod eieio-speedbar-derive-line-path ((obj rudel-session) &optional depth)
+;; "Return the path to OBJ.
+;; Optional DEPTH is the depth we start at."
+;; (let ((proj (rudel-target-parent obj)))
+;; ;; Check the type of line we are currently on.
+;; ;; If we are on a child, we need a file name too.
+;; (save-excursion
+;; (let ((lt (speedbar-line-token)))
+;; (if (or (eieio-object-p lt) (stringp lt))
+;; (eieio-speedbar-derive-line-path proj)
+;; ;; a child element is a token. Do some work to get a filename too.
+;; (concat (eieio-speedbar-derive-line-path proj)
+;; (rudel-find-nearest-file-line)))))))
+;;
+;; (defmethod eieio-speedbar-description ((obj rudel-session))
+;; "Provide a speedbar description for OBJ."
+;; "bla") ;(rudel-description obj))
+;;
+;;
+;; (defmethod eieio-speedbar-object-buttonname ((object rudel-project))
+;; "Return a string to use as a speedbar button for OBJECT."
+;; (if (rudel-parent-project object)
+;; (rudel-name object)
+;; (concat (rudel-name object) " " (oref object version))))
+;;
+;;
+;; (defmethod eieio-speedbar-object-children ((this rudel-project))
+;; "Return the list of speedbar display children for THIS."
+;; (condition-case nil
+;; (with-slots (subproj targets) this
+;; (append subproj targets))
+;; (error nil)))
+;;
+;;
+;; ;;; Generic file management for TARGETS
+;; ;;
+;; (defun rudel-file-find (text token indent)
+;; "Find the file TEXT at path TOKEN.
+;; INDENT is the current indentation level."
+;; (speedbar-find-file-in-frame
+;; (expand-file-name token (speedbar-line-directory indent)))
+;; (speedbar-maybee-jump-to-attached-frame))
+;;
+;; (defun rudel-create-tag-buttons (filename indent)
+;; "Create the tag buttons associated with FILENAME at INDENT."
+;; (let* ((lst (speedbar-fetch-dynamic-tags filename)))
+;; ;; if no list, then remove expando button
+;; (if (not lst)
+;; (speedbar-change-expand-button-char ??)
+;; (speedbar-with-writable
+;; ;; We must do 1- because indent was already incremented.
+;; (speedbar-insert-generic-list (1- indent)
+;; lst
+;; 'rudel-tag-expand
+;; 'rudel-tag-find)))))
+;;
+;; (defun rudel-tag-expand (text token indent)
+;; "Expand a tag sublist. Imenu will return sub-lists of specialized tag types.
+;; Etags does not support this feature. TEXT will be the button
+;; string. TOKEN will be the list, and INDENT is the current indentation
+;; level."
+;; (cond ((string-match "+" text) ;we have to expand this file
+;; (speedbar-change-expand-button-char ?-)
+;; (speedbar-with-writable
+;; (save-excursion
+;; (end-of-line) (forward-char 1)
+;; (speedbar-insert-generic-list indent token
+;; 'rudel-tag-expand
+;; 'rudel-tag-find))))
+;; ((string-match "-" text) ;we have to contract this node
+;; (speedbar-change-expand-button-char ?+)
+;; (speedbar-delete-subblock indent))
+;; (t (error "Ooops... not sure what to do")))
+;; (speedbar-center-buffer-smartly))
+;;
+;; (defun rudel-tag-find (text token indent)
+;; "For the tag TEXT in a file TOKEN, goto that position.
+;; INDENT is the current indentation level."
+;; (let ((file (rudel-find-nearest-file-line)))
+;; (speedbar-find-file-in-frame file)
+;; (save-excursion (speedbar-stealthy-updates))
+;; ;; Reset the timer with a new timeout when cliking a file
+;; ;; in case the user was navigating directories, we can cancel
+;; ;; that other timer.
+;; ; (speedbar-set-timer speedbar-update-speed)
+;; (goto-char token)
+;; (run-hooks 'speedbar-visiting-tag-hook)
+;; ;;(recenter)
+;; (speedbar-maybee-jump-to-attached-frame)
+;; ))
+
+(provide 'rudel-speedbar)
+
+;;; rudel-speedbar.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-state-machine.el b/emacs.d/lisp/rudel/rudel-state-machine.el
new file mode 100644
index 0000000..d96bcc7
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-state-machine.el
@@ -0,0 +1,331 @@
+;;; rudel-state-machine.el --- A simple state machine for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, FSM
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This is a simple implementation of a finite state machine
+;; (FSM). The is modeled by rudel-state-machine class, objects of
+;; which contain state objects of classes derived from
+;; rudel-state. There are no explicit transition rules, since states
+;; specify their successors.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-errors)
+(require 'rudel-compat) ;; for pulsing progress reporter
+
+
+;;; Errors related to the state machine
+;;
+
+;; rudel-state-error
+
+(intern "rudel-state-error")
+
+(put 'rudel-state-error 'error-conditions
+ '(error
+ rudel-error rudel-state-error))
+
+(put 'rudel-state-error 'error-message
+ "Invalid state or state transition")
+
+;; rudel-invalid-successor-state
+
+(intern "rudel-invalid-successor-state")
+
+(put 'rudel-invalid-successor-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-invalid-successor-state))
+
+(put 'rudel-invalid-successor-state 'error-message
+ "Invalid successor state in state transition")
+
+;; rudel-entered-error-state
+
+(intern "rudel-entered-error-state")
+
+(put 'rudel-entered-error-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-entered-error-state))
+
+(put 'rudel-entered-error-state 'error-message
+ "Transition to error state")
+
+;; rudel-no-start-state
+
+(intern "rudel-no-start-state")
+
+(put 'rudel-no-start-state 'error-conditions
+ '(error
+ rudel-error rudel-state-error rudel-no-start-state))
+
+(put 'rudel-no-start-state 'error-message
+ "No start state specified for state machine")
+
+
+;;; Class rudel-state
+;;
+
+(defclass rudel-state ()
+ ()
+ "A state that can be used in state machines."
+ :abstract t)
+
+(defgeneric rudel-accept ((this rudel-state) &rest arguments)
+ "Executed when the machine receives an event while in state THIS.")
+
+(defgeneric rudel-enter ((this rudel-state) &rest arguments)
+ "Executed when the machine switches to state THIS.")
+
+(defgeneric rudel-leave ((this rudel-state))
+ "Executed when the machine leaves state THIS.")
+
+
+;;; Class rudel-state-machine
+;;
+
+(defclass rudel-state-machine ()
+ ((states :initarg :states
+ :type list ;; alist
+ :initform nil
+ :documentation
+ "A list (NAME . STATE) conses where NAME is a symbol
+and STATE is an object of a class derived from rudel-state.")
+ (state :initarg :state
+ :type rudel-state-child
+ :documentation
+ "The current state of the machine."))
+ "A finite state machine.")
+
+(defmethod initialize-instance :after ((this rudel-state-machine)
+ &rest slots)
+ "Set current state of THIS to a proper initial value.
+If a start state is specified in the arguments to the
+constructor, that state is used. If there is no such state, the
+list of states is search for a state named start. If that fails
+as well, the first state in the state list is used."
+ (with-slots (states) this
+ ;; Find a suitable start state and switch to it.
+ (let ((start (or (plist-get slots :start)
+ (car (assoc 'start states))
+ (when (length states)
+ (car (nth 0 states))))))
+ (unless start
+ (signal 'rudel-no-start-state nil))
+ ;; Make start state the current state and call send an enter
+ ;; message.
+ (let ((start (cdr (assoc start states))))
+ (oset this :state start)
+ (rudel--switch-to-return-value
+ this start (rudel-enter start)))))
+ )
+
+(defmethod rudel-find-state ((this rudel-state-machine) name)
+ "Return state object for symbol NAME."
+ (with-slots (states) this
+ (cdr (assoc name states))))
+
+(defmethod rudel-register-state ((this rudel-state-machine) name state)
+ "Register STATE and its NAME with THIS state machine."
+ (object-add-to-list this :states (cons name state) t))
+
+(defmethod rudel-register-states ((this rudel-state-machine) states)
+ "Register STATES with THIS state machine.
+STATES is a list of cons cells whose car is a symbol - the name
+of the state - and whose cdr is a class."
+ (dolist (symbol-and-state states)
+ (destructuring-bind (name . class) symbol-and-state
+ (rudel-register-state
+ this name (make-instance class (symbol-name name)))))
+ )
+
+(defmethod rudel-current-state ((this rudel-state-machine) &optional object)
+ "Return name and, optionally, state object of the current state of THIS.
+If OBJECT is non-nil, (NAME . OBJECT) is returned. Otherwise,
+just NAME."
+ (with-slots (states state) this
+ (let ((state-symbol (car (find state states :key #'cdr :test #'eq))))
+ (if object
+ (cons state-symbol state)
+ state-symbol)))
+ )
+
+(defmethod rudel-accept ((this rudel-state-machine) &rest arguments)
+ "Process an event described by ARGUMENTS."
+ (with-slots (state) this
+ ;; Let the current state decide which state is next.
+ (let ((next (apply #'rudel-accept state arguments)))
+ (cond
+ ;; If NEXT is nil, a symbol or a state object, we switch states
+ ;; without passing any data.
+ ((or (null next) (symbolp next) (rudel-state-child-p next))
+ (rudel-switch this next))
+
+ ;; If NEXT is a list, it contains the symbol of the successor
+ ;; state and additional data.
+ ((listp next)
+ (apply #'rudel-switch this next))
+
+ ;; Other types cannot be processed.
+ (t
+ (signal 'wrong-type-argument (list (type-of next)))))))
+ )
+
+(defmethod rudel-switch ((this rudel-state-machine) next
+ &rest arguments)
+ "Leave current state and switch to state NEXT.
+ARGUMENTS are passed to the `rudel-enter' method of the successor
+state."
+ (with-slots (states state) this
+ (cond
+ ;; When NEXT is a state object, use it.
+ ((rudel-state-child-p next))
+
+ ;; When NEXT is nil, stay in the current state.
+ ((null next)
+ (setq next state))
+
+ ;; When NEXT is a symbol (but not nil), look up the corresponding
+ ;; state. Signal an error, if there is none.
+ ((symbolp next)
+ (let ((next-state (assoc next states)))
+ (unless next-state
+ (signal 'rudel-invalid-successor-state
+ (list next '<- state)))
+ (setq next (cdr next-state))))
+
+ ;; Other types cannot be processed.
+ (t
+ (signal 'wrong-type-argument (list (type-of next)))))
+
+ ;; Unless the successor state is equal to the current state, leave
+ ;; the current state and switch to the successor.
+ (if (and (eq state next)
+ (null arguments))
+ ;; Return state
+ state
+ ;; Notify (old) current state.
+ (rudel-leave state)
+ ;; Update current state.
+ (setq state next)
+ ;; Notify (new) current state. Using the call's value as next
+ ;; state is a bit dangerous since a long sequence of immediate
+ ;; state switches could exhaust the stack.
+ (rudel--switch-to-return-value
+ this state (apply #'rudel-enter state arguments))))
+ )
+
+(defmethod rudel--switch-to-return-value ((this rudel-state-machine)
+ state next)
+ "Switch from STATE to the next state indicated by NEXT.
+STATE is the current state.
+NEXT can nil, a list or a `rudel-state' object."
+ (cond
+ ;; Remain in current state.
+ ((null next)
+ state)
+ ;; NEXT contains next state and arguments to pass to it when
+ ;; switching.
+ ((listp next)
+ (apply #'rudel-switch this next))
+ ;; Otherwise NEXT is a `rudel-state' object.
+ (t
+ (rudel-switch this next)))
+ )
+
+(defmethod object-print ((this rudel-state-machine) &rest strings)
+ "Add current state to the string representation of THIS."
+ (if (slot-boundp this 'state)
+ (with-slots (state) this
+ (apply #'call-next-method
+ this
+ (format " state: %s"
+ (object-name-string state))
+ strings))
+ (call-next-method this " state: #start"))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-state-wait (machine success-states
+ &optional error-states callback)
+ "Repeatedly call CALLBACK until MACHINE is in a state in SUCCESS-STATES or ERROR-STATES.
+MACHINE should be of type rudel-state-machine-child or at least
+have a method `rudel-get-state'.
+
+SUCCESS-STATES and ERROR-STATES are lists which contain the
+names (as symbols) of success and error states respectively.
+This function does not return when MACHINE enters states not in
+SUCCESS-STATES or ERROR-STATES. As a result, a deadlock can occur
+when MACHINE deadlocks or cycles through states not in either
+list infinitely.
+
+When non-nil, CALLBACK has to be a function that accepts one
+argument of the form (SYMBOL . STATE) where SYMBOL is the name
+symbol of the current state and STATE is the state object."
+ ;; Wait until MACHINE enter a state in SUCCESS-STATES or
+ ;; ERROR-STATES.
+ (let ((result
+ (catch 'state-wait
+ (while t
+ ;; Retrieve current state.
+ (destructuring-bind (symbol . state)
+ (rudel-current-state machine t)
+
+ ;; Check against success and error states.
+ (when (memq symbol success-states)
+ (throw 'state-wait (cons 'success (cons symbol state))))
+ (when (memq symbol error-states)
+ (throw 'state-wait (cons 'error (cons symbol state))))
+
+ ;; Update progress indicator and sleep.
+ (when callback
+ (funcall callback (cons symbol state)))
+ (sleep-for 0.05))))))
+ (when callback
+ (funcall callback t))
+
+ ;; If MACHINE ended up in an error state, signal
+ (unless (eq (car result) 'success)
+ (signal 'rudel-entered-error-state (cdr result)))
+ ;; Return state
+ (cdr result))
+ )
+
+(provide 'rudel-state-machine)
+;;; rudel-state-machine.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-tls.el b/emacs.d/lisp/rudel/rudel-tls.el
new file mode 100644
index 0000000..a770851
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-tls.el
@@ -0,0 +1,201 @@
+;;; rudel-tls.el --- Start TLS protocol.
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, TLS, encryption, starttls, gnutls
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This contains a simple implementation of the so calls Start TLS
+;; protocol, which means enabling TLS encryption for an existing
+;; network connection.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'format-spec)
+
+(require 'rudel)
+(require 'rudel-util)
+
+
+;;; Customization
+;;
+
+(defcustom rudel-tls-client-program
+ "gnutls-cli"
+ "The gnutls client program to use for encrypted connections."
+ :group 'rudel
+ :type 'file)
+
+(defcustom rudel-tls-client-arguments
+ "--starttls --kx ANON_DH --port %p %h"
+ "Arguments passed to the gnutls client program."
+ :group 'rudel
+ :type 'string)
+
+
+;;; TLS functions
+;;
+
+(defun rudel-tls-make-process (&rest args)
+ "Make a network process with keyword arguments ARGS.
+This function works similar to `make-network-process'. Supported
+keyword arguments are :name (ignore), :host, :port, :filter
+and :sentinel. The returned process object is suitable for
+start-TLS. Once the enclosing protocol indicates TLS encryption
+should start, `rudel-tls-start-tls' can be called to enabled TLS
+for the network connection."
+ (let* ((host (plist-get args :host)) ;; TODO clumsy
+ (port (plist-get args :service))
+ (filter (plist-get args :filter))
+ (sentinel (plist-get args :sentinel))
+ ;; Compile the command to start the TLS binary.
+ (arguments (format-spec rudel-tls-client-arguments
+ (format-spec-make
+ ?h host
+ ?p (number-to-string port))))
+ ;; Start the TLS program.
+ (process (apply #'start-process
+ (format "*tls-%s*" host) nil
+ rudel-tls-client-program
+ (split-string arguments " "))))
+
+ ;; Store filter function and attach proxy filter to handle TLS
+ ;; handshake.
+ (when filter
+ (rudel-set-process-object process filter :old-filter))
+ (set-process-filter process #'rudel-tls-wait-init)
+
+ ;; Attach sentinel function.
+ (when sentinel
+ (set-process-sentinel process sentinel))
+
+ ;; Mark the process as supporting TLS encryption
+ (rudel-set-process-object process t :supports-tls)
+
+ process)
+ )
+
+(defun rudel-tls-start-tls (process)
+ "Enable TLS encryption for the network connection PROCESS.
+This only works if PROCESS has been created by
+`rudel-tls-make-process'."
+ ;; Save current filter function.
+ (rudel-set-process-object
+ process (process-filter process) :old-filter)
+ ;; Install TLS handshake filter function and signal program to start
+ ;; TLS handshake.
+ (message "tls-start-tls: switching to \"handshake\" filter")
+ (set-process-filter process #'rudel-tls-wait-handshake)
+ (signal-process process 'sigalrm)
+ )
+
+(defun rudel-tls-wait-init (process data)
+ "Is installed as process filter on PROCESS until gnutls is done printing messages."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter))
+ (client-mode))
+
+ ;; Assemble lines that were not generated by gnutls. It is very
+ ;; brittle to wait for last line of gnutls output like, but it
+ ;; cannot be helped.
+ (rudel-loop-lines data line
+ (if client-mode
+ (setq client-data (concat client-data line "\n"))
+ (when (string-match-p "- Simple Client Mode.*" line)
+ (setq client-mode t))))
+
+ ;; When there are any lines not generated by gnutls,
+ ;; initialization is over. Process the data and install the old
+ ;; filter function.
+ (when client-data
+ (funcall old-filter process client-data))
+ (when client-mode
+ (message "tls-wait-init: switching back to old filter")
+ (set-process-filter process old-filter)))
+ )
+
+(defun rudel-tls-wait-handshake (process data)
+ "Is installed as process filter on PROCESS while gnutls is doing the TLS handshake."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter))
+ (client-mode))
+
+ ;; Assemble lines that were not generated by gnutls. It is very
+ ;; brittle to wait for last line of gnutls output like, but it
+ ;; cannot be helped.
+ (rudel-loop-lines data line
+ (if client-mode
+ (setq client-data (concat client-data line "\n"))
+ (when (string-match-p "- Compression.*" line)
+ (setq client-mode t))))
+
+ ;; When there are any lines not generated by gnutls, handshake is
+ ;; over. Process the data and install `established' filter
+ ;; function.
+ (when client-data
+ (funcall old-filter process client-data))
+ (when client-mode
+ (message "tls-wait-handshake: switching to \"established\" filter")
+ (set-process-filter process #'rudel-tls-established)
+ (rudel-set-process-object process t :encryption)))
+ )
+
+(defun rudel-tls-established (process data)
+ "Is installed as process filter on PROCESS after gnutls has established TLS encryption."
+ ;; Retrieve complete lines.
+ (let ((buffer (rudel-process-object process :buffer)))
+ (rudel-assemble-line-fragments data buffer)
+ (rudel-set-process-object process buffer :buffer))
+
+ (let ((client-data)
+ (old-filter (rudel-process-object process :old-filter)))
+
+ ;; Assemble lines that were not generated by gnutls.
+ (rudel-loop-lines data line
+ (unless (string-match-p "- Peer has closed the GNUTLS connection" line)
+ (setq client-data (concat client-data line "\n"))))
+
+ ;; When there are any lines not generated by gnutls, pass those to
+ ;; the old filter function.
+ (when client-data
+ (funcall old-filter process client-data)))
+ )
+
+(provide 'rudel-tls)
+;;; rudel-tls.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-transport.el b/emacs.d/lisp/rudel/rudel-transport.el
new file mode 100644
index 0000000..8f0b21d
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-transport.el
@@ -0,0 +1,72 @@
+;;; rudel-transport.el --- Rudel transport interface and backend
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, backend, transport
+;; X-RCS: $Id:$
+;;
+;; 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 3 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, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains the interface for Rudel transport backends.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+
+
+;;; Class rudel-transport
+;;
+
+(defclass rudel-transport ()
+ ()
+ "Interface for transport objects.")
+
+(defgeneric rudel-transport-send ((this rudel-transport) data)
+ "Send DATA through THIS transport object.")
+
+(defgeneric rudel-transport-set-handler ((this rudel-transport)
+ handler)
+ "Install HANDLER as dispatcher for messages received by THIS.")
+
+
+;;; Class rudel-transport-backend
+;;
+
+(defclass rudel-transport-backend (rudel-backend)
+ ()
+ "Interface implemented by transport backends."
+ :abstract t)
+
+(defgeneric rudel-make-connection ((this rudel-transport-backend) info)
+ "Create a transport object according to INFO.")
+
+(defgeneric rudel-wait-for-connections ((this rudel-transport-backend)
+ info)
+ "Create a transport object according to INFO.")
+
+(provide 'rudel-transport)
+;;; rudel-transport.el ends here
diff --git a/emacs.d/lisp/rudel/rudel-util.el b/emacs.d/lisp/rudel/rudel-util.el
new file mode 100644
index 0000000..12a967c
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel-util.el
@@ -0,0 +1,261 @@
+;;; rudel-util.el --- Miscellaneous functions for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, miscellaneous, util
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains miscellaneous functions for Rudel.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+
+(require 'rudel-errors)
+
+
+;;; Errors
+;;
+
+;; rudel-dispatch-error
+
+(intern "rudel-dispatch-error")
+
+(put 'rudel-dispatch-error 'error-conditions
+ '(error
+ rudel-error rudel-dispatch-error))
+
+(put 'rudel-dispatch-error 'error-message
+ "Could not dispatch message to handler")
+
+
+;;; Class rudel-hook-object
+;;
+
+(defclass rudel-hook-object ()
+ ()
+ "Mixin for classes that offer one or more hooks for each of
+their objects.
+
+This idiom is usually called something like signal/slot or
+event/subscription, but for Emacs, the notion of hooks seems more
+appropriate."
+ :abstract t)
+
+(defmethod object-add-hook ((this rudel-hook-object)
+ hook function &optional append)
+ "Add FUNCTION to HOOK for THIS.
+If APPEND is non-nil FUNCTION becomes the last element in the
+list of hooks."
+ (let ((value (slot-value this hook)))
+ (unless (member function value)
+ (set-slot-value this hook
+ (if append (append value (list function))
+ (cons function value)))))
+ )
+
+(defmethod object-remove-hook ((this rudel-hook-object)
+ hook function)
+ "Remove FUNCTION from HOOK for THIS."
+ (set-slot-value this hook
+ (remove function (slot-value this hook))))
+
+(defmethod object-run-hook-with-args ((this rudel-hook-object)
+ hook &rest arguments)
+ "Run HOOK of THIS with arguments ARGUMENTS."
+ (let ((hook (slot-value this hook)))
+ (apply #'run-hook-with-args 'hook this arguments)))
+
+
+;;; Class rudel-socket-owner
+;;
+
+(defclass rudel-socket-owner ()
+ ((socket :initarg :socket
+ :type process
+ :documentation
+ "The process object representing the socket through
+which the communication happens."))
+ "Class rudel-socket-owner ")
+
+(defmethod initialize-instance :after ((this rudel-socket-owner)
+ &rest slots)
+ "Attach THIS to as process object of our socket."
+ ;; Attach to our socket.
+ (with-slots (socket) this
+ (rudel-set-process-object socket this))
+ )
+
+(defmethod rudel-disconnect ((this rudel-socket-owner))
+ "Disconnect the network connection owned by THIS."
+ (with-slots (socket) this
+ (delete-process socket)))
+
+(defmethod rudel-state-change ((this rudel-socket-owner) state message)
+ "Called when the state of THIS changes to STATE.
+MESSAGE is the message emitted when the state transition
+occurred."
+ (with-slots (socket) this
+ (case state
+ ;; Nothing to do here.
+ (run
+ nil)
+
+ ;; Dispatch events which indicate the termination of the
+ ;; connection to `rudel-close'.
+ ((closed failed exit)
+ (rudel-close this))))
+ )
+
+(defmethod rudel-close ((this rudel-socket-owner))
+ "Called when the connection associated to THIS is closed.")
+
+
+;;; Networking helper functions and macros
+;;
+
+(defun rudel-process-object (process &optional key)
+ "Return the object attached to PROCESS using identifier KEY."
+ (unless key
+ (setq key :object))
+ (get (intern (process-name process)) key))
+
+(defun rudel-set-process-object (process object &optional key)
+ "Set object attached to PROCESS using identifier KEY to OBJECT."
+ (unless key
+ (setq key :object))
+ (put (intern (process-name process)) key object))
+
+(defun rudel-filter-dispatch (process data)
+ "Call `rudel-receive' method of object attached to PROCESS with DATA."
+ (let ((object (rudel-process-object process)))
+ (rudel-receive object data)))
+
+(defun rudel-sentinel-dispatch (process message)
+ "Call `rudel-state-change' method of the object attached to PROCESS with state and MESSAGE."
+ (let ((object (rudel-process-object process))
+ (state (process-status process)))
+ (rudel-state-change object state message)))
+
+
+;;; Fragmentation and assembling functions.
+;;
+
+(defmacro rudel-assemble-line-fragments (data storage)
+ "Find an return complete lines in DATA, store excess data in STORAGE.
+If STORAGE is non-nil when calling, consider content as leftover
+data from last and concatenate with DATA before processing."
+ (declare (debug (form form)))
+ (let ((index (make-symbol "index")))
+ `(progn
+ ;; If there are stored fragments, append them to the new data.
+ (when ,storage
+ (setq ,data (concat ,storage ,data))
+ (setq ,storage nil))
+ ;; Try to find a line break in the augmented data.
+ (let ((,index (position ?\n ,data :from-end t)))
+ (unless (and ,index (eq ,index (- (length ,data) 1)))
+ (setq ,storage (if ,index
+ (substring ,data (+ ,index 1))
+ ,data))
+ (setq ,data (when ,index
+ (substring ,data 0 (+ ,index 1))))))
+ ,data))
+ )
+
+(defmacro rudel-loop-lines (data var &rest forms)
+ "Execute FROMS with VAR subsequently bound to all lines in DATA."
+ (declare (indent 2)
+ (debug (form symbolp &rest form)))
+ (let ((lines (make-symbol "lines")))
+ `(when ,data
+ (let ((,lines (split-string ,data "\n" t)))
+ (dolist (,var ,lines)
+ (progn ,@forms)))))
+ )
+
+(defmacro rudel-loop-chunks (data var size &rest forms)
+ "Execute FROMS in a loop with VAR bound to chunks of DATA of SIZE.
+Unless (zerop (mod (length data) size) 0) the final chunk is
+truncated. The expression SIZE is evaluated in each loop unless
+it is a number."
+ (declare (indent 3)
+ (debug (form symbolp numberp &rest form)))
+ ;; If we got a constant number as SIZE, we can check right away.
+ (when (and (numberp size) (<= size 0))
+ (error "Size should be positive"))
+
+ (let ((rest (make-symbol "rest"))
+ (amount (make-symbol "amount"))
+ ;; If SIZE has to be evaluated, we have to check at runtime.
+ (check (unless (numberp size)
+ `((when (<= ,size 0)
+ (error "Size should be positive"))))))
+ `(progn
+ ,@check
+ (let ((,rest ,data)
+ (,var)
+ (,amount))
+ (while (not (string= ,rest ""))
+ (setq ,amount (min (length ,rest) ,size)
+ ,var (substring ,rest 0 ,amount)
+ ,rest (substring ,rest ,amount))
+ (progn ,@forms)))))
+ )
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-dispatch (object prefix name arguments)
+ "Call method (concat PREFIX NAME) of OBJECT with ARGUMENTS.
+If no such method can be found, the condition
+rudel-dispatch-error is signalled."
+ ;; Construct a matching symbol.
+ (let* ((method (intern-soft (concat prefix name))))
+ ;; If we found a suitable method, run it; Otherwise signal.
+ (unless method
+ (signal 'rudel-dispatch-error 'method-symbol-unbound))
+ (condition-case error
+ ;; Try to call METHOD. This can still fail when METHOD is not
+ ;; defined for the class of OBJECT.
+ (apply method object arguments)
+ ;; Only handle a condition 'no-method-definition' that refers to
+ ;; METHOD, otherwise continue unwinding.
+ (no-method-definition
+ (if (eq method (cadr error))
+ (signal 'rudel-dispatch-error 'no-method-for-object)
+ (signal (car error) (cdr error))))))
+ )
+
+(provide 'rudel-util)
+;;; rudel-util.el ends here
diff --git a/emacs.d/lisp/rudel/rudel.el b/emacs.d/lisp/rudel/rudel.el
new file mode 100644
index 0000000..88603fa
--- /dev/null
+++ b/emacs.d/lisp/rudel/rudel.el
@@ -0,0 +1,1012 @@
+;;; rudel.el --- A collaborative editing framework for Emacs
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: rudel, collaboration
+;; URL: http://rudel.sourceforge.net/
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Rudel is a framework for collaborative editing in Emacs. Its
+;; architecture allows communication with arbitrary collaborative
+;; editors.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl))
+
+(require 'eieio)
+(require 'eieio-base)
+
+(require 'eieio-speedbar) ;; TODO required for now
+
+(require 'rudel-util)
+(require 'rudel-backend)
+(require 'rudel-session-initiation)
+(require 'rudel-operations)
+(require 'rudel-operators)
+(require 'rudel-overlay)
+(require 'rudel-hooks)
+(require 'rudel-interactive) ;; for `rudel-read-backend',
+ ;; `rudel-read-document',
+ ;; `rudel-read-session'
+(require 'rudel-icons)
+(require 'rudel-compat) ;; for `read-color' replacement
+
+
+;;; Global variables
+;;
+
+(defconst rudel-version '(0 3)
+ "Version of the Rudel framework.")
+
+(defvar rudel-current-session nil
+ "Global object representing the current Rudel session.
+nil if there is no active session.")
+
+(defvar rudel-buffer-document nil
+ "Buffer-local variable which holds the Rudel document associated with the buffer.")
+(make-variable-buffer-local 'rudel-buffer-document)
+(put 'rudel-buffer-document 'permanent-local t)
+
+(defvar rudel-buffer-change-workaround-data nil
+ "Buffer-local variable which holds change data that could not be accessed otherwise.
+It would be nice to find another way to do this.")
+(make-variable-buffer-local 'rudel-buffer-change-workaround-data)
+(put 'rudel-buffer-change-workaround-data 'permanent-local t)
+
+
+;;; Customization
+;;
+
+(defgroup rudel nil
+ "Rudel collaborative editing framework."
+ :group 'applications)
+
+(defcustom rudel-allocate-buffer-function
+ 'rudel-allocate-buffer-clear-existing
+ "A function used to find or create buffers to associate to documents.
+The function is called with the document name as the sole
+argument and has to return a buffer object which will be attached
+to the document in question."
+ :group 'rudel
+ :type '(choice (const :tag "Clear content of existing buffer"
+ rudel-allocate-buffer-clear-existing )
+ (const :tag "Create a new uniquely named buffer"
+ rudel-allocate-buffer-make-unique )
+ (function :tag "Other function"))
+ :require 'rudel-interactive)
+
+(defcustom rudel-default-username (user-login-name)
+ "*"
+ :group 'rudel
+ :type '(string))
+
+
+;;; Class rudel-session
+;;
+
+(defclass rudel-session (rudel-hook-object)
+ ((backend :initarg :backend
+ :type rudel-backend-child
+ :documentation
+ "The backend used by this session.")
+ (users :initarg :users
+ :type list
+ :initform nil
+ :documentation
+ "The list of users participating in this
+session.")
+ (documents :initarg :documents
+ :type list
+ :initform nil
+ :documentation
+ "This list of documents available in
+this session.")
+ ;; Hooks
+ (end-hook :initarg :end-hook
+ :type list
+ :initform nil
+ :documentation
+ "")
+ (add-user-hook :initarg :add-user-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user gets added
+to the session.
+The arguments are the session and the user object.")
+ (remove-user-hook :initarg :remove-user-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user gets
+removed from the session.
+The arguments are the session and the user object.")
+ (add-document-hook :initarg :add-document-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a document gets
+added to the session.
+The arguments are the session and the document object.")
+ (remove-document-hook :initarg :remove-document-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a document gets
+removed from the session.
+The arguments are the session and the document object."))
+ "This class serves as a base class for rudel-client-session and
+rudel-server-session. Consequently, it consists of slots common
+to client and server sessions."
+ :abstract t)
+
+(defmethod rudel-end ((this rudel-session))
+ "Terminate THIS session performing all necessary cleanup."
+ ;; Run the hook.
+ (object-run-hook-with-args this 'end-hook))
+
+(defmethod rudel-add-user ((this rudel-session) user)
+ "Add USER to the user list of THIS session.
+
+Runs object hook (see `rudel-hook-object') `add-user-hook' with
+arguments THIS and USER."
+ ;; Add USER to list.
+ (object-add-to-list this :users user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'add-user-hook user))
+
+(defmethod rudel-remove-user ((this rudel-session) user)
+ "Remove USER from the user list of THIS session.
+
+Runs object hook (see `rudel-hook-object') `remove-user-hook'
+with arguments THIS and USER."
+ ;; Remove USER from list.
+ (object-remove-from-list this :users user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'remove-user-hook user))
+
+(defmethod rudel-find-user ((this rudel-session)
+ which &optional test key)
+ "Find user WHICH in the user list.
+WHICH is compared to the result of KEY using TEST."
+ (unless test
+ (setq test #'string=))
+ (unless key
+ (setq key #'object-name-string))
+ (with-slots (users) this
+ (find which users :key key :test test))
+ )
+
+(defmethod rudel-add-document ((this rudel-session) document)
+ ""
+ (unless (slot-boundp document :session)
+ (oset document :session this))
+
+ ;; Add DOCUMENT to the list of documents in THIS session.
+ (object-add-to-list this :documents document)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'add-document-hook document))
+
+(defmethod rudel-remove-document ((this rudel-session) document)
+ "Remove DOCUMENT from THIS session, detaching it if necessary."
+ ;; Detach document from its buffer when necessary.
+ (when (rudel-attached-p document)
+ (rudel-detach-from-buffer document))
+
+ ;; Remove DOCUMENT from the list of documents in THIS session.
+ (object-remove-from-list this :documents document)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'remove-document-hook document))
+
+(defmethod rudel-find-document ((this rudel-session)
+ which &optional test key)
+ "Find document WHICH in the document list.
+WHICH is compared to the result of KEY using TEST."
+ (unless test
+ (setq test #'string=))
+ (unless key
+ (setq key #'object-name-string))
+ (with-slots (documents) this
+ (find which documents :key key :test test))
+ )
+
+(defmethod rudel-unsubscribed-documents ((this rudel-session))
+ ""
+ (unless (slot-boundp this :self)
+ (error "Cannot find unsubscribed documents unless slot self is bound"))
+ (with-slots (documents self) this
+ (remove-if
+ (lambda (document)
+ (with-slots (subscribed) document
+ (memq self subscribed)))
+ documents))
+ )
+
+
+;;; Class rudel-client-session
+;;
+(defclass rudel-client-session (rudel-session)
+ ((connection :initarg :connection
+ :type (or null rudel-connection-child)
+ :initform nil
+ :documentation
+ "The connection used for communication by this
+session.")
+ (self :initarg :self
+ :type rudel-user-child
+ :documentation
+ "Points into USERS to the user object representing
+the local user"))
+ "Objects represent a collaborative editing session from a
+client perspective.")
+
+(defmethod rudel-end ((this rudel-client-session))
+ ;; Clean everything up
+ (with-slots (connection users documents) this
+ ;; Detach all documents from their buffers
+ (mapc #'rudel-detach-from-buffer documents)
+
+ ;; Terminate the connection
+ (when connection
+ (condition-case nil
+ (rudel-disconnect connection)
+ (error nil))))
+
+ ;;
+ (when (next-method-p)
+ (call-next-method))
+ )
+
+
+;;; Class rudel-server-session
+;;
+
+(defclass rudel-server-session (rudel-session)
+ ()
+ "Class rudel-server-session "
+ :abstract t)
+
+
+;;; Class rudel-connection
+;;
+
+(defclass rudel-connection ()
+ ((session :initarg :session
+ :type rudel-session-child
+ :documentation
+ ""))
+ "This abstract class defines the interface implementations of
+client protocols have to obey."
+ :abstract t)
+
+(defgeneric rudel-disconnect ((this rudel-connection))
+ "Close the connection.")
+
+(defgeneric rudel-change-color- ((this rudel-connection) color) ;; TODO name
+ "")
+
+(defgeneric rudel-publish ((this rudel-connection) document)
+ "")
+
+(defgeneric rudel-subscribe-to ((this rudel-connection) document)
+ "")
+
+(defgeneric rudel-unsubscribe-from ((this rudel-connection) document) ; TODO name should be rudel-unsubscribe
+ "")
+
+(defgeneric rudel-local-insert ((this rudel-connection))
+ "")
+
+(defgeneric rudel-local-delete ((this rudel-connection))
+ "")
+
+(defgeneric rudel-remote-insert ((this rudel-connection))
+ "")
+
+(defgeneric rudel-remote-delete ((this rudel-connection))
+ "")
+
+
+;;; Class rudel-user
+;;
+
+(defclass rudel-user (eieio-named
+ eieio-speedbar-file-button
+ rudel-hook-object)
+ ((color :initarg :color
+ :accessor rudel-color
+ :documentation
+ "Color used to indicate ownership or authorship
+by the user. Examples includes text written by the user or the
+user name itself.")
+ (change-hook :initarg :change-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when this user object
+changes."))
+ "Objects of this class represent users participating in
+collaborative editing session. Note that a participating user
+does not have to be connected to the session at any given time."
+ :abstract t)
+
+(defmethod rudel-display-string ((this rudel-user)
+ &optional use-images align)
+ "Return a textual representation of THIS for user interface stuff."
+ (with-slots ((name :object-name) color) this
+ (propertize
+ (concat
+ (when use-images
+ (propertize "*" 'display rudel-icon-person))
+ name)
+ 'face (list :background color)))
+ )
+
+
+;;; Class rudel-document
+;;
+
+(defclass rudel-document (eieio-named
+ eieio-speedbar-file-button
+ rudel-hook-object)
+ ((session :initarg :session
+ :type rudel-session
+ :documentation
+ "")
+ (buffer :initarg :buffer
+ :type (or null buffer)
+ :initform nil
+ :documentation
+ "")
+ (subscribed :initarg :subscribed
+ :type list
+ :initform nil
+ :documentation
+ "")
+ ;; Hooks
+ (subscribe-hook :initarg :subscribe-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user subscribes to
+this document object.")
+ (unsubscribe-hook :initarg :unsubscribe-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a user unsubscribes
+from this document object.")
+ (attach-hook :initarg :attach-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when a buffer is attached
+to this document object.")
+ (detach-hook :initarg :detach-hook
+ :type list
+ :initform nil
+ :documentation
+ "This hook is run when the attached buffer
+is detached from this document object."))
+ "This class represents a document, which participants of a
+collaborative editing session can subscribe to."
+ :abstract t)
+
+(defmethod rudel-unique-name ((this rudel-document))
+ "Returns a suggested name for the buffer attached to THIS document."
+ (object-name-string this))
+
+(defmethod rudel-suggested-buffer-name ((this rudel-document))
+ "Returns a suggested name for the buffer attached to THIS document."
+ (rudel-unique-name this))
+
+(defmethod rudel-attached-p ((this rudel-document))
+ (with-slots (buffer) this
+ buffer))
+
+(defmethod rudel-attach-to-buffer ((this rudel-document) buffer)
+ "Attach THIS document to BUFFER"
+ (with-slots ((doc-buffer :buffer)) this
+ ;; Set buffer slot of THIS to BUFFER and associated THIS with
+ ;; BUFFER.
+ (setq doc-buffer buffer)
+ (rudel-set-buffer-document this buffer)
+
+ (with-current-buffer doc-buffer
+ ;; Add the handler function for buffer changes to the buffer's
+ ;; change hook.
+ (add-hook 'after-change-functions
+ #'rudel-handle-buffer-change
+ nil t)
+
+ ;; Store change data before the change a done. This is necessary
+ ;; because the number of bytes (not characters) cannot otherwise
+ ;; be recovered after a deletion.
+ (add-hook 'before-change-functions
+ #'rudel-buffer-change-workaround
+ nil t)
+
+ ;; Add a handler to the kill-buffer hook to unsubscribe from the
+ ;; document when the buffer gets killed.
+ (add-hook 'kill-buffer-hook
+ #'rudel-unpublish-buffer
+ nil t)
+
+ ;;
+ (add-hook 'change-major-mode-hook
+ #'rudel-handle-major-mode-change
+ nil t))
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'attach-hook doc-buffer))
+ )
+
+(defmethod rudel-detach-from-buffer ((this rudel-document))
+ "Detach document THIS from its buffer.
+Do nothing, if THIS is not attached to any buffer."
+ (with-slots (buffer) this
+ (let ((buffer-save buffer))
+
+ ;; Only try to detach from BUFFER, if it is non-nil. BUFFER can
+ ;; be nil, if the user did not subscribe to the document, or
+ ;; unsubscribed after subscribing.
+ (when buffer
+
+ (with-current-buffer buffer
+ ;; Remove our handler function from the kill-buffer hook.
+ (remove-hook 'kill-buffer-hook
+ #'rudel-unpublish-buffer
+ t)
+
+ ;; Remove our handler function from the after-change hook.
+ (remove-hook 'after-change-functions
+ #'rudel-handle-buffer-change
+ t)
+
+ ;; Remove our handler function from the before-change hook.
+ (remove-hook 'before-change-functions
+ #'rudel-buffer-change-workaround
+ t)
+
+ ;; Remove all overlays.
+ (rudel-overlays-remove-all)
+
+ ;; Remove the major mode change handler.
+ (remove-hook 'change-major-mode-hook
+ #'rudel-handle-major-mode-change
+ t))
+
+ ;; Unset buffer slot of THIS and delete association of THIS with
+ ;; BUFFER.
+ (rudel-set-buffer-document nil buffer)
+ (setq buffer nil))
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'detach-hook buffer-save)))
+ )
+
+(defmethod rudel-add-user ((this rudel-document) user)
+ "Add USER to the list of subscribed users of THIS.
+
+Runs object hook (see `rudel-hook-object') `subscribe-hook' with
+arguments THIS and USER."
+ ;; Add USER to list.
+ (object-add-to-list this :subscribed user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'subscribe-hook user))
+
+(defmethod rudel-remove-user ((this rudel-document) user)
+ "Remove USER from the list of subscribed users of THIS.
+
+Runs object hook (see `rudel-hook-object') `unsubscribe-hook'
+with arguments THIS and USER."
+ ;; Remove USER from list.
+ (object-remove-from-list document :subscribed user)
+
+ ;; Run the hook.
+ (object-run-hook-with-args this 'unsubscribe-hook user))
+
+(defmethod rudel-insert ((this rudel-document) position data)
+ "Insert DATA at POSITION into the buffer attached to THIS.
+When POSITION is nil `point-max' is used to determine the
+insertion position.
+Modification hooks are disabled during the insertion."
+ (with-slots (buffer) this
+ (save-excursion
+ (set-buffer buffer)
+
+ (unless position
+ (setq position (- (point-max) 1)))
+
+ (let ((inhibit-modification-hooks t))
+ (goto-char (+ position 1))
+ (insert data))))
+ )
+
+(defmethod rudel-delete ((this rudel-document) position length)
+ "Delete a region of LENGTH character at POSITION from the buffer attached to THIS.
+Modification hooks are disabled during the insertion."
+ (with-slots (buffer) this
+ (save-excursion
+ (set-buffer buffer)
+
+ (let ((inhibit-modification-hooks t))
+ (delete-region (+ position 1) (+ position length 1)))))
+ )
+
+(defmethod rudel-local-operation ((this rudel-document) operation)
+ "Apply the local operation OPERATION to THIS."
+ (with-slots (session buffer) this
+ (with-slots (connection (user :self)) session
+ (dolist (operators (list
+
+ ;; Update overlays
+ (rudel-overlay-operators
+ "overlay-operators"
+ :document this
+ :user user)
+
+ ;; Notify connection
+ (rudel-connection-operators
+ "connection-operators"
+ :connection connection
+ :document this)))
+
+ ;; Apply the operation using each set of operators
+ (rudel-apply operation operators))))
+ )
+
+(defmethod rudel-remote-operation ((this rudel-document) user operation)
+ "Apply the remote operation OPERATION performed by USER to THIS."
+ (dolist (operators (append
+
+ ;; Update buffer contents
+ (list (rudel-document-operators
+ "document-operators"
+ :document this))
+
+ ;; Update overlays
+ (when user
+ (list (rudel-overlay-operators
+ "overlay-operators"
+ :document this
+ :user user)))))
+
+ ;; Apply the operation using each set of operators
+ (rudel-apply operation operators))
+ )
+
+(defmethod rudel-chunks ((this rudel-document))
+ "Return a list of text chunks of the associated buffer.
+Each element in the chunk is a list structured like this (START
+END AUTHOR). START and END are numbers, AUTHOR is of type (or
+null rudel-user-child)."
+ (with-slots (buffer) this
+ ;; Extract buffer string and a list of chunks partitioning the
+ ;; string according to the respective author (or nil).
+ (with-current-buffer buffer
+ (let ((string (buffer-string)) ;; TODO no-properties?
+ (overlay-chunks (mapcar
+ (lambda (overlay)
+ (list (- (overlay-start overlay) 1)
+ (- (overlay-end overlay) 1)
+ (rudel-overlay-user overlay)))
+ (sort* (rudel-author-overlays)
+ '< :key 'overlay-start)))
+ (last)
+ (augmented-chunks))
+
+ ;; Iterate through the list of chunks to find gaps between
+ ;; chunks (also before the first) and insert entries with
+ ;; author nil accordingly.
+ (dolist (chunk overlay-chunks)
+ (when (or (and (not last)
+ (> (nth 0 chunk) 0))
+ (and last
+ (/= (nth 1 last)
+ (nth 0 chunk))))
+ (push (list (if last (nth 1 last) 0)
+ (nth 0 chunk)
+ nil)
+ augmented-chunks))
+ (push chunk augmented-chunks)
+ (setq last chunk))
+
+ ;; If there is text after the last chunk, create another one
+ ;; with author nil. If there were no chunks at all, this chunk
+ ;; can also cover the whole buffer string.
+ (when (or (and (not last)
+ (/= (length string) 0))
+ (and last
+ (/= (nth 1 last) (length string))))
+ (push (list (if last (nth 1 last) 0)
+ (length string)
+ nil)
+ augmented-chunks))
+
+ ;; Sort chunks according to the start position.
+ (sort* augmented-chunks '< :key 'car))))
+ )
+
+
+;;; Buffer-related functions
+;;
+
+(defun rudel-buffer-has-document-p (&optional buffer)
+ "Return non-nil if a document object is attached to BUFFER.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (buffer-local-value 'rudel-buffer-document buffer))
+
+(defun rudel-buffer-document (&optional buffer)
+ "Return the document object attached to BUFFER.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (buffer-local-value 'rudel-buffer-document buffer))
+
+(defun rudel-set-buffer-document (document &optional buffer)
+ "Associate BUFFER to DOCUMENT.
+If DOCUMENT is nil, make it not associated to any buffer.
+If BUFFER is nil, use the current buffer."
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (setq rudel-buffer-document document)))
+
+(defun rudel-handle-buffer-change (from to length)
+ "Handle buffer change at range FROM to TO with length LENGTH by relaying them to the document object of the buffer.
+See after-change-functions for more information."
+ (when (rudel-buffer-has-document-p)
+ (let ((document (rudel-buffer-document))
+ (text)) ; TODO with-rudel-buffer-document?
+ (cond
+ ;; The change was an insert
+ ((and (/= from to)
+ (zerop length))
+ (with-slots (buffer) document
+ (with-current-buffer buffer
+ (setq text (buffer-substring-no-properties from to)))
+ (rudel-local-operation document
+ (rudel-insert-op
+ "insert"
+ :from (- from 1)
+ :data text))))
+
+ ;; The change was a delete
+ ((and (= from to)
+ (not (zerop length)))
+ (rudel-local-operation document
+ (rudel-delete-op
+ "delete"
+ :from (- from 1)
+ :length length)))
+
+ ;; The operation was neither an insert nor a delete. This seems
+ ;; to mean that the region has changed arbitrarily. The only
+ ;; option we have is sending a delete and corresponding insert
+ ;; message that emulate the change.
+ (t
+ (with-slots (buffer) document
+ (with-current-buffer buffer
+ (setq text (buffer-substring-no-properties from to)))
+ (rudel-local-operation document
+ (rudel-delete-op
+ "delete"
+ :from (- from 1)
+ :length length))
+ (rudel-local-operation document
+ (rudel-insert-op
+ "insert"
+ :from (- from 1)
+ :data text)))))))
+ )
+
+(defun rudel-buffer-change-workaround (from to)
+ (when (/= from to)
+ (setq rudel-buffer-change-workaround-data
+ (list from to
+ (buffer-substring-no-properties from to)))))
+
+
+;;; Protection against major mode changes
+;;
+
+(defvar rudel-mode-changed-buffers nil
+ "List of buffers that may need to be repaired after a major
+ mode change.")
+
+(defun rudel-handle-major-mode-change ()
+ "Store the current buffer to repair damage done by major mode change.
+
+Note: The way this works is inspired by mode-local.el by David
+Ponce and Eric M. Ludlam."
+ ;; Store the buffer for later repair.
+ (add-to-list 'rudel-mode-changed-buffers (current-buffer))
+
+ ;; Schedule `rudel-after-major-mode-change' to run after the
+ ;; command, that caused the major mode change.
+ (add-hook 'post-command-hook
+ #'rudel-after-major-mode-change)
+ )
+
+(defun rudel-after-major-mode-change ()
+ "Repair damage done by major mode changes.
+As a function in `post-command-hook', this is run after there was
+a `major-mode' change.
+
+Note: The way this works is inspired by mode-local.el by David
+Ponce and Eric M. Ludlam."
+ ;; Remove this function from `post-command-hook'.
+ (remove-hook 'post-command-hook
+ #'rudel-after-major-mode-change)
+
+ ;; Repair all buffers affected by the major mode change.
+ (dolist (buffer rudel-mode-changed-buffers)
+ (let ((document (buffer-local-value 'rudel-buffer-document
+ buffer)))
+ (rudel-attach-to-buffer document buffer)))
+ )
+
+
+;;; Interactive functions
+;;
+
+;;;###autoload
+(defun rudel-join-session (info)
+ "Join the collaborative editing session described by INFO.
+INFO is a property list that describes the collaborative editing
+session in terms of properties like :host, :port
+and :encryption. The particular properties and their respective
+meanings depend on the used backend.
+
+When called interactively, all data required to join a session
+will be prompted for."
+ (interactive
+ ;; Try the discover method of session initiation backends to find
+ ;; available sessions.
+ (list
+ (let ((info)
+ (session-initiation-backend))
+ (while (not info)
+ (message "Discovering Sessions ...")
+ (let* ((sessions (rudel-session-initiation-discover
+ session-initiation-backend))
+ (maybe-info (if (= (length sessions) 1)
+ (car sessions)
+ (rudel-read-session
+ sessions "Choose Session: " 'object))))
+ (if (rudel-backend-cons-p maybe-info)
+ (setq session-initiation-backend (car maybe-info))
+ (setq info maybe-info))))
+ info)))
+
+ ;; First, create the session object.
+ (let* ((backend (cdr (plist-get info :backend)))
+ (session (rudel-client-session
+ (plist-get info :name)
+ :backend backend))
+ (connection))
+ ;; Give the backend a chance to collect remaining connect
+ ;; info. For session initiation methods like Zeroconf, we have the
+ ;; _connection_ info, but are still missing the username and
+ ;; stuff.
+ (setq info (rudel-ask-connect-info backend info))
+
+ ;; Add the session object to the connect information.
+ (plist-put info :session session)
+
+ ;; Ask BACKEND to connect using INFO. Do not catch errors since
+ ;; the error messages are probably the best feedback we can give.
+ (setq connection (rudel-connect backend info))
+
+ ;; Set the connection slot of the session object and store it
+ ;; globally.
+ (oset session :connection connection)
+ (setq rudel-current-session session)
+
+ ;; Reset the global session variable when the session ends.
+ (object-add-hook session 'end-hook
+ (lambda (session)
+ (setq rudel-current-session nil)))
+
+ ;; Run the hook.
+ (run-hook-with-args 'rudel-session-start-hook session))
+ )
+
+;;;###autoload
+(defun rudel-host-session ()
+ "Host a collaborative editing session.
+All data required to host a session will be prompted for
+interactively."
+ (interactive)
+ ;; If necessary, ask the user for the backend we should use.
+ (let* ((backend (cdr (rudel-backend-choose
+ 'protocol
+ (lambda (backend)
+ (rudel-capable-of-p backend 'host)))))
+ (info (rudel-ask-host-info backend))
+ (server))
+
+ ;; Try to create the server
+ (condition-case error-data
+ (setq server (rudel-host backend info))
+ ('error
+ (error "Could not host session using backend `%s' with %s: %s"
+ (object-name-string backend)
+ info
+ (car error-data))))
+ server))
+
+;;;###autoload
+(defun rudel-end-session ()
+ "End the current collaborative editing session."
+ (interactive)
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ ;; Actually end the session.
+ (rudel-end rudel-current-session)
+ )
+
+;;;###autoload
+(defun rudel-change-color ()
+ "Change the color associated with the local user.
+Not all backends support this operation."
+ (interactive)
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (with-slots (backend connection self) rudel-current-session
+ ;; Make sure the backend can change colors.
+ (unless (rudel-capable-of-p backend 'change-color)
+ (error "Backend `%s' cannot change colors"
+ (object-name-string backend)))
+
+ (with-slots ((name :object-name) color) self
+ ;; Ask the user for a new color.
+ (setq color (read-color "New Color: " t))
+
+ ;; Tell the connection to announce the change and change it in
+ ;; our user object.
+ (rudel-change-color- connection color)
+
+ ;; Run the change hook.
+ (object-run-hook-with-args self 'change-hook)
+
+ ;; Update overlay color.
+ (rudel-overlay-set-face-attributes
+ (rudel-overlay-make-face-symbol 'author name)
+ color)))
+ )
+
+;;;###autoload
+(defun rudel-subscribe (document)
+ "Subscribe to DOCUMENT offered by a peer in a collaborative editing session.
+When called interactively, DOCUMENT is prompted for interactively."
+ (interactive
+ (list (progn
+ ;; We have to retrieve the document list from an active
+ ;; session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+ ;; Select unsubscribed documents.
+ (let ((documents (rudel-unsubscribed-documents
+ rudel-current-session)))
+ ;; Already subscribed to all documents. This is an error.
+ (when (null documents)
+ (error "No unsubscribed documents"))
+ ;; Read an unsubscribed document.
+ (rudel-read-document documents nil 'object)))))
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ ;; Create a new buffer and attach the document to it.
+ (let* ((name (rudel-suggested-buffer-name document))
+ (buffer (funcall rudel-allocate-buffer-function name)))
+ (rudel-attach-to-buffer document buffer)
+
+ (let ((connection (oref (oref document :session) :connection)))
+ (rudel-subscribe-to connection document))
+
+ ;; Show the new buffer.
+ (set-window-buffer nil buffer))
+ )
+
+;;;###autoload
+(defun rudel-publish-buffer (&optional buffer)
+ "Make the BUFFER available for subscription to peers in a collaborative editing session.
+If BUFFER is nil, the current buffer is used."
+ (interactive (list nil))
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (when (rudel-buffer-has-document-p)
+ (error "Buffer already published or subscribed"))) ; TODO keep this?
+
+ ;;
+ (with-slots (backend connection self) rudel-current-session
+ (let ((document (rudel-make-document backend
+ (buffer-name buffer)
+ rudel-current-session)))
+ (rudel-add-document rudel-current-session document)
+
+ (rudel-attach-to-buffer document buffer)
+ (object-add-to-list document :subscribed self)
+
+ (rudel-publish connection document)))
+ )
+
+;;;###autoload
+(defun rudel-unpublish-buffer (&optional buffer)
+ "Deny peers access to BUFFER in a collaborative editing session.
+If BUFFER is nil, the current is used."
+ (interactive)
+
+ ;; Make sure we have a session.
+ (unless rudel-current-session
+ (error "No active Rudel session"))
+
+ (unless buffer
+ (setq buffer (current-buffer)))
+
+ (with-current-buffer buffer
+ (unless (rudel-buffer-has-document-p)
+ (error "Buffer is not published")))
+
+ ;;
+ (with-slots (connection) rudel-current-session
+ (let ((document (rudel-buffer-document buffer)))
+ (rudel-detach-from-buffer document)
+
+ (rudel-unsubscribe-from connection document)))
+ )
+
+(provide 'rudel)
+;;; rudel.el ends here
diff --git a/emacs.d/lisp/rudel/telepathy/.svn/all-wcprops b/emacs.d/lisp/rudel/telepathy/.svn/all-wcprops
new file mode 100644
index 0000000..e89bd10
--- /dev/null
+++ b/emacs.d/lisp/rudel/telepathy/.svn/all-wcprops
@@ -0,0 +1,11 @@
+K 25
+svn:wc:ra_dav:version-url
+V 43
+/svnroot/rudel/!svn/ver/301/trunk/telepathy
+END
+rudel-telepathy.el
+K 25
+svn:wc:ra_dav:version-url
+V 62
+/svnroot/rudel/!svn/ver/301/trunk/telepathy/rudel-telepathy.el
+END
diff --git a/emacs.d/lisp/rudel/telepathy/.svn/entries b/emacs.d/lisp/rudel/telepathy/.svn/entries
new file mode 100644
index 0000000..ee21fde
--- /dev/null
+++ b/emacs.d/lisp/rudel/telepathy/.svn/entries
@@ -0,0 +1,62 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/telepathy
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-03T01:27:08.697881Z
+301
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+rudel-telepathy.el
+file
+
+
+
+
+2009-11-18T14:01:46.000000Z
+d4713da73fb5f147e0c7afcbcdb269b9
+2009-10-03T01:27:08.697881Z
+301
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1882
+
diff --git a/emacs.d/lisp/rudel/telepathy/.svn/text-base/rudel-telepathy.el.svn-base b/emacs.d/lisp/rudel/telepathy/.svn/text-base/rudel-telepathy.el.svn-base
new file mode 100644
index 0000000..3d41643
--- /dev/null
+++ b/emacs.d/lisp/rudel/telepathy/.svn/text-base/rudel-telepathy.el.svn-base
@@ -0,0 +1,76 @@
+;;; rudel-telepathy.el --- A telepathy backend for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, telepathy, backend
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel backend which realizes session
+;; initiation and transport of Rudel data through freedesktop's
+;; Telepathy framework.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+(require 'rudel-transport)
+
+
+;;; Constants
+;;
+
+(defconst rudel-telepathy-version '(0 1)
+ "Version of the telepathy backend for Rudel.")
+
+
+;;; Class rudel-telepathy-backend
+;;
+
+(defclass rudel-telepathy-backend (rudel-transport-backend)
+ ((capabilities :initform '()))
+ "Class rudel-telepathy-backend ")
+
+(defmethod initialize-instance ((this rudel-telepathy-backend) &rest slots)
+ "Initialize slots of THIS according to SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-telepathy-version))
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'transport)
+ 'telepathy 'rudel-telepathy-backend)
+
+(provide 'rudel-telepathy)
+;;; rudel-telepathy.el ends here
diff --git a/emacs.d/lisp/rudel/telepathy/rudel-telepathy.el b/emacs.d/lisp/rudel/telepathy/rudel-telepathy.el
new file mode 100644
index 0000000..3d41643
--- /dev/null
+++ b/emacs.d/lisp/rudel/telepathy/rudel-telepathy.el
@@ -0,0 +1,76 @@
+;;; rudel-telepathy.el --- A telepathy backend for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, telepathy, backend
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel backend which realizes session
+;; initiation and transport of Rudel data through freedesktop's
+;; Telepathy framework.
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(require 'eieio)
+
+(require 'rudel-backend)
+(require 'rudel-transport)
+
+
+;;; Constants
+;;
+
+(defconst rudel-telepathy-version '(0 1)
+ "Version of the telepathy backend for Rudel.")
+
+
+;;; Class rudel-telepathy-backend
+;;
+
+(defclass rudel-telepathy-backend (rudel-transport-backend)
+ ((capabilities :initform '()))
+ "Class rudel-telepathy-backend ")
+
+(defmethod initialize-instance ((this rudel-telepathy-backend) &rest slots)
+ "Initialize slots of THIS according to SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-telepathy-version))
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'transport)
+ 'telepathy 'rudel-telepathy-backend)
+
+(provide 'rudel-telepathy)
+;;; rudel-telepathy.el ends here
diff --git a/emacs.d/lisp/rudel/wave/.svn/all-wcprops b/emacs.d/lisp/rudel/wave/.svn/all-wcprops
new file mode 100644
index 0000000..5430a3f
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 38
+/svnroot/rudel/!svn/ver/345/trunk/wave
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 50
+/svnroot/rudel/!svn/ver/291/trunk/wave/Project.ede
+END
+rudel-wave.el
+K 25
+svn:wc:ra_dav:version-url
+V 52
+/svnroot/rudel/!svn/ver/291/trunk/wave/rudel-wave.el
+END
diff --git a/emacs.d/lisp/rudel/wave/.svn/entries b/emacs.d/lisp/rudel/wave/.svn/entries
new file mode 100644
index 0000000..537adf3
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/wave
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-03T02:03:51.626714Z
+345
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+74bbb6356abac34a5aa8305ff84a2631
+2009-10-03T01:23:04.047285Z
+291
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+265
+
+rudel-wave.el
+file
+
+
+
+
+2009-11-18T14:01:45.000000Z
+b53a8ef79d48d009a10a0b013e2c69a5
+2009-10-03T01:23:04.047285Z
+291
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1833
+
diff --git a/emacs.d/lisp/rudel/wave/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/wave/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..af39c6f
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,14 @@
+;; Object rudel/wave
+;; EDE project file.
+(ede-proj-project "rudel/wave"
+ :name "wave"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "wave"
+ :name "wave"
+ :path ""
+ :source '("rudel-wave.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/wave/.svn/text-base/rudel-wave.el.svn-base b/emacs.d/lisp/rudel/wave/.svn/text-base/rudel-wave.el.svn-base
new file mode 100644
index 0000000..f8e0555
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/.svn/text-base/rudel-wave.el.svn-base
@@ -0,0 +1,77 @@
+;;; rudel-wave.el --- A Wave backend for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, Wave protocol, backend
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel protocol backend, which implements the
+;; Wave client protocol.
+
+
+;;; History:
+;;
+;; 0.1 - Initial version
+
+
+;;; Code:
+;;
+
+(require 'rudel-backend)
+(require 'rudel-protocol)
+
+
+;;; Constants
+;;
+
+(defconst rudel-wave-version '(0 1)
+ "Version of the wave backend for Rudel.")
+
+
+;;; Class rudel-wave-backend
+;;
+
+;;;###autoload
+(defclass rudel-wave-backend (rudel-protocol-backend)
+ ((capabilities :initform '(join
+ chat
+ track-subscriptions)))
+ "Main class of the Rudel Wave backend. Creates wave client
+connections.")
+
+(defmethod initialize-instance ((this rudel-wave-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-wave-version))
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'protocol)
+ 'wave 'rudel-wave-backend)
+
+(provide 'rudel-wave)
+;;; rudel-wave.el ends here
diff --git a/emacs.d/lisp/rudel/wave/Project.ede b/emacs.d/lisp/rudel/wave/Project.ede
new file mode 100644
index 0000000..af39c6f
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/Project.ede
@@ -0,0 +1,14 @@
+;; Object rudel/wave
+;; EDE project file.
+(ede-proj-project "rudel/wave"
+ :name "wave"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "wave"
+ :name "wave"
+ :path ""
+ :source '("rudel-wave.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/wave/rudel-wave.el b/emacs.d/lisp/rudel/wave/rudel-wave.el
new file mode 100644
index 0000000..f8e0555
--- /dev/null
+++ b/emacs.d/lisp/rudel/wave/rudel-wave.el
@@ -0,0 +1,77 @@
+;;; rudel-wave.el --- A Wave backend for Rudel
+;;
+;; Copyright (C) 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, Wave protocol, backend
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; This file contains a Rudel protocol backend, which implements the
+;; Wave client protocol.
+
+
+;;; History:
+;;
+;; 0.1 - Initial version
+
+
+;;; Code:
+;;
+
+(require 'rudel-backend)
+(require 'rudel-protocol)
+
+
+;;; Constants
+;;
+
+(defconst rudel-wave-version '(0 1)
+ "Version of the wave backend for Rudel.")
+
+
+;;; Class rudel-wave-backend
+;;
+
+;;;###autoload
+(defclass rudel-wave-backend (rudel-protocol-backend)
+ ((capabilities :initform '(join
+ chat
+ track-subscriptions)))
+ "Main class of the Rudel Wave backend. Creates wave client
+connections.")
+
+(defmethod initialize-instance ((this rudel-wave-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-wave-version))
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'protocol)
+ 'wave 'rudel-wave-backend)
+
+(provide 'rudel-wave)
+;;; rudel-wave.el ends here
diff --git a/emacs.d/lisp/rudel/zeroconf/.svn/all-wcprops b/emacs.d/lisp/rudel/zeroconf/.svn/all-wcprops
new file mode 100644
index 0000000..f660614
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/.svn/all-wcprops
@@ -0,0 +1,17 @@
+K 25
+svn:wc:ra_dav:version-url
+V 42
+/svnroot/rudel/!svn/ver/345/trunk/zeroconf
+END
+Project.ede
+K 25
+svn:wc:ra_dav:version-url
+V 54
+/svnroot/rudel/!svn/ver/260/trunk/zeroconf/Project.ede
+END
+rudel-zeroconf.el
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/rudel/!svn/ver/260/trunk/zeroconf/rudel-zeroconf.el
+END
diff --git a/emacs.d/lisp/rudel/zeroconf/.svn/entries b/emacs.d/lisp/rudel/zeroconf/.svn/entries
new file mode 100644
index 0000000..3ab3d1c
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/.svn/entries
@@ -0,0 +1,96 @@
+10
+
+dir
+545
+https://rudel.svn.sourceforge.net/svnroot/rudel/trunk/zeroconf
+https://rudel.svn.sourceforge.net/svnroot/rudel
+
+
+
+2009-10-03T02:03:51.626714Z
+345
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+694b31df-dcbb-44e8-af88-74c7ea918228
+
+Project.ede
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+5d5760fd4535be2a6e18cc9c42334b05
+2009-10-03T01:06:09.107570Z
+260
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+286
+
+rudel-zeroconf.el
+file
+
+
+
+
+2009-11-18T14:01:44.000000Z
+deed32ca24d718009bd1137e49439fc0
+2009-10-03T01:06:09.107570Z
+260
+scymtym
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+7370
+
diff --git a/emacs.d/lisp/rudel/zeroconf/.svn/text-base/Project.ede.svn-base b/emacs.d/lisp/rudel/zeroconf/.svn/text-base/Project.ede.svn-base
new file mode 100644
index 0000000..7bee2d0
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/.svn/text-base/Project.ede.svn-base
@@ -0,0 +1,14 @@
+;; Object rudel/obby
+;; EDE project file.
+(ede-proj-project "rudel/zeroconf"
+ :name "zeroconf"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "zeroconf"
+ :name "zeroconf"
+ :path ""
+ :source '("rudel-zeroconf.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/zeroconf/.svn/text-base/rudel-zeroconf.el.svn-base b/emacs.d/lisp/rudel/zeroconf/.svn/text-base/rudel-zeroconf.el.svn-base
new file mode 100644
index 0000000..01ffc0d
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/.svn/text-base/rudel-zeroconf.el.svn-base
@@ -0,0 +1,253 @@
+;;; rudel-zeroconf.el --- Zeroconf support for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, service, discovery, advertising, zeroconf,
+;; rendezvous, avahi
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Zeroconf session discovery and advertising for Rudel. The main
+;; class `rudel-zeroconf-backend' implements discovery and advertising
+;; for registered service types. Service types are registered by
+;; adding an element of the form (SERVICE BACKEND) to the
+;; `rudel-zeroconf-service-types'. BACKEND is the symbol of the
+;; protocol backend and SERVICE is the string used as service type in
+;; the Zeroconf record (example: '("_lobby._tcp" obby)).
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl)) ;; first, second
+
+(require 'zeroconf)
+
+(require 'rudel-backend)
+(require 'rudel-session-initiation)
+
+
+;;; Constants and global variables
+;;
+
+(defconst rudel-zeroconf-version '(0 1)
+ "Version of the Zeroconf backend for Rudel.")
+
+(defvar rudel-zeroconf-service-types nil
+ "Service types used by Rudel backends.
+Each element is of the form (SERVICE BACKEND).")
+
+
+;;; Accessors and manipulators for the service list
+;;
+
+(defalias 'rudel-zeroconf-service-type 'first
+ "Return type of service.")
+
+(defalias 'rudel-zeroconf-service-backend 'second
+ "Return backend associated with service type.")
+
+(defun rudel-zeroconf-service (key which)
+ "Return the Zeroconf service type used by BACKEND."
+ (find which rudel-zeroconf-service-types
+ :key key :test (if (eq key 'rudel-zeroconf-service-type)
+ #'string= #'eq)))
+
+;;;###autoload
+(defun rudel-zeroconf-register-service (type backend)
+ "Add an entry for TYPE with BACKEND to the list of service types.
+BACKEND is the name of the protocol backend handling the service
+type TYPE."
+ (push (list type backend)
+ rudel-zeroconf-service-types))
+
+
+;;; Initialization
+;;
+
+(message "Initializing Zeroconf ...")
+(zeroconf-init)
+
+
+;;; Class rudel-zeroconf-backend
+;;
+
+;;;###autoload
+(defclass rudel-zeroconf-backend (rudel-session-initiation-backend)
+ ((capabilities :initform (discover advertise))
+ (priority :initform primary))
+ "")
+
+(defmethod initialize-instance ((this rudel-zeroconf-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-zeroconf-version))
+
+(defmethod rudel-discover ((this rudel-zeroconf-backend))
+ "Return a list of session information property lists for Zeroconf-advertised sessions."
+ (mapcar
+ #'rudel-zeroconf-service->plist
+ (remove-if
+ #'null
+ (mapcar
+ #'zeroconf-resolve-service
+ (apply
+ #'append
+ (mapcar
+ #'rudel-zeroconf-services
+ (mapcar #'rudel-zeroconf-service-backend
+ rudel-zeroconf-service-types))))))
+ )
+
+(defmethod rudel-advertise ((this rudel-session-initiation-backend) info)
+ "Use Zeroconf to advertise the session described by INFO to other users."
+ (let ((name (plist-get info :name))
+ (backend (plist-get info :backend))
+ (host (plist-get info :host))
+ (port (plist-get info :port))
+ (data (plist-get info :data)))
+ (when backend
+ (apply #'rudel-zeroconf-publish
+ backend name host port data)))
+ t)
+
+(defmethod rudel-withdraw ((this rudel-session-initiation-backend))
+ "Withdraw Zeroconf record."
+ (error "Not implemented, yet"))
+
+
+;;; Zeroconf wrapper functions
+;;
+
+(defun rudel-zeroconf-services (backend)
+ "List Zeroconf services for BACKEND."
+ (zeroconf-list-services
+ (rudel-zeroconf-service-type
+ (rudel-zeroconf-service
+ #'rudel-zeroconf-service-backend backend))))
+
+(defun rudel-zeroconf-services-present-p (backend)
+ "Check whether there are Zeroconf services for BACKEND."
+ (rudel-zeroconf-services backend))
+
+(defun rudel-zeroconf-publish (backend name host port &rest data)
+ "Publish BACKEND service NAME for HOST and PORT."
+ ;; Try to find the service entry for the protocol backend and
+ ;; publish the service if an entry is found.
+ (let ((service (rudel-zeroconf-service
+ #'rudel-zeroconf-service-backend backend)))
+ (when service
+ (zeroconf-publish-service
+ name
+ (rudel-zeroconf-service-type service)
+ "local"
+ (concat host ".local")
+ port
+ "" ; address
+ (mapcar
+ (lambda (item)
+ (concat (car item) "=" (cdr item)))
+ data)
+ )))
+ )
+
+(defun rudel-zeroconf-withdraw (backend name)
+ "Withdraw service NAME for BACKEND."
+ (error "Not implemented, yet"))
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-zeroconf-service->plist (service)
+ "Convert a Zeroconf service record to an info property list."
+ (let* ((type (zeroconf-service-type service))
+ (data (rudel-zeroconf-parse-txt-record
+ (zeroconf-service-txt service)))
+ (service-type (rudel-zeroconf-service
+ #'rudel-zeroconf-service-type type)))
+ ;; Construct information property list.
+ (list
+ :name (format "Zeroconf advertised session \"%s\""
+ (zeroconf-service-name service))
+ :backend (rudel-backend-get
+ 'protocol
+ (rudel-zeroconf-service-backend service-type))
+ :host (zeroconf-service-host service)
+ :port (zeroconf-service-port service)
+ ;; Encryption defaults to yes to be compatible with Gobby.
+ :encryption (or (not (member :encryption data))
+ (string= (plist-get data :encryption)
+ "yes"))))
+ )
+
+(defun rudel-zeroconf-parse-txt-record (record)
+ "Parse RECORD into a property list of keys and values."
+ (apply #'append
+ (mapcar
+ (lambda (entry)
+ (multiple-value-bind (key value) (split-string entry "=")
+ (list (intern (concat ":" key))
+ value)))
+ record))
+ )
+
+
+;;; User interaction
+;;
+
+(defun rudel-zeroconf-read-service (backend)
+ "Retrieve services for BACKEND and read one from user."
+ ;; First, find all matching services for the backend.
+ (let* ((services (rudel-zeroconf-services backend))
+ ;; Read one of the names of these services.
+ (service-name (completing-read
+ "Service: "
+ (mapcar #'zeroconf-service-name services)
+ nil t))
+ ;; Retrieve and resolve the selected service object.
+ (service (find service-name services
+ :key #'zeroconf-service-name
+ :test #'string=))
+ (service-resolved (zeroconf-resolve-service service)))
+ ;; Return host and port
+ (list (zeroconf-service-host service-resolved)
+ (zeroconf-service-port service-resolved)))
+ )
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'zeroconf 'rudel-zeroconf-backend)
+
+(provide 'rudel-zeroconf)
+;;; rudel-zeroconf.el ends here
diff --git a/emacs.d/lisp/rudel/zeroconf/Project.ede b/emacs.d/lisp/rudel/zeroconf/Project.ede
new file mode 100644
index 0000000..7bee2d0
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/Project.ede
@@ -0,0 +1,14 @@
+;; Object rudel/obby
+;; EDE project file.
+(ede-proj-project "rudel/zeroconf"
+ :name "zeroconf"
+ :file "Project.ede"
+ :targets (list
+ (ede-proj-target-elisp "zeroconf"
+ :name "zeroconf"
+ :path ""
+ :source '("rudel-zeroconf.el")
+ :aux-packages '("rudel")
+ )
+ )
+ )
diff --git a/emacs.d/lisp/rudel/zeroconf/rudel-zeroconf.el b/emacs.d/lisp/rudel/zeroconf/rudel-zeroconf.el
new file mode 100644
index 0000000..01ffc0d
--- /dev/null
+++ b/emacs.d/lisp/rudel/zeroconf/rudel-zeroconf.el
@@ -0,0 +1,253 @@
+;;; rudel-zeroconf.el --- Zeroconf support for Rudel
+;;
+;; Copyright (C) 2008, 2009 Jan Moringen
+;;
+;; Author: Jan Moringen <scymtym@users.sourceforge.net>
+;; Keywords: Rudel, service, discovery, advertising, zeroconf,
+;; rendezvous, avahi
+;; X-RCS: $Id:$
+;;
+;; This file is part of Rudel.
+;;
+;; Rudel 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 3 of the License, or
+;; (at your option) any later version.
+;;
+;; Rudel 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 Rudel. If not, see <http://www.gnu.org/licenses>.
+
+
+;;; Commentary:
+;;
+;; Zeroconf session discovery and advertising for Rudel. The main
+;; class `rudel-zeroconf-backend' implements discovery and advertising
+;; for registered service types. Service types are registered by
+;; adding an element of the form (SERVICE BACKEND) to the
+;; `rudel-zeroconf-service-types'. BACKEND is the symbol of the
+;; protocol backend and SERVICE is the string used as service type in
+;; the Zeroconf record (example: '("_lobby._tcp" obby)).
+
+
+;;; History:
+;;
+;; 0.1 - Initial revision.
+
+
+;;; Code:
+;;
+
+(eval-when-compile
+ (require 'cl)) ;; first, second
+
+(require 'zeroconf)
+
+(require 'rudel-backend)
+(require 'rudel-session-initiation)
+
+
+;;; Constants and global variables
+;;
+
+(defconst rudel-zeroconf-version '(0 1)
+ "Version of the Zeroconf backend for Rudel.")
+
+(defvar rudel-zeroconf-service-types nil
+ "Service types used by Rudel backends.
+Each element is of the form (SERVICE BACKEND).")
+
+
+;;; Accessors and manipulators for the service list
+;;
+
+(defalias 'rudel-zeroconf-service-type 'first
+ "Return type of service.")
+
+(defalias 'rudel-zeroconf-service-backend 'second
+ "Return backend associated with service type.")
+
+(defun rudel-zeroconf-service (key which)
+ "Return the Zeroconf service type used by BACKEND."
+ (find which rudel-zeroconf-service-types
+ :key key :test (if (eq key 'rudel-zeroconf-service-type)
+ #'string= #'eq)))
+
+;;;###autoload
+(defun rudel-zeroconf-register-service (type backend)
+ "Add an entry for TYPE with BACKEND to the list of service types.
+BACKEND is the name of the protocol backend handling the service
+type TYPE."
+ (push (list type backend)
+ rudel-zeroconf-service-types))
+
+
+;;; Initialization
+;;
+
+(message "Initializing Zeroconf ...")
+(zeroconf-init)
+
+
+;;; Class rudel-zeroconf-backend
+;;
+
+;;;###autoload
+(defclass rudel-zeroconf-backend (rudel-session-initiation-backend)
+ ((capabilities :initform (discover advertise))
+ (priority :initform primary))
+ "")
+
+(defmethod initialize-instance ((this rudel-zeroconf-backend) &rest slots)
+ "Initialize slots of THIS with SLOTS."
+ (when (next-method-p)
+ (call-next-method))
+
+ (oset this :version rudel-zeroconf-version))
+
+(defmethod rudel-discover ((this rudel-zeroconf-backend))
+ "Return a list of session information property lists for Zeroconf-advertised sessions."
+ (mapcar
+ #'rudel-zeroconf-service->plist
+ (remove-if
+ #'null
+ (mapcar
+ #'zeroconf-resolve-service
+ (apply
+ #'append
+ (mapcar
+ #'rudel-zeroconf-services
+ (mapcar #'rudel-zeroconf-service-backend
+ rudel-zeroconf-service-types))))))
+ )
+
+(defmethod rudel-advertise ((this rudel-session-initiation-backend) info)
+ "Use Zeroconf to advertise the session described by INFO to other users."
+ (let ((name (plist-get info :name))
+ (backend (plist-get info :backend))
+ (host (plist-get info :host))
+ (port (plist-get info :port))
+ (data (plist-get info :data)))
+ (when backend
+ (apply #'rudel-zeroconf-publish
+ backend name host port data)))
+ t)
+
+(defmethod rudel-withdraw ((this rudel-session-initiation-backend))
+ "Withdraw Zeroconf record."
+ (error "Not implemented, yet"))
+
+
+;;; Zeroconf wrapper functions
+;;
+
+(defun rudel-zeroconf-services (backend)
+ "List Zeroconf services for BACKEND."
+ (zeroconf-list-services
+ (rudel-zeroconf-service-type
+ (rudel-zeroconf-service
+ #'rudel-zeroconf-service-backend backend))))
+
+(defun rudel-zeroconf-services-present-p (backend)
+ "Check whether there are Zeroconf services for BACKEND."
+ (rudel-zeroconf-services backend))
+
+(defun rudel-zeroconf-publish (backend name host port &rest data)
+ "Publish BACKEND service NAME for HOST and PORT."
+ ;; Try to find the service entry for the protocol backend and
+ ;; publish the service if an entry is found.
+ (let ((service (rudel-zeroconf-service
+ #'rudel-zeroconf-service-backend backend)))
+ (when service
+ (zeroconf-publish-service
+ name
+ (rudel-zeroconf-service-type service)
+ "local"
+ (concat host ".local")
+ port
+ "" ; address
+ (mapcar
+ (lambda (item)
+ (concat (car item) "=" (cdr item)))
+ data)
+ )))
+ )
+
+(defun rudel-zeroconf-withdraw (backend name)
+ "Withdraw service NAME for BACKEND."
+ (error "Not implemented, yet"))
+
+
+;;; Miscellaneous functions
+;;
+
+(defun rudel-zeroconf-service->plist (service)
+ "Convert a Zeroconf service record to an info property list."
+ (let* ((type (zeroconf-service-type service))
+ (data (rudel-zeroconf-parse-txt-record
+ (zeroconf-service-txt service)))
+ (service-type (rudel-zeroconf-service
+ #'rudel-zeroconf-service-type type)))
+ ;; Construct information property list.
+ (list
+ :name (format "Zeroconf advertised session \"%s\""
+ (zeroconf-service-name service))
+ :backend (rudel-backend-get
+ 'protocol
+ (rudel-zeroconf-service-backend service-type))
+ :host (zeroconf-service-host service)
+ :port (zeroconf-service-port service)
+ ;; Encryption defaults to yes to be compatible with Gobby.
+ :encryption (or (not (member :encryption data))
+ (string= (plist-get data :encryption)
+ "yes"))))
+ )
+
+(defun rudel-zeroconf-parse-txt-record (record)
+ "Parse RECORD into a property list of keys and values."
+ (apply #'append
+ (mapcar
+ (lambda (entry)
+ (multiple-value-bind (key value) (split-string entry "=")
+ (list (intern (concat ":" key))
+ value)))
+ record))
+ )
+
+
+;;; User interaction
+;;
+
+(defun rudel-zeroconf-read-service (backend)
+ "Retrieve services for BACKEND and read one from user."
+ ;; First, find all matching services for the backend.
+ (let* ((services (rudel-zeroconf-services backend))
+ ;; Read one of the names of these services.
+ (service-name (completing-read
+ "Service: "
+ (mapcar #'zeroconf-service-name services)
+ nil t))
+ ;; Retrieve and resolve the selected service object.
+ (service (find service-name services
+ :key #'zeroconf-service-name
+ :test #'string=))
+ (service-resolved (zeroconf-resolve-service service)))
+ ;; Return host and port
+ (list (zeroconf-service-host service-resolved)
+ (zeroconf-service-port service-resolved)))
+ )
+
+
+;;; Autoloading
+;;
+
+;;;###autoload
+(rudel-add-backend (rudel-backend-get-factory 'session-initiation)
+ 'zeroconf 'rudel-zeroconf-backend)
+
+(provide 'rudel-zeroconf)
+;;; rudel-zeroconf.el ends here