summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile130
-rw-r--r--docs/_static/agogo.css452
-rw-r--r--docs/_static/basic.css532
-rw-r--r--docs/_static/default.css256
-rw-r--r--docs/_static/fonts/Museo_Slab_500.otfbin0 -> 62180 bytes
-rw-r--r--docs/_static/fonts/Museo_Slab_500italic.otfbin0 -> 66376 bytes
-rw-r--r--docs/_static/fonts/OFLGoudyStMTT-Italic.ttfbin0 -> 161252 bytes
-rw-r--r--docs/_static/fonts/OFLGoudyStMTT.ttfbin0 -> 173520 bytes
-rw-r--r--docs/_static/fonts/YanoneKaffeesatz-Bold.ttfbin0 -> 121352 bytes
-rw-r--r--docs/_static/fonts/YanoneKaffeesatz-Light.ttfbin0 -> 129136 bytes
-rw-r--r--docs/_static/fonts/YanoneKaffeesatz-Regular.ttfbin0 -> 128564 bytes
-rw-r--r--docs/_static/fonts/YanoneKaffeesatz-Thin.ttfbin0 -> 129060 bytes
-rw-r--r--docs/_static/haiku.css406
-rw-r--r--docs/_static/header.pngbin0 -> 16588 bytes
-rw-r--r--docs/_static/images/arch_layers.pngbin0 -> 27645 bytes
-rw-r--r--docs/_static/ir_black.css70
-rw-r--r--docs/_static/nature.css245
-rw-r--r--docs/_static/noise_dk.pngbin0 -> 22763 bytes
-rw-r--r--docs/_static/pygments.css70
-rw-r--r--docs/_static/sphinxdoc.css339
-rw-r--r--docs/_templates/defindex.html35
-rw-r--r--docs/_templates/indexcontent.html61
-rw-r--r--docs/_templates/layout.html69
-rw-r--r--docs/api/clientxmpp.rst19
-rw-r--r--docs/architecture.rst269
-rw-r--r--docs/conf.py220
-rw-r--r--docs/create_plugin.rst677
-rw-r--r--docs/event_index.rst271
-rw-r--r--docs/glossary.rst35
-rw-r--r--docs/guide_xep_0030.rst201
-rw-r--r--docs/index.rst130
-rw-r--r--docs/license.rst5
-rw-r--r--docs/make.bat170
-rw-r--r--docs/quickstart.rst300
-rw-r--r--docs/xmpp_tdg.rst249
35 files changed, 5211 insertions, 0 deletions
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 00000000..a520f6a1
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/SleekXMPP.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/SleekXMPP.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/SleekXMPP"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/SleekXMPP"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/_static/agogo.css b/docs/_static/agogo.css
new file mode 100644
index 00000000..8cdbf9c0
--- /dev/null
+++ b/docs/_static/agogo.css
@@ -0,0 +1,452 @@
+/*
+ * agogo.css_t
+ * ~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- agogo theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+* {
+ margin: 0px;
+ padding: 0px;
+}
+
+body {
+ font-family: "Verdana", Arial, sans-serif;
+ line-height: 1.4em;
+ color: black;
+ background-color: #eeeeec;
+}
+
+
+/* Page layout */
+
+div.header, div.content, div.footer {
+ width: 70em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+div.header-wrapper {
+ background: url(bgtop.png) top left repeat-x;
+ border-bottom: 3px solid #2e3436;
+}
+
+
+/* Default body styles */
+a {
+ color: #ce5c00;
+}
+
+div.bodywrapper a, div.footer a {
+ text-decoration: underline;
+}
+
+.clearer {
+ clear: both;
+}
+
+.left {
+ float: left;
+}
+
+.right {
+ float: right;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+h1, h2, h3, h4 {
+ font-family: "Georgia", "Times New Roman", serif;
+ font-weight: normal;
+ color: #3465a4;
+ margin-bottom: .8em;
+}
+
+h1 {
+ color: #204a87;
+}
+
+h2 {
+ padding-bottom: .5em;
+ border-bottom: 1px solid #3465a4;
+}
+
+a.headerlink {
+ visibility: hidden;
+ color: #dddddd;
+ padding-left: .3em;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+img {
+ border: 0;
+}
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 2px 7px 1px 7px;
+ border-left: 0.2em solid black;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+dt:target, .highlighted {
+ background-color: #fbe54e;
+}
+
+/* Header */
+
+div.header {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+
+div.header h1 {
+ font-family: "Georgia", "Times New Roman", serif;
+ font-weight: normal;
+ font-size: 180%;
+ letter-spacing: .08em;
+}
+
+div.header h1 a {
+ color: white;
+}
+
+div.header div.rel {
+ margin-top: 1em;
+}
+
+div.header div.rel a {
+ color: #fcaf3e;
+ letter-spacing: .1em;
+ text-transform: uppercase;
+}
+
+p.logo {
+ float: right;
+}
+
+img.logo {
+ border: 0;
+}
+
+
+/* Content */
+div.content-wrapper {
+ background-color: white;
+ padding-top: 20px;
+ padding-bottom: 20px;
+}
+
+div.document {
+ width: 50em;
+ float: left;
+}
+
+div.body {
+ padding-right: 2em;
+ text-align: justify;
+}
+
+div.document ul {
+ margin: 1.5em;
+ list-style-type: square;
+}
+
+div.document dd {
+ margin-left: 1.2em;
+ margin-top: .4em;
+ margin-bottom: 1em;
+}
+
+div.document .section {
+ margin-top: 1.7em;
+}
+div.document .section:first-child {
+ margin-top: 0px;
+}
+
+div.document div.highlight {
+ padding: 3px;
+ background-color: #eeeeec;
+ border-top: 2px solid #dddddd;
+ border-bottom: 2px solid #dddddd;
+ margin-top: .8em;
+ margin-bottom: .8em;
+}
+
+div.document h2 {
+ margin-top: .7em;
+}
+
+div.document p {
+ margin-bottom: .5em;
+}
+
+div.document li.toctree-l1 {
+ margin-bottom: 1em;
+}
+
+div.document .descname {
+ font-weight: bold;
+}
+
+div.document .docutils.literal {
+ background-color: #eeeeec;
+ padding: 1px;
+}
+
+div.document .docutils.xref.literal {
+ background-color: transparent;
+ padding: 0px;
+}
+
+div.document blockquote {
+ margin: 1em;
+}
+
+div.document ol {
+ margin: 1.5em;
+}
+
+
+/* Sidebar */
+
+div.sidebar {
+ width: 20em;
+ float: right;
+ font-size: .9em;
+}
+
+div.sidebar a, div.header a {
+ text-decoration: none;
+}
+
+div.sidebar a:hover, div.header a:hover {
+ text-decoration: underline;
+}
+
+div.sidebar h3 {
+ color: #2e3436;
+ text-transform: uppercase;
+ font-size: 130%;
+ letter-spacing: .1em;
+}
+
+div.sidebar ul {
+ list-style-type: none;
+}
+
+div.sidebar li.toctree-l1 a {
+ display: block;
+ padding: 1px;
+ border: 1px solid #dddddd;
+ background-color: #eeeeec;
+ margin-bottom: .4em;
+ padding-left: 3px;
+ color: #2e3436;
+}
+
+div.sidebar li.toctree-l2 a {
+ background-color: transparent;
+ border: none;
+ margin-left: 1em;
+ border-bottom: 1px solid #dddddd;
+}
+
+div.sidebar li.toctree-l3 a {
+ background-color: transparent;
+ border: none;
+ margin-left: 2em;
+ border-bottom: 1px solid #dddddd;
+}
+
+div.sidebar li.toctree-l2:last-child a {
+ border-bottom: none;
+}
+
+div.sidebar li.toctree-l1.current a {
+ border-right: 5px solid #fcaf3e;
+}
+
+div.sidebar li.toctree-l1.current li.toctree-l2 a {
+ border-right: none;
+}
+
+
+/* Footer */
+
+div.footer-wrapper {
+ background: url(bgfooter.png) top left repeat-x;
+ border-top: 4px solid #babdb6;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ min-height: 80px;
+}
+
+div.footer, div.footer a {
+ color: #888a85;
+}
+
+div.footer .right {
+ text-align: right;
+}
+
+div.footer .left {
+ text-transform: uppercase;
+}
+
+
+/* Styles copied from basic theme */
+
+img.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+ clear: right;
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ clear: both;
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+/* -- viewcode extension ---------------------------------------------------- */
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family:: "Verdana", Arial, sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -3px;
+ padding: 0 3px;
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+} \ No newline at end of file
diff --git a/docs/_static/basic.css b/docs/_static/basic.css
new file mode 100644
index 00000000..888716a6
--- /dev/null
+++ b/docs/_static/basic.css
@@ -0,0 +1,532 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+ clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: 230px;
+ margin-left: -100%;
+ font-size: 90%;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+img {
+ border: 0;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+ width: 100%;
+}
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable dl, table.indextable dd {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+div.modindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+a.headerlink {
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+.field-list ul {
+ padding-left: 1em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+ clear: right;
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ clear: both;
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+ margin: 0 0 0.5em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #efefef;
+ width: 40%;
+ float: right;
+ -mox-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+ text-transform: uppercase;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ border: 0;
+ border-collapse: collapse;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 0;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 1px solid #aaa;
+}
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dt:target, .highlighted {
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.refcount {
+ color: #060;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-family: sans-serif;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+tt.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+tt.descclassname {
+ background-color: transparent;
+}
+
+tt.xref, a tt {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
+ background-color: transparent;
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
+
diff --git a/docs/_static/default.css b/docs/_static/default.css
new file mode 100644
index 00000000..21f3f509
--- /dev/null
+++ b/docs/_static/default.css
@@ -0,0 +1,256 @@
+/*
+ * default.css_t
+ * ~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- default theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: sans-serif;
+ font-size: 100%;
+ background-color: #11303d;
+ color: #000;
+ margin: 0;
+ padding: 0;
+}
+
+div.document {
+ background-color: #1c4e63;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+div.body {
+ background-color: #ffffff;
+ color: #000000;
+ padding: 0 20px 30px 20px;
+}
+
+div.footer {
+ color: #ffffff;
+ width: 100%;
+ padding: 9px 0 9px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #ffffff;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #133f52;
+ line-height: 30px;
+ color: #ffffff;
+}
+
+div.related a {
+ color: #ffffff;
+}
+
+div.sphinxsidebar {
+}
+
+div.sphinxsidebar h3 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #ffffff;
+ font-size: 1.4em;
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+
+div.sphinxsidebar h3 a {
+ color: #ffffff;
+}
+
+div.sphinxsidebar h4 {
+ font-family: 'Trebuchet MS', sans-serif;
+ color: #ffffff;
+ font-size: 1.3em;
+ font-weight: normal;
+ margin: 5px 0 0 0;
+ padding: 0;
+}
+
+div.sphinxsidebar p {
+ color: #ffffff;
+}
+
+div.sphinxsidebar p.topless {
+ margin: 5px 10px 10px 10px;
+}
+
+div.sphinxsidebar ul {
+ margin: 10px;
+ padding: 0;
+ color: #ffffff;
+}
+
+div.sphinxsidebar a {
+ color: #98dbcc;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+
+
+/* -- hyperlink styles ------------------------------------------------------ */
+
+a {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:visited {
+ color: #355f7c;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+
+
+/* -- body styles ----------------------------------------------------------- */
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: 'Trebuchet MS', sans-serif;
+ background-color: #f2f2f2;
+ font-weight: normal;
+ color: #20435c;
+ border-bottom: 1px solid #ccc;
+ margin: 20px -20px 10px -20px;
+ padding: 3px 0 3px 10px;
+}
+
+div.body h1 { margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 160%; }
+div.body h3 { font-size: 140%; }
+div.body h4 { font-size: 120%; }
+div.body h5 { font-size: 110%; }
+div.body h6 { font-size: 100%; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ text-align: justify;
+ line-height: 130%;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.admonition p {
+ margin-bottom: 5px;
+}
+
+div.admonition pre {
+ margin-bottom: 5px;
+}
+
+div.admonition ul, div.admonition ol {
+ margin-bottom: 5px;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.topic {
+ background-color: #eee;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+pre {
+ padding: 5px;
+ background-color: #eeffcc;
+ color: #333333;
+ line-height: 120%;
+ border: 1px solid #ac9;
+ border-left: none;
+ border-right: none;
+}
+
+tt {
+ background-color: #ecf0f3;
+ padding: 0 1px 0 1px;
+ font-size: 0.95em;
+}
+
+th {
+ background-color: #ede;
+}
+
+.warning tt {
+ background: #efc2c2;
+}
+
+.note tt {
+ background: #d6d6d6;
+}
+
+.viewcode-back {
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+} \ No newline at end of file
diff --git a/docs/_static/fonts/Museo_Slab_500.otf b/docs/_static/fonts/Museo_Slab_500.otf
new file mode 100644
index 00000000..84ceaca5
--- /dev/null
+++ b/docs/_static/fonts/Museo_Slab_500.otf
Binary files differ
diff --git a/docs/_static/fonts/Museo_Slab_500italic.otf b/docs/_static/fonts/Museo_Slab_500italic.otf
new file mode 100644
index 00000000..a8c055fd
--- /dev/null
+++ b/docs/_static/fonts/Museo_Slab_500italic.otf
Binary files differ
diff --git a/docs/_static/fonts/OFLGoudyStMTT-Italic.ttf b/docs/_static/fonts/OFLGoudyStMTT-Italic.ttf
new file mode 100644
index 00000000..91956cba
--- /dev/null
+++ b/docs/_static/fonts/OFLGoudyStMTT-Italic.ttf
Binary files differ
diff --git a/docs/_static/fonts/OFLGoudyStMTT.ttf b/docs/_static/fonts/OFLGoudyStMTT.ttf
new file mode 100644
index 00000000..dc900c29
--- /dev/null
+++ b/docs/_static/fonts/OFLGoudyStMTT.ttf
Binary files differ
diff --git a/docs/_static/fonts/YanoneKaffeesatz-Bold.ttf b/docs/_static/fonts/YanoneKaffeesatz-Bold.ttf
new file mode 100644
index 00000000..64e5d1ce
--- /dev/null
+++ b/docs/_static/fonts/YanoneKaffeesatz-Bold.ttf
Binary files differ
diff --git a/docs/_static/fonts/YanoneKaffeesatz-Light.ttf b/docs/_static/fonts/YanoneKaffeesatz-Light.ttf
new file mode 100644
index 00000000..15eccf5c
--- /dev/null
+++ b/docs/_static/fonts/YanoneKaffeesatz-Light.ttf
Binary files differ
diff --git a/docs/_static/fonts/YanoneKaffeesatz-Regular.ttf b/docs/_static/fonts/YanoneKaffeesatz-Regular.ttf
new file mode 100644
index 00000000..25cee817
--- /dev/null
+++ b/docs/_static/fonts/YanoneKaffeesatz-Regular.ttf
Binary files differ
diff --git a/docs/_static/fonts/YanoneKaffeesatz-Thin.ttf b/docs/_static/fonts/YanoneKaffeesatz-Thin.ttf
new file mode 100644
index 00000000..6e26d9e8
--- /dev/null
+++ b/docs/_static/fonts/YanoneKaffeesatz-Thin.ttf
Binary files differ
diff --git a/docs/_static/haiku.css b/docs/_static/haiku.css
new file mode 100644
index 00000000..615ed47b
--- /dev/null
+++ b/docs/_static/haiku.css
@@ -0,0 +1,406 @@
+/*
+ * haiku.css_t
+ * ~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- haiku theme.
+ *
+ * Adapted from http://haiku-os.org/docs/Haiku-doc.css.
+ * Original copyright message:
+ *
+ * Copyright 2008-2009, Haiku. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Francois Revol <revol@free.fr>
+ * Stephan Assmus <superstippi@gmx.de>
+ * Braden Ewing <brewin@gmail.com>
+ * Humdinger <humdingerb@gmail.com>
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+
+@font-face {
+ font-family: "Museo Slab";
+ font-weight: normal;
+ font-style: normal;
+ src: local("Museo Slab"),
+ url("fonts/Museo_Slab_500.otf") format("opentype");
+}
+
+@font-face {
+ font-family: "Yanone Kaffeesatz";
+ font-weight: bold;
+ font-style: normal;
+ src: local("Yanone Kaffeesatz"),
+ url("fonts/YanoneKaffeesatz-Bold.ttf") format("truetype");
+}
+
+@font-face {
+ font-family: "Yanone Kaffeesatz";
+ font-weight: lighter;
+ font-style: normal;
+ src: local("Yanone Kaffeesatz"),
+ url("fonts/YanoneKaffeesatz-Regular.ttf") format("truetype");
+}
+
+html {
+ margin: 0px;
+ padding: 0px;
+ background: #FFF url(header.png) top left repeat-x;
+}
+
+body {
+ line-height: 1.5;
+ margin: auto;
+ padding: 0px;
+ font-family: "Helvetica Neueu", Helvetica, sans-serif;
+ min-width: 59em;
+ max-width: 70em;
+ color: #444;
+}
+
+div.footer {
+ padding: 8px;
+ font-size: 11px;
+ text-align: center;
+ letter-spacing: 0.5px;
+}
+
+/* link colors and text decoration */
+
+a:link {
+ font-weight: bold;
+ text-decoration: none;
+ color: #00ADEE;
+}
+
+a:visited {
+ font-weight: bold;
+ text-decoration: none;
+ color: #00ADEE;
+}
+
+a:hover, a:active {
+ text-decoration: underline;
+ color: #F46DBA;
+}
+
+/* Some headers act as anchors, don't give them a hover effect */
+
+h1 a:hover, a:active {
+ text-decoration: none;
+ color: #CFCFCF;
+}
+
+h2 a:hover, a:active {
+ text-decoration: none;
+ color: #CFCFCF;
+}
+
+h3 a:hover, a:active {
+ text-decoration: none;
+ color: #CFCFCF;
+}
+
+h4 a:hover, a:active {
+ text-decoration: none;
+ color: #CFCFCF;
+}
+
+a.headerlink {
+ color: #a7ce38;
+ padding-left: 5px;
+}
+
+a.headerlink:hover {
+ color: #a7ce38;
+}
+
+/* basic text elements */
+
+div.content {
+ margin-top: 20px;
+ margin-left: 40px;
+ margin-right: 40px;
+ margin-bottom: 50px;
+ font-size: 0.9em;
+}
+
+/* heading and navigation */
+
+div.header {
+ position: relative;
+ margin-top: 125px;
+ height: 85px;
+ padding: 0 40px;
+ font-family: "Yanone Kaffeesatz";
+}
+div.header h1 {
+ font-size: 2.6em;
+ font-weight: normal;
+ letter-spacing: 1px;
+ color: #CFCFCF;
+ border: 0;
+ margin: 0;
+ padding-top: 15px;
+ font-family: "Yanone Kaffeesatz";
+ text-shadow: 1px 1px 1px rgba(175, 175, 175, .8);
+ font-variant: small-caps;
+}
+div.header h1 a {
+ font-weight: normal;
+ color: #00ADEE;
+}
+div.header h2 {
+ font-size: 1.3em;
+ font-weight: normal;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ color: #aaa;
+ border: 0;
+ margin-top: -3px;
+ padding: 0;
+ font-family: "Yanone Kaffeesatz";
+}
+
+div.header img.rightlogo {
+ float: right;
+}
+
+
+div.title {
+ font-size: 1.3em;
+ font-weight: bold;
+ color: #CFCFCF;
+ border-bottom: dotted thin #e0e0e0;
+ margin-bottom: 25px;
+}
+div.topnav {
+ position: relative;
+ z-index: 0;
+}
+div.topnav p {
+ margin-top: 0;
+ margin-left: 40px;
+ margin-right: 40px;
+ margin-bottom: 0px;
+ text-align: right;
+ font-size: 0.8em;
+}
+div.bottomnav {
+ background: #eeeeee;
+}
+div.bottomnav p {
+ margin-right: 40px;
+ text-align: right;
+ font-size: 0.8em;
+}
+
+a.uplink {
+ font-weight: normal;
+}
+
+
+/* contents box */
+
+table.index {
+ margin: 0px 0px 30px 30px;
+ padding: 1px;
+ border-width: 1px;
+ border-style: dotted;
+ border-color: #e0e0e0;
+}
+table.index tr.heading {
+ background-color: #e0e0e0;
+ text-align: center;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+table.index tr.index {
+ background-color: #eeeeee;
+}
+table.index td {
+ padding: 5px 20px;
+}
+
+table.index a:link, table.index a:visited {
+ font-weight: normal;
+ text-decoration: none;
+ color: #4A7389;
+}
+table.index a:hover, table.index a:active {
+ text-decoration: underline;
+ color: #ff4500;
+}
+
+
+/* Haiku User Guide styles and layout */
+
+/* Rounded corner boxes */
+/* Common declarations */
+div.admonition {
+ -webkit-border-radius: 10px;
+ -khtml-border-radius: 10px;
+ -moz-border-radius: 10px;
+ border-radius: 10px;
+ border-style: dotted;
+ border-width: thin;
+ border-color: #dcdcdc;
+ padding: 10px 15px 10px 15px;
+ margin-bottom: 15px;
+ margin-top: 15px;
+}
+div.note {
+ padding: 10px 15px 10px 15px;
+ background-color: #e4ffde;
+ /*background: #e4ffde url(alert_info_32.png) 15px 15px no-repeat;*/
+ min-height: 42px;
+}
+div.warning {
+ padding: 10px 15px 10px 15px;
+ background-color: #fffbc6;
+ /*background: #fffbc6 url(alert_warning_32.png) 15px 15px no-repeat;*/
+ min-height: 42px;
+}
+div.seealso {
+ background: #e4ffde;
+}
+
+/* More layout and styles */
+h1 {
+ font-size: 1.6em;
+ color: #aaa;
+ border-bottom: dotted thin #e0e0e0;
+ margin-top: 30px;
+ font-family: "Museo Slab";
+ text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
+}
+
+h2 {
+ font-size: 1.5em;
+ font-weight: normal;
+ color: #aaa;
+ border-bottom: dotted thin #e0e0e0;
+ margin-top: 30px;
+ font-family: "Museo Slab";
+ text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
+}
+
+h3 {
+ font-size: 1.4em;
+ font-weight: normal;
+ color: #aaa;
+ margin-top: 30px;
+ font-family: "Museo Slab";
+ text-shadow: 1px 1px 1px rgba(175, 175, 175, .25);
+}
+
+h4 {
+ font-size: 1.3em;
+ font-weight: normal;
+ color: #CFCFCF;
+ margin-top: 30px;
+}
+
+p {
+ text-align: justify;
+}
+
+p.last {
+ margin-bottom: 0;
+}
+
+ol {
+ padding-left: 20px;
+}
+
+ul {
+ padding-left: 5px;
+ margin-top: 3px;
+}
+
+li {
+ line-height: 1.3;
+}
+
+div.content ul > li {
+ -moz-background-clip:border;
+ -moz-background-inline-policy:continuous;
+ -moz-background-origin:padding;
+ background: transparent url(bullet_orange.png) no-repeat scroll left 0.45em;
+ list-style-image: none;
+ list-style-type: none;
+ padding: 0 0 0 1.666em;
+ margin-bottom: 3px;
+}
+
+td {
+ vertical-align: top;
+}
+
+tt {
+ background-color: #e2e2e2;
+ font-size: 1.0em;
+ font-family: monospace;
+}
+
+pre {
+ font-size: 1.1em;
+ margin: 0 0 12px 0;
+ padding: 0.8em;
+ background-image: url(noise_dk.png);
+ background-color: #222;
+}
+
+hr {
+ border-top: 1px solid #ccc;
+ border-bottom: 0;
+ border-right: 0;
+ border-left: 0;
+ margin-bottom: 10px;
+ margin-top: 20px;
+}
+
+/* printer only pretty stuff */
+@media print {
+ .noprint {
+ display: none;
+ }
+ /* for acronyms we want their definitions inlined at print time */
+ acronym[title]:after {
+ font-size: small;
+ content: " (" attr(title) ")";
+ font-style: italic;
+ }
+ /* and not have mozilla dotted underline */
+ acronym {
+ border: none;
+ }
+ div.topnav, div.bottomnav, div.header, table.index {
+ display: none;
+ }
+ div.content {
+ margin: 0px;
+ padding: 0px;
+ }
+ html {
+ background: #FFF;
+ }
+}
+
+.viewcode-back {
+ font-family: "DejaVu Sans", Arial, Helvetica, sans-serif;
+}
+
+div.viewcode-block:target {
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+ margin: -1px -12px;
+ padding: 0 12px;
+}
+
diff --git a/docs/_static/header.png b/docs/_static/header.png
new file mode 100644
index 00000000..2aaa53a1
--- /dev/null
+++ b/docs/_static/header.png
Binary files differ
diff --git a/docs/_static/images/arch_layers.png b/docs/_static/images/arch_layers.png
new file mode 100644
index 00000000..1ee183bb
--- /dev/null
+++ b/docs/_static/images/arch_layers.png
Binary files differ
diff --git a/docs/_static/ir_black.css b/docs/_static/ir_black.css
new file mode 100644
index 00000000..f04bc738
--- /dev/null
+++ b/docs/_static/ir_black.css
@@ -0,0 +1,70 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #000000; color: #f6f3e8; }
+.highlight .c { color: #7C7C7C; } /* Comment */
+.highlight .err { color: #f6f3e8; } /* Error */
+.highlight .g { color: #f6f3e8; } /* Generic */
+.highlight .k { color: #00ADEE; } /* Keyword */
+.highlight .l { color: #f6f3e8; } /* Literal */
+.highlight .n { color: #f6f3e8; } /* Name */
+.highlight .o { color: #f6f3e8; } /* Operator */
+.highlight .x { color: #f6f3e8; } /* Other */
+.highlight .p { color: #f6f3e8; } /* Punctuation */
+.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
+.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
+.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
+.highlight .cs { color: #7C7C7C; } /* Comment.Special */
+.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
+.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
+.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
+.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
+.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
+.highlight .go { color: #070707; } /* Generic.Output */
+.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
+.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
+.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
+.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
+.highlight .kc { color: #6699CC; } /* Keyword.Constant */
+.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
+.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
+.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
+.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
+.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
+.highlight .ld { color: #f6f3e8; } /* Literal.Date */
+.highlight .m { color: #FF73FD; } /* Literal.Number */
+.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
+.highlight .na { color: #f6f3e8; } /* Name.Attribute */
+.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
+.highlight .nc { color: #f6f3e8; } /* Name.Class */
+.highlight .no { color: #99CC99; } /* Name.Constant */
+.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
+.highlight .ni { color: #E18964; } /* Name.Entity */
+.highlight .ne { color: #f6f3e8; } /* Name.Exception */
+.highlight .nf { color: #F64DBA; } /* Name.Function */
+.highlight .nl { color: #f6f3e8; } /* Name.Label */
+.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
+.highlight .nx { color: #f6f3e8; } /* Name.Other */
+.highlight .py { color: #f6f3e8; } /* Name.Property */
+.highlight .nt { color: #00ADEE; } /* Name.Tag */
+.highlight .nv { color: #C6C5FE; } /* Name.Variable */
+.highlight .ow { color: #ffffff; } /* Operator.Word */
+.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
+.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
+.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
+.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
+.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
+.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
+.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
+.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
+.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
+.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
+.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
+.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
+.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
+.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
+.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
+.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
+.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
+.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
+.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
+.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */
diff --git a/docs/_static/nature.css b/docs/_static/nature.css
new file mode 100644
index 00000000..52b328ea
--- /dev/null
+++ b/docs/_static/nature.css
@@ -0,0 +1,245 @@
+/*
+ * nature.css_t
+ * ~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- nature theme.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: Arial, sans-serif;
+ font-size: 100%;
+ background-color: #111;
+ color: #555;
+ margin: 0;
+ padding: 0;
+}
+
+div.documentwrapper {
+ float: left;
+ width: 100%;
+}
+
+div.bodywrapper {
+ margin: 0 0 0 230px;
+}
+
+hr {
+ border: 1px solid #B1B4B6;
+}
+
+div.document {
+ background-color: #eee;
+}
+
+div.body {
+ background-color: #ffffff;
+ color: #3E4349;
+ padding: 0 30px 30px 30px;
+ font-size: 0.9em;
+}
+
+div.footer {
+ color: #555;
+ width: 100%;
+ padding: 13px 0;
+ text-align: center;
+ font-size: 75%;
+}
+
+div.footer a {
+ color: #444;
+ text-decoration: underline;
+}
+
+div.related {
+ background-color: #6BA81E;
+ line-height: 32px;
+ color: #fff;
+ text-shadow: 0px 1px 0 #444;
+ font-size: 0.9em;
+}
+
+div.related a {
+ color: #E2F3CC;
+}
+
+div.sphinxsidebar {
+ font-size: 0.75em;
+ line-height: 1.5em;
+}
+
+div.sphinxsidebarwrapper{
+ padding: 20px 0;
+}
+
+div.sphinxsidebar h3,
+div.sphinxsidebar h4 {
+ font-family: Arial, sans-serif;
+ color: #222;
+ font-size: 1.2em;
+ font-weight: normal;
+ margin: 0;
+ padding: 5px 10px;
+ background-color: #ddd;
+ text-shadow: 1px 1px 0 white
+}
+
+div.sphinxsidebar h4{
+ font-size: 1.1em;
+}
+
+div.sphinxsidebar h3 a {
+ color: #444;
+}
+
+
+div.sphinxsidebar p {
+ color: #888;
+ padding: 5px 20px;
+}
+
+div.sphinxsidebar p.topless {
+}
+
+div.sphinxsidebar ul {
+ margin: 10px 20px;
+ padding: 0;
+ color: #000;
+}
+
+div.sphinxsidebar a {
+ color: #444;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #ccc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+div.sphinxsidebar input[type=text]{
+ margin-left: 20px;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+a {
+ color: #005B81;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #E32E00;
+ text-decoration: underline;
+}
+
+div.body h1,
+div.body h2,
+div.body h3,
+div.body h4,
+div.body h5,
+div.body h6 {
+ font-family: Arial, sans-serif;
+ background-color: #BED4EB;
+ font-weight: normal;
+ color: #212224;
+ margin: 30px 0px 10px 0px;
+ padding: 5px 0 5px 10px;
+ text-shadow: 0px 1px 0 white
+}
+
+div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
+div.body h2 { font-size: 150%; background-color: #C8D5E3; }
+div.body h3 { font-size: 120%; background-color: #D8DEE3; }
+div.body h4 { font-size: 110%; background-color: #D8DEE3; }
+div.body h5 { font-size: 100%; background-color: #D8DEE3; }
+div.body h6 { font-size: 100%; background-color: #D8DEE3; }
+
+a.headerlink {
+ color: #c60f0f;
+ font-size: 0.8em;
+ padding: 0 4px 0 4px;
+ text-decoration: none;
+}
+
+a.headerlink:hover {
+ background-color: #c60f0f;
+ color: white;
+}
+
+div.body p, div.body dd, div.body li {
+ line-height: 1.5em;
+}
+
+div.admonition p.admonition-title + p {
+ display: inline;
+}
+
+div.highlight{
+ background-color: white;
+}
+
+div.note {
+ background-color: #eee;
+ border: 1px solid #ccc;
+}
+
+div.seealso {
+ background-color: #ffc;
+ border: 1px solid #ff6;
+}
+
+div.topic {
+ background-color: #eee;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+p.admonition-title {
+ display: inline;
+}
+
+p.admonition-title:after {
+ content: ":";
+}
+
+pre {
+ padding: 10px;
+ background-color: White;
+ color: #222;
+ line-height: 1.2em;
+ border: 1px solid #C6C9CB;
+ font-size: 1.1em;
+ margin: 1.5em 0 1.5em 0;
+ -webkit-box-shadow: 1px 1px 1px #d8d8d8;
+ -moz-box-shadow: 1px 1px 1px #d8d8d8;
+}
+
+tt {
+ background-color: #ecf0f3;
+ color: #222;
+ /* padding: 1px 2px; */
+ font-size: 1.1em;
+ font-family: monospace;
+}
+
+.viewcode-back {
+ font-family: Arial, sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+} \ No newline at end of file
diff --git a/docs/_static/noise_dk.png b/docs/_static/noise_dk.png
new file mode 100644
index 00000000..f0b4de42
--- /dev/null
+++ b/docs/_static/noise_dk.png
Binary files differ
diff --git a/docs/_static/pygments.css b/docs/_static/pygments.css
new file mode 100644
index 00000000..f04bc738
--- /dev/null
+++ b/docs/_static/pygments.css
@@ -0,0 +1,70 @@
+.highlight .hll { background-color: #ffffcc }
+.highlight { background: #000000; color: #f6f3e8; }
+.highlight .c { color: #7C7C7C; } /* Comment */
+.highlight .err { color: #f6f3e8; } /* Error */
+.highlight .g { color: #f6f3e8; } /* Generic */
+.highlight .k { color: #00ADEE; } /* Keyword */
+.highlight .l { color: #f6f3e8; } /* Literal */
+.highlight .n { color: #f6f3e8; } /* Name */
+.highlight .o { color: #f6f3e8; } /* Operator */
+.highlight .x { color: #f6f3e8; } /* Other */
+.highlight .p { color: #f6f3e8; } /* Punctuation */
+.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
+.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
+.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
+.highlight .cs { color: #7C7C7C; } /* Comment.Special */
+.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
+.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
+.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
+.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
+.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
+.highlight .go { color: #070707; } /* Generic.Output */
+.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
+.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
+.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
+.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
+.highlight .kc { color: #6699CC; } /* Keyword.Constant */
+.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
+.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
+.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
+.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
+.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
+.highlight .ld { color: #f6f3e8; } /* Literal.Date */
+.highlight .m { color: #FF73FD; } /* Literal.Number */
+.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
+.highlight .na { color: #f6f3e8; } /* Name.Attribute */
+.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
+.highlight .nc { color: #f6f3e8; } /* Name.Class */
+.highlight .no { color: #99CC99; } /* Name.Constant */
+.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
+.highlight .ni { color: #E18964; } /* Name.Entity */
+.highlight .ne { color: #f6f3e8; } /* Name.Exception */
+.highlight .nf { color: #F64DBA; } /* Name.Function */
+.highlight .nl { color: #f6f3e8; } /* Name.Label */
+.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
+.highlight .nx { color: #f6f3e8; } /* Name.Other */
+.highlight .py { color: #f6f3e8; } /* Name.Property */
+.highlight .nt { color: #00ADEE; } /* Name.Tag */
+.highlight .nv { color: #C6C5FE; } /* Name.Variable */
+.highlight .ow { color: #ffffff; } /* Operator.Word */
+.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
+.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
+.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
+.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
+.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
+.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
+.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
+.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
+.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
+.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
+.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
+.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
+.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
+.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
+.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
+.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
+.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
+.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
+.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
+.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */
diff --git a/docs/_static/sphinxdoc.css b/docs/_static/sphinxdoc.css
new file mode 100644
index 00000000..0a428074
--- /dev/null
+++ b/docs/_static/sphinxdoc.css
@@ -0,0 +1,339 @@
+/*
+ * sphinxdoc.css_t
+ * ~~~~~~~~~~~~~~~
+ *
+ * Sphinx stylesheet -- sphinxdoc theme. Originally created by
+ * Armin Ronacher for Werkzeug.
+ *
+ * :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+@import url("basic.css");
+
+/* -- page layout ----------------------------------------------------------- */
+
+body {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+ font-size: 14px;
+ letter-spacing: -0.01em;
+ line-height: 150%;
+ text-align: center;
+ background-color: #BFD1D4;
+ color: black;
+ padding: 0;
+ border: 1px solid #aaa;
+
+ margin: 0px 80px 0px 80px;
+ min-width: 740px;
+}
+
+div.document {
+ background-color: white;
+ text-align: left;
+ background-image: url(contents.png);
+ background-repeat: repeat-x;
+}
+
+div.bodywrapper {
+ margin: 0 240px 0 0;
+ border-right: 1px solid #ccc;
+}
+
+div.body {
+ margin: 0;
+ padding: 0.5em 20px 20px 20px;
+}
+
+div.related {
+ font-size: 1em;
+}
+
+div.related ul {
+ background-image: url(navigation.png);
+ height: 2em;
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+}
+
+div.related ul li {
+ margin: 0;
+ padding: 0;
+ height: 2em;
+ float: left;
+}
+
+div.related ul li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+div.related ul li a {
+ margin: 0;
+ padding: 0 5px 0 5px;
+ line-height: 1.75em;
+ color: #EE9816;
+}
+
+div.related ul li a:hover {
+ color: #3CA8E7;
+}
+
+div.sphinxsidebarwrapper {
+ padding: 0;
+}
+
+div.sphinxsidebar {
+ margin: 0;
+ padding: 0.5em 15px 15px 0;
+ width: 210px;
+ float: right;
+ font-size: 1em;
+ text-align: left;
+}
+
+div.sphinxsidebar h3, div.sphinxsidebar h4 {
+ margin: 1em 0 0.5em 0;
+ font-size: 1em;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border: 1px solid #86989B;
+ background-color: #AFC1C4;
+}
+
+div.sphinxsidebar h3 a {
+ color: white;
+}
+
+div.sphinxsidebar ul {
+ padding-left: 1.5em;
+ margin-top: 7px;
+ padding: 0;
+ line-height: 130%;
+}
+
+div.sphinxsidebar ul ul {
+ margin-left: 20px;
+}
+
+div.footer {
+ background-color: #E3EFF1;
+ color: #86989B;
+ padding: 3px 8px 3px 0;
+ clear: both;
+ font-size: 0.8em;
+ text-align: right;
+}
+
+div.footer a {
+ color: #86989B;
+ text-decoration: underline;
+}
+
+/* -- body styles ----------------------------------------------------------- */
+
+p {
+ margin: 0.8em 0 0.5em 0;
+}
+
+a {
+ color: #CA7900;
+ text-decoration: none;
+}
+
+a:hover {
+ color: #2491CF;
+}
+
+div.body a {
+ text-decoration: underline;
+}
+
+h1 {
+ margin: 0;
+ padding: 0.7em 0 0.3em 0;
+ font-size: 1.5em;
+ color: #11557C;
+}
+
+h2 {
+ margin: 1.3em 0 0.2em 0;
+ font-size: 1.35em;
+ padding: 0;
+}
+
+h3 {
+ margin: 1em 0 -0.3em 0;
+ font-size: 1.2em;
+}
+
+div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
+ color: black!important;
+}
+
+h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
+ display: none;
+ margin: 0 0 0 0.3em;
+ padding: 0 0.2em 0 0.2em;
+ color: #aaa!important;
+}
+
+h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
+h5:hover a.anchor, h6:hover a.anchor {
+ display: inline;
+}
+
+h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
+h5 a.anchor:hover, h6 a.anchor:hover {
+ color: #777;
+ background-color: #eee;
+}
+
+a.headerlink {
+ color: #c60f0f!important;
+ font-size: 1em;
+ margin-left: 6px;
+ padding: 0 4px 0 4px;
+ text-decoration: none!important;
+}
+
+a.headerlink:hover {
+ background-color: #ccc;
+ color: white!important;
+}
+
+cite, code, tt {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.01em;
+}
+
+tt {
+ background-color: #f2f2f2;
+ border-bottom: 1px solid #ddd;
+ color: #333;
+}
+
+tt.descname, tt.descclassname, tt.xref {
+ border: 0;
+}
+
+hr {
+ border: 1px solid #abc;
+ margin: 2em;
+}
+
+a tt {
+ border: 0;
+ color: #CA7900;
+}
+
+a tt:hover {
+ color: #2491CF;
+}
+
+pre {
+ font-family: 'Consolas', 'Deja Vu Sans Mono',
+ 'Bitstream Vera Sans Mono', monospace;
+ font-size: 0.95em;
+ letter-spacing: 0.015em;
+ line-height: 120%;
+ padding: 0.5em;
+ border: 1px solid #ccc;
+ background-color: #f8f8f8;
+}
+
+pre a {
+ color: inherit;
+ text-decoration: underline;
+}
+
+td.linenos pre {
+ padding: 0.5em 0;
+}
+
+div.quotebar {
+ background-color: #f8f8f8;
+ max-width: 250px;
+ float: right;
+ padding: 2px 7px;
+ border: 1px solid #ccc;
+}
+
+div.topic {
+ background-color: #f8f8f8;
+}
+
+table {
+ border-collapse: collapse;
+ margin: 0 -0.5em 0 -0.5em;
+}
+
+table td, table th {
+ padding: 0.2em 0.5em 0.2em 0.5em;
+}
+
+div.admonition, div.warning {
+ font-size: 0.9em;
+ margin: 1em 0 1em 0;
+ border: 1px solid #86989B;
+ background-color: #f7f7f7;
+ padding: 0;
+}
+
+div.admonition p, div.warning p {
+ margin: 0.5em 1em 0.5em 1em;
+ padding: 0;
+}
+
+div.admonition pre, div.warning pre {
+ margin: 0.4em 1em 0.4em 1em;
+}
+
+div.admonition p.admonition-title,
+div.warning p.admonition-title {
+ margin: 0;
+ padding: 0.1em 0 0.1em 0.5em;
+ color: white;
+ border-bottom: 1px solid #86989B;
+ font-weight: bold;
+ background-color: #AFC1C4;
+}
+
+div.warning {
+ border: 1px solid #940000;
+}
+
+div.warning p.admonition-title {
+ background-color: #CF0000;
+ border-bottom-color: #940000;
+}
+
+div.admonition ul, div.admonition ol,
+div.warning ul, div.warning ol {
+ margin: 0.1em 0.5em 0.5em 3em;
+ padding: 0;
+}
+
+div.versioninfo {
+ margin: 1em 0 0 0;
+ border: 1px solid #ccc;
+ background-color: #DDEAF0;
+ padding: 8px;
+ line-height: 1.3em;
+ font-size: 0.9em;
+}
+
+.viewcode-back {
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+ 'Verdana', sans-serif;
+}
+
+div.viewcode-block:target {
+ background-color: #f4debf;
+ border-top: 1px solid #ac9;
+ border-bottom: 1px solid #ac9;
+}
diff --git a/docs/_templates/defindex.html b/docs/_templates/defindex.html
new file mode 100644
index 00000000..ce8d3af6
--- /dev/null
+++ b/docs/_templates/defindex.html
@@ -0,0 +1,35 @@
+{#
+ basic/defindex.html
+ ~~~~~~~~~~~~~~~~~~~
+
+ Default template for the "index" page.
+
+ :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "layout.html" %}
+{% set title = _('Overview') %}
+{% block body %}
+ <h1>{{ docstitle|e }}</h1>
+ <p>
+ Welcome! This is
+ {% block description %}the documentation for {{ project|e }}
+ {{ release|e }}{% if last_updated %}, last updated {{ last_updated|e }}{% endif %}{% endblock %}.
+ </p>
+ {% block tables %}
+ <p><strong>{{ _('Indices and tables:') }}</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">{{ _('Complete Table of Contents') }}</a><br>
+ <span class="linkdescr">{{ _('lists all sections and subsections') }}</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">{{ _('Search Page') }}</a><br>
+ <span class="linkdescr">{{ _('search this documentation') }}</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("modindex") }}">{{ _('Global Module Index') }}</a><br>
+ <span class="linkdescr">{{ _('quick access to all modules') }}</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">{{ _('General Index') }}</a><br>
+ <span class="linkdescr">{{ _('all functions, classes, terms') }}</span></p>
+ </td></tr>
+ </table>
+ {% endblock %}
+{% endblock %}
diff --git a/docs/_templates/indexcontent.html b/docs/_templates/indexcontent.html
new file mode 100644
index 00000000..d5e17cd6
--- /dev/null
+++ b/docs/_templates/indexcontent.html
@@ -0,0 +1,61 @@
+{% extends "defindex.html" %}
+{% block tables %}
+ <p><strong>Parts of the documentation:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("whatsnew/" + version) }}">What's new in Python {{ version }}?</a><br/>
+ <span class="linkdescr">or <a href="{{ pathto("whatsnew/index") }}">all "What's new" documents</a> since 2.0</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("tutorial/index") }}">Tutorial</a><br/>
+ <span class="linkdescr">start here</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("library/index") }}">Library Reference</a><br/>
+ <span class="linkdescr">keep this under your pillow</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("reference/index") }}">Language Reference</a><br/>
+ <span class="linkdescr">describes syntax and language elements</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("using/index") }}">Python Setup and Usage</a><br/>
+ <span class="linkdescr">how to use Python on different platforms</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("howto/index") }}">Python HOWTOs</a><br/>
+ <span class="linkdescr">in-depth documents on specific topics</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("extending/index") }}">Extending and Embedding</a><br/>
+ <span class="linkdescr">tutorial for C/C++ programmers</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("c-api/index") }}">Python/C API</a><br/>
+ <span class="linkdescr">reference for C/C++ programmers</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("install/index") }}">Installing Python Modules</a><br/>
+ <span class="linkdescr">information for installers &amp; sys-admins</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("distutils/index") }}">Distributing Python Modules</a><br/>
+ <span class="linkdescr">sharing modules with others</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("documenting/index") }}">Documenting Python</a><br/>
+ <span class="linkdescr">guide for documentation authors</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("faq/index") }}">FAQs</a><br/>
+ <span class="linkdescr">frequently asked questions (with answers!)</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Indices and tables:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("py-modindex") }}">Global Module Index</a><br/>
+ <span class="linkdescr">quick access to all modules</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("genindex") }}">General Index</a><br/>
+ <span class="linkdescr">all functions, classes, terms</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("glossary") }}">Glossary</a><br/>
+ <span class="linkdescr">the most important terms explained</span></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("search") }}">Search page</a><br/>
+ <span class="linkdescr">search this documentation</span></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Complete Table of Contents</a><br/>
+ <span class="linkdescr">lists all sections and subsections</span></p>
+ </td></tr>
+ </table>
+
+ <p><strong>Meta information:</strong></p>
+ <table class="contentstable" align="center"><tr>
+ <td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("bugs") }}">Reporting bugs</a></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("about") }}">About the documentation</a></p>
+ </td><td width="50%">
+ <p class="biglink"><a class="biglink" href="{{ pathto("license") }}">History and License of Python</a></p>
+ <p class="biglink"><a class="biglink" href="{{ pathto("copyright") }}">Copyright</a></p>
+ </td></tr>
+ </table>
+{% endblock %}
diff --git a/docs/_templates/layout.html b/docs/_templates/layout.html
new file mode 100644
index 00000000..a5dd7c82
--- /dev/null
+++ b/docs/_templates/layout.html
@@ -0,0 +1,69 @@
+{#
+ haiku/layout.html
+ ~~~~~~~~~~~~~~~~~
+
+ Sphinx layout template for the haiku theme.
+
+ :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{% extends "basic/layout.html" %}
+{% set script_files = script_files + ['_static/theme_extras.js'] %}
+{% set css_files = css_files + ['_static/print.css'] %}
+
+{# do not display relbars #}
+{% block relbar1 %}{% endblock %}
+{% block relbar2 %}{% endblock %}
+
+{% macro nav() %}
+ <p>
+ {%- block haikurel1 %}
+ {%- endblock %}
+ {%- if prev %}
+ «&#160;&#160;<a href="{{ prev.link|e }}">{{ prev.title }}</a>
+ &#160;&#160;::&#160;&#160;
+ {%- endif %}
+ <a class="uplink" href="{{ pathto(master_doc) }}">{{ _('Contents') }}</a>
+ {%- if next %}
+ &#160;&#160;::&#160;&#160;
+ <a href="{{ next.link|e }}">{{ next.title }}</a>&#160;&#160;»
+ {%- endif %}
+ {%- block haikurel2 %}
+ {%- endblock %}
+ </p>
+{% endmacro %}
+
+{% block content %}
+ <div class="header">
+ {%- block haikuheader %}
+ {%- if theme_full_logo != "false" %}
+ <a href="{{ pathto('index') }}">
+ <img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
+ </a>
+ {%- else %}
+ {%- if logo -%}
+ <img class="rightlogo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
+ {%- endif -%}
+ <h1 class="heading">
+ <a href="{{ pathto('index') }}"><span>{{ project|e }}</span></a>
+ </h1>
+ <h2 class="heading"><span>{{ shorttitle|e }}</span></h2>
+ {%- endif %}
+ {%- endblock %}
+ </div>
+ <div class="topnav">
+ {{ nav() }}
+ </div>
+ <div class="content">
+ {#{%- if display_toc %}
+ <div id="toc">
+ <h3>Table Of Contents</h3>
+ {{ toc }}
+ </div>
+ {%- endif %}#}
+ {% block body %}{% endblock %}
+ </div>
+ <div class="bottomnav">
+ {{ nav() }}
+ </div>
+{% endblock %}
diff --git a/docs/api/clientxmpp.rst b/docs/api/clientxmpp.rst
new file mode 100644
index 00000000..1c5055a9
--- /dev/null
+++ b/docs/api/clientxmpp.rst
@@ -0,0 +1,19 @@
+==========
+clientxmpp
+==========
+
+.. module:: sleekxmpp.clientxmpp
+
+.. autodata:: SRV_SUPPORT
+
+.. autoclass:: ClientXMPP
+
+ .. automethod:: connect
+
+ .. automethod:: register_feature
+
+ .. automethod:: get_roster
+
+ .. automethod:: update_roster
+
+ .. automethod:: del_roster_item
diff --git a/docs/architecture.rst b/docs/architecture.rst
new file mode 100644
index 00000000..53c326e1
--- /dev/null
+++ b/docs/architecture.rst
@@ -0,0 +1,269 @@
+.. index:: XMLStream, BaseXMPP, ClientXMPP, ComponentXMPP
+
+SleekXMPP Architecture
+======================
+
+The core of SleekXMPP is contained in four classes: ``XMLStream``,
+``BaseXMPP``, ``ClientXMPP``, and ``ComponentXMPP``. Along side this
+stack is a library for working with XML objects that eliminates most
+of the tedium of creating/manipulating XML.
+
+.. image:: _static/images/arch_layers.png
+ :height: 300px
+ :align: center
+
+
+.. index:: XMLStream
+
+The Foundation: XMLStream
+-------------------------
+``XMLStream`` is a mostly XMPP-agnostic class whose purpose is to read
+and write from a bi-directional XML stream. It also allows for callback
+functions to execute when XML matching given patterns is received; these
+callbacks are also referred to as :term:`stream handlers <stream handler>`.
+The class also provides a basic eventing system which can be triggered
+either manually or on a timed schedule.
+
+The Main Threads
+~~~~~~~~~~~~~~~~
+``XMLStream`` instances run using at least three background threads: the
+send thread, the read thread, and the scheduler thread. The send thread is
+in charge of monitoring the send queue and writing text to the outgoing
+XML stream. The read thread pulls text off of the incoming XML stream and
+stores the results in an event queue. The scheduler thread is used to emit
+events after a given period of time.
+
+Additionally, the main event processing loop may be executed in its
+own thread if SleekXMPP is being used in the background for another
+application.
+
+Short-lived threads may also be spawned as requested for threaded
+:term:`event handlers <event handler>`.
+
+How XML Text is Turned into Action
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To demonstrate the flow of information, let's consider what happens
+when this bit of XML is received (with an assumed namespace of
+``jabber:client``):
+
+.. code-block:: xml
+
+ <message to="user@example.com" from="friend@example.net">
+ <body>Hej!</body>
+ </message>
+
+
+1. **Convert XML strings into objects.**
+
+ Incoming text is parsed and converted into XML objects (using
+ ElementTree) which are then wrapped into what are referred to as
+ :term:`Stanza objects <stanza object>`. The appropriate class for the
+ new object is determined using a map of namespaced element names to
+ classes.
+
+ Our incoming XML is thus turned into a ``Message`` :term:`stanza object`
+ because the namespaced element name ``{jabber:client}message`` is
+ associated with the class ``sleekxmpp.stanza.Message``.
+
+2. **Match stanza objects to callbacks.**
+
+ These objects are then compared against the stored patterns associated
+ with the registered callback handlers. For each match, a copy of the
+ :term:`stanza object` is paired with a reference to the handler and
+ placed into the event queue.
+
+ Our ``Message`` object is thus paired with the message stanza handler
+ ``BaseXMPP._handle_message`` to create the tuple::
+
+ ('stanza', stanza_obj, handler)
+
+3. **Process the event queue.**
+
+ The event queue is the heart of SleekXMPP. Nearly every action that
+ takes place is first inserted into this queue, whether that be received
+ stanzas, custom events, or scheduled events.
+
+ When the stanza is pulled out of the event queue with an associated
+ callback, the callback function is executed with the stanza as its only
+ parameter.
+
+ .. warning::
+ The callback, aka :term:`stream handler`, is executed in the main
+ processing thread. If the handler blocks, event processing will also
+ block.
+
+4. **Raise Custom Events**
+
+ Since a :term:`stream handler` shouldn't block, if extensive processing
+ for a stanza is required (such as needing to send and receive an
+ ``Iq`` stanza), then custom events must be used. These events are not
+ explicitly tied to the incoming XML stream and may be raised at any
+ time. Importantly, these events may be handled in their own thread.
+
+ When the event is raised, a copy of the stanza is created for each
+ handler registered for the event. In contrast to :term:`stream handlers <stream handler>`,
+ these functions are referred to as :term:`event handlers <event handler>`.
+ Each stanza/handler pair is then put into the event queue.
+
+ .. note::
+ It is possible to skip the event queue and process an event immediately
+ by using ``direct=True`` when raising the event.
+
+ The code for ``BaseXMPP._handle_message`` follows this pattern, and
+ raises a ``'message'`` event::
+
+ self.event('message', msg)
+
+ The event call then places the message object back into the event queue
+ paired with an :term:`event handler`::
+
+ ('event', 'message', msg_copy1, custom_event_handler_1)
+ ('event', 'message', msg_copy2, custom_evetn_handler_2)
+
+5. **Process Custom Events**
+
+ The stanza and :term:`event handler` are then pulled from the event
+ queue, and the handler is executed, passing the stanza as its only
+ argument. If the handler was registered as threaded, then a new thread
+ will be spawned for it.
+
+ .. note::
+ Events may be raised without needing :term:`stanza objects <stanza object>`.
+ For example, you could use ``self.event('custom', {'a': 'b'})``.
+ You don't even need any arguments: ``self.event('no_parameters')``.
+ However, every event handler MUST accept at least one argument.
+
+ Finally, after a long trek, our message is handed off to the user's
+ custom handler in order to do awesome stuff::
+
+ msg.reply()
+ msg['body'] = "Hey! This is awesome!"
+ msg.send()
+
+
+.. index:: BaseXMPP, XMLStream
+
+Raising XMPP Awareness: BaseXMPP
+--------------------------------
+While ``XMLStream`` attempts to shy away from anything too XMPP specific,
+``BaseXMPP``'s sole purpose is to provide foundational support for sending
+and receiving XMPP stanzas. This support includes registering the basic
+message, presence, and iq stanzas, methods for creating and sending
+stanzas, and default handlers for incoming messages and keeping track of
+presence notifications.
+
+The plugin system for adding new XEP support is also maintained by
+``BaseXMPP``.
+
+.. index:: ClientXMPP, BaseXMPP
+
+ClientXMPP
+----------
+``ClientXMPP`` extends ``BaseXMPP`` with additional logic for connecting to
+an XMPP server by performing DNS lookups. It also adds support for stream
+features such as STARTTLS and SASL.
+
+.. index:: ComponentXMPP, BaseXMPP
+
+ComponentXMPP
+-------------
+``ComponentXMPP`` is only a thin layer on top of ``BaseXMPP`` that
+implements the component handshake protocol.
+
+.. index::
+ double: object; stanza
+
+Stanza Objects: A Brief Look
+----------------------------
+.. seealso::
+ See :ref:`api-stanza-objects` for a more detailed overview.
+
+Almost worthy of their own standalone library, :term:`stanza objects <stanza object>`
+are wrappers for XML objects which expose dictionary like interfaces
+for manipulating their XML content. For example, consider the XML:
+
+.. code-block:: xml
+
+ <message />
+
+A very plain element to start with, but we can create a :term:`stanza object`
+using ``sleekxmpp.stanza.Message`` as so::
+
+ msg = Message(xml=ET.fromstring("<message />"))
+
+The ``Message`` stanza class defines interfaces such as ``'body'`` and
+``'to'``, so we can assign values to those interfaces to include new XML
+content::
+
+ msg['body'] = "Following so far?"
+ msg['to'] = 'user@example.com'
+
+Dumping the XML content of ``msg`` (using ``msg.xml``), we find:
+
+.. code-block:: xml
+
+ <message to="user@example.com">
+ <body>Following so far?</body>
+ </message>
+
+The process is similar for reading from interfaces and deleting interface
+contents. A :term:`stanza object` behaves very similarly to a regular
+``dict`` object: you may assign to keys, read from keys, and ``del`` keys.
+
+Stanza interfaces come with built-in behaviours such as adding/removing
+attribute and sub element values. However, a lot of the time more custom
+logic is needed. This can be provided by defining methods of the form
+``get_*``, ``set_*``, and ``del_*`` for any interface which requires custom
+behaviour.
+
+Stanza Plugins
+~~~~~~~~~~~~~~
+Since it is generally possible to embed one XML element inside another,
+:term:`stanza objects <stanza object>` may be nested. Nested
+:term:`stanza objects <stanza object>` are referred to as :term:`stanza plugins <stanza plugin>`
+or :term:`substanzas <substanza>`.
+
+A :term:`stanza plugin` exposes its own interfaces by adding a new
+interface to its parent stanza. To demonstrate, consider these two stanza
+class definitions using ``sleekxmpp.xmlstream.ElementBase``:
+
+
+.. code-block:: python
+
+ class Parent(ElementBase):
+ name = "the-parent-xml-element-name"
+ namespace = "the-parent-namespace"
+ interfaces = set(('foo', 'bar'))
+
+ class Child(ElementBase):
+ name = "the-child-xml-element-name"
+ namespace = "the-child-namespace"
+ plugin_attrib = 'child'
+ interfaces = set(('baz',))
+
+
+If we register the ``Child`` stanza as a plugin of the ``Parent`` stanza as
+so, using ``sleekxmpp.xmlstream.register_stanza_plugin``::
+
+ register_stanza_plugin(Parent, Child)
+
+Then we can access content in the child stanza through the parent.
+Note that the interface used to access the child stanza is the same as
+``Child.plugin_attrib``::
+
+ parent = Parent()
+ parent['foo'] = 'a'
+ parent['child']['baz'] = 'b'
+
+The above code would produce:
+
+.. code-block:: xml
+
+ <the-parent-xml-element xmlns="the-parent-namespace" foo="a">
+ <the-child-xml-element xmlsn="the-child-namespace" baz="b" />
+ </the-parent-xml-element>
+
+It is also possible to allow a :term:`substanza` to appear multiple times
+by using ``iterable=True`` in the ``register_stanza_plugin`` call. All
+iterable :term:`substanzas <substanza>` can be accessed using a standard
+``substanzas`` interface.
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 00000000..8a165872
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+#
+# SleekXMPP documentation build configuration file, created by
+# sphinx-quickstart on Tue Aug 9 22:27:06 2011.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'SleekXMPP'
+copyright = u'2011, Nathan Fritz, Lance Stout'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '1.0'
+# The full version, including alpha/beta/rc tags.
+release = '1.0RC1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'default'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'haiku'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {'headingcolor': '#CFCFCF', 'linkcolor': '#4A7389'}
+
+# 00ADEE
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+html_title = 'SleekXMPP'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+html_short_title = '%s Documentation' % release
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = {
+}
+
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'SleekXMPPdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'SleekXMPP.tex', u'SleekXMPP Documentation',
+ u'Nathan Fritz, Lance Stout', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'sleekxmpp', u'SleekXMPP Documentation',
+ [u'Nathan Fritz, Lance Stout'], 1)
+]
diff --git a/docs/create_plugin.rst b/docs/create_plugin.rst
new file mode 100644
index 00000000..112ef505
--- /dev/null
+++ b/docs/create_plugin.rst
@@ -0,0 +1,677 @@
+Creating a SleekXMPP Plugin
+===========================
+
+One of the goals of SleekXMPP is to provide support for every draft or final
+XMPP extension (`XEP <http://xmpp.org/extensions/>`_). To do this, SleekXMPP has a
+plugin mechanism for adding the functionalities required by each XEP. But even
+though plugins were made to quickly implement and prototype the official XMPP
+extensions, there is no reason you can't create your own plugin to implement
+your own custom XMPP-based protocol.
+
+This guide will help walk you through the steps to
+implement a rudimentary version of `XEP-0077 In-band
+Registration <http://xmpp.org/extensions/xep-0077.html>`_. In-band registration
+was implemented in example 14-6 (page 223) of `XMPP: The Definitive
+Guide <http://oreilly.com/catalog/9780596521271>`_ because there was no SleekXMPP
+plugin for XEP-0077 at the time of writing. We will partially fix that issue
+here by turning the example implementation from *XMPP: The Definitive Guide*
+into a plugin. Again, note that this will not a complete implementation, and a
+different, more robust, official plugin for XEP-0077 may be added to SleekXMPP
+in the future.
+
+.. note::
+
+ The example plugin created in this guide is for the server side of the
+ registration process only. It will **NOT** be able to register new accounts
+ on an XMPP server.
+
+First Steps
+-----------
+Every plugin inherits from the class :mod:`base_plugin <sleekxmpp.plugins.base.base_plugin>`,
+and must include a ``plugin_init`` method. While the
+plugins distributed with SleekXMPP must be placed in the plugins directory
+``sleekxmpp/plugins`` to be loaded, custom plugins may be loaded from any
+module. To do so, use the following form when registering the plugin:
+
+.. code-block:: python
+
+ self.register_plugin('myplugin', module=mod_containing_my_plugin)
+
+The plugin name must be the same as the plugin's class name.
+
+Now, we can open our favorite text editors and create ``xep_0077.py`` in
+``SleekXMPP/sleekxmpp/plugins``. We want to do some basic house-keeping and
+declare the name and description of the XEP we are implementing. If you
+are creating your own custom plugin, you don't need to include the ``xep``
+attribute.
+
+.. code-block:: python
+
+ """
+ Creating a SleekXMPP Plugin
+
+ This is a minimal implementation of XEP-0077 to serve
+ as a tutorial for creating SleekXMPP plugins.
+ """
+
+ from sleekxmpp.plugins.base import base_plugin
+
+ class xep_0077(base_plugin):
+ """
+ XEP-0077 In-Band Registration
+ """
+
+ def plugin_init(self):
+ self.description = "In-Band Registration"
+ self.xep = "0077"
+
+Now that we have a basic plugin, we need to edit
+``sleekxmpp/plugins/__init__.py`` to include our new plugin by adding
+``'xep_0077'`` to the ``__all__`` declaration.
+
+Interacting with Other Plugins
+------------------------------
+
+In-band registration is a feature that should be advertised through `Service
+Discovery <http://xmpp.org/extensions/xep-0030.html>`_. To do that, we tell the
+``xep_0030`` plugin to add the ``"jabber:iq:register"`` feature. We put this
+call in a method named ``post_init`` which will be called once the plugin has
+been loaded; by doing so we advertise that we can do registrations only after we
+finish activating the plugin.
+
+The ``post_init`` method needs to call ``base_plugin.post_init(self)``
+which will mark that ``post_init`` has been called for the plugin. Once the
+SleekXMPP object begins processing, ``post_init`` will be called on any plugins
+that have not already run ``post_init``. This allows you to register plugins and
+their dependencies without needing to worry about the order in which you do so.
+
+**Note:** by adding this call we have introduced a dependency on the XEP-0030
+plugin. Be sure to register ``'xep_0030'`` as well as ``'xep_0077'``. SleekXMPP
+does not automatically load plugin dependencies for you.
+
+.. code-block:: python
+
+ def post_init(self):
+ base_plugin.post_init(self)
+ self.xmpp['xep_0030'].add_feature("jabber:iq:register")
+
+Creating Custom Stanza Objects
+------------------------------
+
+Now, the IQ stanzas needed to implement our version of XEP-0077 are not very
+complex, and we could just interact with the XML objects directly just like
+in the *XMPP: The Definitive Guide* example. However, creating custom stanza
+objects is good practice.
+
+We will create a new ``Registration`` stanza. Following the *XMPP: The
+Definitive Guide* example, we will add support for a username and password
+field. We also need two flags: ``registered`` and ``remove``. The ``registered``
+flag is sent when an already registered user attempts to register, along with
+their registration data. The ``remove`` flag is a request to unregister a user's
+account.
+
+Adding additional `fields specified in
+XEP-0077 <http://xmpp.org/extensions/xep-0077.html#registrar-formtypes-register>`_
+will not be difficult and is left as an exercise for the reader.
+
+Our ``Registration`` class needs to start with a few descriptions of its
+behaviour:
+
+* ``namespace``
+ The namespace our stanza object lives in. In this case,
+ ``"jabber:iq:register"``.
+
+* ``name``
+ The name of the root XML element. In this case, the ``query`` element.
+
+* ``plugin_attrib``
+ The name to access this type of stanza. In particular, given a
+ registration stanza, the ``Registration`` object can be found using:
+ ``iq_object['register']``.
+
+* ``interfaces``
+ A list of dictionary-like keys that can be used with the stanza object.
+ When using ``"key"``, if there exists a method of the form ``getKey``,
+ ``setKey``, or``delKey`` (depending on context) then the result of calling
+ that method will be returned. Otherwise, the value of the attribute ``key``
+ of the main stanza element is returned if one exists.
+
+ **Note:** The accessor methods currently use title case, and not camel case.
+ Thus if you need to access an item named ``"methodName"`` you will need to
+ use ``getMethodname``. This naming convention might change to full camel
+ case in a future version of SleekXMPP.
+
+* ``sub_interfaces``
+ A subset of ``interfaces``, but these keys map to the text of any
+ subelements that are direct children of the main stanza element. Thus,
+ referencing ``iq_object['register']['username']`` will either execute
+ ``getUsername`` or return the value in the ``username`` element of the
+ query.
+
+ If you need to access an element, say ``elem``, that is not a direct child
+ of the main stanza element, you will need to add ``getElem``, ``setElem``,
+ and ``delElem``. See the note above about naming conventions.
+
+.. code-block:: python
+
+ from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
+ from sleekxmpp import Iq
+
+ class Registration(ElementBase):
+ namespace = 'jabber:iq:register'
+ name = 'query'
+ plugin_attrib = 'register'
+ interfaces = set(('username', 'password', 'registered', 'remove'))
+ sub_interfaces = interfaces
+
+ def getRegistered(self):
+ present = self.xml.find('{%s}registered' % self.namespace)
+ return present is not None
+
+ def getRemove(self):
+ present = self.xml.find('{%s}remove' % self.namespace)
+ return present is not None
+
+ def setRegistered(self, registered):
+ if registered:
+ self.addField('registered')
+ else:
+ del self['registered']
+
+ def setRemove(self, remove):
+ if remove:
+ self.addField('remove')
+ else:
+ del self['remove']
+
+ def addField(self, name):
+ itemXML = ET.Element('{%s}%s' % (self.namespace, name))
+ self.xml.append(itemXML)
+
+Setting a ``sub_interface`` attribute to ``""`` will remove that subelement.
+Since we want to include empty registration fields in our form, we need the
+``addField`` method to add the empty elements.
+
+Since the ``registered`` and ``remove`` elements are just flags, we need to add
+custom logic to enforce the binary behavior.
+
+Extracting Stanzas from the XML Stream
+--------------------------------------
+
+Now that we have a custom stanza object, we need to be able to detect when we
+receive one. To do this, we register a stream handler that will pattern match
+stanzas off of the XML stream against our stanza object's element name and
+namespace. To do so, we need to create a ``Callback`` object which contains
+an XML fragment that can identify our stanza type. We can add this handler
+registration to our ``plugin_init`` method.
+
+Also, we need to associate our ``Registration`` class with IQ stanzas;
+that requires the use of the ``register_stanza_plugin`` function (in
+``sleekxmpp.xmlstream.stanzabase``) which takes the class of a parent stanza
+type followed by the substanza type. In our case, the parent stanza is an IQ
+stanza, and the substanza is our registration query.
+
+The ``__handleRegistration`` method referenced in the callback will be our
+handler function to process registration requests.
+
+.. code-block:: python
+
+ def plugin_init(self):
+ self.description = "In-Band Registration"
+ self.xep = "0077"
+
+ self.xmpp.registerHandler(
+ Callback('In-Band Registration',
+ MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns),
+ self.__handleRegistration))
+ register_stanza_plugin(Iq, Registration)
+
+Handling Incoming Stanzas and Triggering Events
+-----------------------------------------------
+There are six situations that we need to handle to finish our implementation of
+XEP-0077.
+
+**Registration Form Request from a New User:**
+
+ .. code-block:: xml
+
+ <iq type="result">
+ <query xmlns="jabber:iq:register">
+ <username />
+ <password />
+ </query>
+ </iq>
+
+**Registration Form Request from an Existing User:**
+
+ .. code-block:: xml
+
+ <iq type="result">
+ <query xmlns="jabber:iq:register">
+ <registered />
+ <username>Foo</username>
+ <password>hunter2</password>
+ </query>
+ </iq>
+
+**Unregister Account:**
+
+ .. code-block:: xml
+
+ <iq type="result">
+ <query xmlns="jabber:iq:register" />
+ </iq>
+
+**Incomplete Registration:**
+
+ .. code-block:: xml
+
+ <iq type="error">
+ <query xmlns="jabber:iq:register">
+ <username>Foo</username>
+ </query>
+ <error code="406" type="modify">
+ <not-acceptable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
+ </error>
+ </iq>
+
+**Conflicting Registrations:**
+
+ .. code-block:: xml
+
+ <iq type="error">
+ <query xmlns="jabber:iq:register">
+ <username>Foo</username>
+ <password>hunter2</password>
+ </query>
+ <error code="409" type="cancel">
+ <conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" />
+ </error>
+ </iq>
+
+**Successful Registration:**
+
+ .. code-block:: xml
+
+ <iq type="result">
+ <query xmlns="jabber:iq:register" />
+ </iq>
+
+Cases 1 and 2: Registration Requests
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Responding to registration requests depends on if the requesting user already
+has an account. If there is an account, the response should include the
+``registered`` flag and the user's current registration information. Otherwise,
+we just send the fields for our registration form.
+
+We will handle both cases by creating a ``sendRegistrationForm`` method that
+will create either an empty of full form depending on if we provide it with
+user data. Since we need to know which form fields to include (especially if we
+add support for the other fields specified in XEP-0077), we will also create a
+method ``setForm`` which will take the names of the fields we wish to include.
+
+.. code-block:: python
+
+ def plugin_init(self):
+ self.description = "In-Band Registration"
+ self.xep = "0077"
+ self.form_fields = ('username', 'password')
+ ... remainder of plugin_init
+
+ ...
+
+ def __handleRegistration(self, iq):
+ if iq['type'] == 'get':
+ # Registration form requested
+ userData = self.backend[iq['from'].bare]
+ self.sendRegistrationForm(iq, userData)
+
+ def setForm(self, *fields):
+ self.form_fields = fields
+
+ def sendRegistrationForm(self, iq, userData=None):
+ reg = iq['register']
+ if userData is None:
+ userData = {}
+ else:
+ reg['registered'] = True
+
+ for field in self.form_fields:
+ data = userData.get(field, '')
+ if data:
+ # Add field with existing data
+ reg[field] = data
+ else:
+ # Add a blank field
+ reg.addField(field)
+
+ iq.reply().setPayload(reg.xml)
+ iq.send()
+
+Note how we are able to access our ``Registration`` stanza object with
+``iq['register']``.
+
+A User Backend
+++++++++++++++
+You might have noticed the reference to ``self.backend``, which is an object
+that abstracts away storing and retrieving user information. Since it is not
+much more than a dictionary, we will leave the implementation details to the
+final, full source code example.
+
+Case 3: Unregister an Account
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The next simplest case to consider is responding to a request to remove
+an account. If we receive a ``remove`` flag, we instruct the backend to
+remove the user's account. Since your application may need to know about
+when users are registered or unregistered, we trigger an event using
+``self.xmpp.event('unregister_user', iq)``. See the component examples below for
+how to respond to that event.
+
+.. code-block:: python
+
+ def __handleRegistration(self, iq):
+ if iq['type'] == 'get':
+ # Registration form requested
+ userData = self.backend[iq['from'].bare]
+ self.sendRegistrationForm(iq, userData)
+ elif iq['type'] == 'set':
+ # Remove an account
+ if iq['register']['remove']:
+ self.backend.unregister(iq['from'].bare)
+ self.xmpp.event('unregistered_user', iq)
+ iq.reply().send()
+ return
+
+Case 4: Incomplete Registration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+For the next case we need to check the user's registration to ensure it has all
+of the fields we wanted. The simple option that we will use is to loop over the
+field names and check each one; however, this means that all fields we send to
+the user are required. Adding optional fields is left to the reader.
+
+Since we have received an incomplete form, we need to send an error message back
+to the user. We have to send a few different types of errors, so we will also
+create a ``_sendError`` method that will add the appropriate ``error`` element
+to the IQ reply.
+
+.. code-block:: python
+
+ def __handleRegistration(self, iq):
+ if iq['type'] == 'get':
+ # Registration form requested
+ userData = self.backend[iq['from'].bare]
+ self.sendRegistrationForm(iq, userData)
+ elif iq['type'] == 'set':
+ if iq['register']['remove']:
+ # Remove an account
+ self.backend.unregister(iq['from'].bare)
+ self.xmpp.event('unregistered_user', iq)
+ iq.reply().send()
+ return
+
+ for field in self.form_fields:
+ if not iq['register'][field]:
+ # Incomplete Registration
+ self._sendError(iq, '406', 'modify', 'not-acceptable'
+ "Please fill in all fields.")
+ return
+
+ ...
+
+ def _sendError(self, iq, code, error_type, name, text=''):
+ iq.reply().setPayload(iq['register'].xml)
+ iq.error()
+ iq['error']['code'] = code
+ iq['error']['type'] = error_type
+ iq['error']['condition'] = name
+ iq['error']['text'] = text
+ iq.send()
+
+Cases 5 and 6: Conflicting and Successful Registration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We are down to the final decision on if we have a successful registration. We
+send the user's data to the backend with the ``self.backend.register`` method.
+If it returns ``True``, then registration has been successful. Otherwise,
+there has been a conflict with usernames and registration has failed. Like
+with unregistering an account, we trigger an event indicating that a user has
+been registered by using ``self.xmpp.event('registered_user', iq)``. See the
+component examples below for how to respond to this event.
+
+.. code-block:: python
+
+ def __handleRegistration(self, iq):
+ if iq['type'] == 'get':
+ # Registration form requested
+ userData = self.backend[iq['from'].bare]
+ self.sendRegistrationForm(iq, userData)
+ elif iq['type'] == 'set':
+ if iq['register']['remove']:
+ # Remove an account
+ self.backend.unregister(iq['from'].bare)
+ self.xmpp.event('unregistered_user', iq)
+ iq.reply().send()
+ return
+
+ for field in self.form_fields:
+ if not iq['register'][field]:
+ # Incomplete Registration
+ self._sendError(iq, '406', 'modify', 'not-acceptable',
+ "Please fill in all fields.")
+ return
+
+ if self.backend.register(iq['from'].bare, iq['register']):
+ # Successful registration
+ self.xmpp.event('registered_user', iq)
+ iq.reply().setPayload(iq['register'].xml)
+ iq.send()
+ else:
+ # Conflicting registration
+ self._sendError(iq, '409', 'cancel', 'conflict',
+ "That username is already taken.")
+
+Example Component Using the XEP-0077 Plugin
+-------------------------------------------
+Alright, the moment we've been working towards - actually using our plugin to
+simplify our other applications. Here is a basic component that simply manages
+user registrations and sends the user a welcoming message when they register,
+and a farewell message when they delete their account.
+
+Note that we have to register the ``'xep_0030'`` plugin first,
+and that we specified the form fields we wish to use with
+``self.xmpp.plugin['xep_0077'].setForm('username', 'password')``.
+
+.. code-block:: python
+
+ import sleekxmpp.componentxmpp
+
+ class Example(sleekxmpp.componentxmpp.ComponentXMPP):
+
+ def __init__(self, jid, password):
+ sleekxmpp.componentxmpp.ComponentXMPP.__init__(self, jid, password, 'localhost', 8888)
+
+ self.registerPlugin('xep_0030')
+ self.registerPlugin('xep_0077')
+ self.plugin['xep_0077'].setForm('username', 'password')
+
+ self.add_event_handler("registered_user", self.reg)
+ self.add_event_handler("unregistered_user", self.unreg)
+
+ def reg(self, iq):
+ msg = "Welcome! %s" % iq['register']['username']
+ self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
+
+ def unreg(self, iq):
+ msg = "Bye! %s" % iq['register']['username']
+ self.sendMessage(iq['from'], msg, mfrom=self.fulljid)
+
+**Congratulations!** We now have a basic, functioning implementation of
+XEP-0077.
+
+Complete Source Code for XEP-0077 Plugin
+----------------------------------------
+Here is a copy of a more complete implementation of the plugin we created, but
+with some additional registration fields implemented.
+
+.. code-block:: python
+
+ """
+ Creating a SleekXMPP Plugin
+
+ This is a minimal implementation of XEP-0077 to serve
+ as a tutorial for creating SleekXMPP plugins.
+ """
+
+ from sleekxmpp.plugins.base import base_plugin
+ from sleekxmpp.xmlstream.handler.callback import Callback
+ from sleekxmpp.xmlstream.matcher.xpath import MatchXPath
+ from sleekxmpp.xmlstream import ElementBase, ET, JID, register_stanza_plugin
+ from sleekxmpp import Iq
+ import copy
+
+
+ class Registration(ElementBase):
+ namespace = 'jabber:iq:register'
+ name = 'query'
+ plugin_attrib = 'register'
+ interfaces = set(('username', 'password', 'email', 'nick', 'name',
+ 'first', 'last', 'address', 'city', 'state', 'zip',
+ 'phone', 'url', 'date', 'misc', 'text', 'key',
+ 'registered', 'remove', 'instructions'))
+ sub_interfaces = interfaces
+
+ def getRegistered(self):
+ present = self.xml.find('{%s}registered' % self.namespace)
+ return present is not None
+
+ def getRemove(self):
+ present = self.xml.find('{%s}remove' % self.namespace)
+ return present is not None
+
+ def setRegistered(self, registered):
+ if registered:
+ self.addField('registered')
+ else:
+ del self['registered']
+
+ def setRemove(self, remove):
+ if remove:
+ self.addField('remove')
+ else:
+ del self['remove']
+
+ def addField(self, name):
+ itemXML = ET.Element('{%s}%s' % (self.namespace, name))
+ self.xml.append(itemXML)
+
+
+ class UserStore(object):
+ def __init__(self):
+ self.users = {}
+
+ def __getitem__(self, jid):
+ return self.users.get(jid, None)
+
+ def register(self, jid, registration):
+ username = registration['username']
+
+ def filter_usernames(user):
+ return user != jid and self.users[user]['username'] == username
+
+ conflicts = filter(filter_usernames, self.users.keys())
+ if conflicts:
+ return False
+
+ self.users[jid] = registration
+ return True
+
+ def unregister(self, jid):
+ del self.users[jid]
+
+ class xep_0077(base_plugin):
+ """
+ XEP-0077 In-Band Registration
+ """
+
+ def plugin_init(self):
+ self.description = "In-Band Registration"
+ self.xep = "0077"
+ self.form_fields = ('username', 'password')
+ self.form_instructions = ""
+ self.backend = UserStore()
+
+ self.xmpp.registerHandler(
+ Callback('In-Band Registration',
+ MatchXPath('{%s}iq/{jabber:iq:register}query' % self.xmpp.default_ns),
+ self.__handleRegistration))
+ register_stanza_plugin(Iq, Registration)
+
+ def post_init(self):
+ base_plugin.post_init(self)
+ self.xmpp['xep_0030'].add_feature("jabber:iq:register")
+
+ def __handleRegistration(self, iq):
+ if iq['type'] == 'get':
+ # Registration form requested
+ userData = self.backend[iq['from'].bare]
+ self.sendRegistrationForm(iq, userData)
+ elif iq['type'] == 'set':
+ if iq['register']['remove']:
+ # Remove an account
+ self.backend.unregister(iq['from'].bare)
+ self.xmpp.event('unregistered_user', iq)
+ iq.reply().send()
+ return
+
+ for field in self.form_fields:
+ if not iq['register'][field]:
+ # Incomplete Registration
+ self._sendError(iq, '406', 'modify', 'not-acceptable',
+ "Please fill in all fields.")
+ return
+
+ if self.backend.register(iq['from'].bare, iq['register']):
+ # Successful registration
+ self.xmpp.event('registered_user', iq)
+ iq.reply().setPayload(iq['register'].xml)
+ iq.send()
+ else:
+ # Conflicting registration
+ self._sendError(iq, '409', 'cancel', 'conflict',
+ "That username is already taken.")
+
+ def setForm(self, *fields):
+ self.form_fields = fields
+
+ def setInstructions(self, instructions):
+ self.form_instructions = instructions
+
+ def sendRegistrationForm(self, iq, userData=None):
+ reg = iq['register']
+ if userData is None:
+ userData = {}
+ else:
+ reg['registered'] = True
+
+ if self.form_instructions:
+ reg['instructions'] = self.form_instructions
+
+ for field in self.form_fields:
+ data = userData.get(field, '')
+ if data:
+ # Add field with existing data
+ reg[field] = data
+ else:
+ # Add a blank field
+ reg.addField(field)
+
+ iq.reply().setPayload(reg.xml)
+ iq.send()
+
+ def _sendError(self, iq, code, error_type, name, text=''):
+ iq.reply().setPayload(iq['register'].xml)
+ iq.error()
+ iq['error']['code'] = code
+ iq['error']['type'] = error_type
+ iq['error']['condition'] = name
+ iq['error']['text'] = text
+ iq.send()
diff --git a/docs/event_index.rst b/docs/event_index.rst
new file mode 100644
index 00000000..2c5dfd39
--- /dev/null
+++ b/docs/event_index.rst
@@ -0,0 +1,271 @@
+Event Index
+===========
+
+.. glossary::
+ :sorted:
+
+ connected
+ - **Data:** ``{}``
+ - **Source:** :py:class:`~sleekxmpp.clientxmpp.ClientXMPP`
+
+ Signal that a connection has been made with the XMPP server, but a session
+ has not yet been established.
+
+ changed_status
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ Triggered when a presence stanza is received from a JID with a show type
+ different than the last presence stanza from the same JID.
+
+ changed_subscription
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ Triggered whenever a presence stanza with a type of ``subscribe``,
+ ``subscribed``, ``unsubscribe``, or ``unsubscribed`` is received.
+
+ Note that if the values ``xmpp.auto_authorize`` and ``xmpp.auto_subscribe``
+ are set to ``True`` or ``False``, and not ``None``, then SleekXMPP will
+ either accept or reject all subscription requests before your event handlers
+ are called. Set these values to ``None`` if you wish to make more complex
+ subscription decisions.
+
+ chatstate_active
+ - **Data:**
+ - **Source:**
+
+ chatstate_composing
+ - **Data:**
+ - **Source:**
+
+ chatstate_gone
+ - **Data:**
+ - **Source:**
+
+ chatstate_inactive
+ - **Data:**
+ - **Source:**
+
+ chatstate_paused
+ - **Data:**
+ - **Source:**
+
+ disco_info
+ - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoInfo`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
+
+ Triggered whenever a ``disco#info`` result stanza is received.
+
+ disco_items
+ - **Data:** :py:class:`~sleekxmpp.plugins.xep_0030.stanza.DiscoItems`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0030.disco.xep_0030`
+
+ Triggered whenever a ``disco#items`` result stanza is received.
+
+ disconnected
+ - **Data:** ``{}``
+ - **Source:** :py:class:`~sleekxmpp.ClientXMPP`
+
+ Signal that the connection with the XMPP server has been lost.
+
+ entity_time
+ - **Data:**
+ - **Source:**
+
+ failed_auth
+ - **Data:** ``{}``
+ - **Source:** :py:class:`~sleekxmpp.ClientXMPP`, :py:class:`~sleekxmpp.plugins.xep_0078.xep_0078`
+
+ Signal that the server has rejected the provided login credentials.
+
+ gmail_notify
+ - **Data:** ``{}``
+ - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
+
+ Signal that there are unread emails for the Gmail account associated with the current XMPP account.
+
+ gmail_messages
+ - **Data:** :py:class:`~sleekxmpp.Iq`
+ - **Source:** :py:class:`~sleekxmpp.plugins.gmail_notify.gmail_notify`
+
+ Signal that there are unread emails for the Gmail account associated with the current XMPP account.
+
+ got_online
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ If a presence stanza is received from a JID which was previously marked as
+ offline, and the presence has a show type of '``chat``', '``dnd``', '``away``',
+ or '``xa``', then this event is triggered as well.
+
+ got_offline
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ Signal that an unavailable presence stanza has been received from a JID.
+
+ groupchat_invite
+ - **Data:**
+ - **Source:**
+
+ groupchat_direct_invite
+ - **Data:** :py:class:`~sleekxmpp.Message`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0249.direct`
+
+ groupchat_message
+ - **Data:** :py:class:`~sleekxmpp.Message`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
+
+ Triggered whenever a message is received from a multi-user chat room.
+
+ groupchat_presence
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
+
+ Triggered whenever a presence stanza is received from a user in a multi-user chat room.
+
+ groupchat_subject
+ - **Data:** :py:class:`~sleekxmpp.Message`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0045.xep_0045`
+
+ Triggered whenever the subject of a multi-user chat room is changed, or announced when joining a room.
+
+ killed
+ - **Data:**
+ - **Source:**
+
+ last_activity
+ - **Data:**
+ - **Source:**
+
+ message
+ - **Data:** :py:class:`~sleekxmpp.Message`
+ - **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>`
+
+ Makes the contents of message stanzas available whenever one is received. Be
+ sure to check the message type in order to handle error messages.
+
+ message_form
+ - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
+
+ Currently the same as :term:`message_xform`.
+
+ message_xform
+ - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
+
+ Triggered whenever a data form is received inside a message.
+
+ mucc::[room]::got_offline
+ - **Data:**
+ - **Source:**
+
+ muc::[room]::got_online
+ - **Data:**
+ - **Source:**
+
+ muc::[room]::message
+ - **Data:**
+ - **Source:**
+
+ muc::[room]::presence
+ - **Data:**
+ - **Source:**
+
+ presence_available
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``available``' is received.
+
+ presence_error
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``error``' is received.
+
+ presence_form
+ - **Data:** :py:class:`~sleekxmpp.plugins.xep_0004.Form`
+ - **Source:** :py:class:`~sleekxmpp.plugins.xep_0004.xep_0004`
+
+ This event is present in the XEP-0004 plugin code, but is currently not used.
+
+ presence_probe
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``probe``' is received.
+
+ presence_subscribe
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``subscribe``' is received.
+
+ presence_subscribed
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``subscribed``' is received.
+
+ presence_unavailable
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``unavailable``' is received.
+
+ presence_unsubscribe
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``unsubscribe``' is received.
+
+ presence_unsubscribed
+ - **Data:** :py:class:`~sleekxmpp.Presence`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
+
+ A presence stanza with a type of '``unsubscribed``' is received.
+
+ roster_update
+ - **Data:** :py:class:`~sleekxmpp.stanza.Roster`
+ - **Source:** :py:class:`~sleekxmpp.ClientXMPP`
+
+ An IQ result containing roster entries is received.
+
+ sent_presence
+ - **Data:** ``{}``
+ - **Source:** :py:class:`BaseXMPP <sleekxmpp.BaseXMPP>`
+
+ Signal that an initial presence stanza has been written to the XML stream.
+
+ session_end
+ - **Data:** ``{}``
+ - **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`,
+ :py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>`
+ :py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>`
+
+ Signal that a connection to the XMPP server has been lost and the current
+ stream session has ended. Currently equivalent to :term:`disconnected`, but
+ future implementation of `XEP-0198: Stream Management <http://xmpp.org/extensions/xep-0198.html>`_
+ will distinguish the two events.
+
+ Plugins that maintain session-based state should clear themselves when
+ this event is fired.
+
+ session_start
+ - **Data:** ``{}``
+ - **Source:** :py:class:`ClientXMPP <sleekxmpp.ClientXMPP>`,
+ :py:class:`ComponentXMPP <sleekxmpp.ComponentXMPP>`
+ :py:class:`XEP-0078 <sleekxmpp.plugins.xep_0078>`
+
+ Signal that a connection to the XMPP server has been made and a session has been established.
+
+ socket_error
+ - **Data:** ``Socket`` exception object
+ - **Source:** :py:class:`~sleekxmpp.xmlstream.XMLstream`
+
+ stream_error
+ - **Data:** :py:class:`~sleekxmpp.stanza.StreamError`
+ - **Source:** :py:class:`~sleekxmpp.BaseXMPP`
diff --git a/docs/glossary.rst b/docs/glossary.rst
new file mode 100644
index 00000000..35d2dc86
--- /dev/null
+++ b/docs/glossary.rst
@@ -0,0 +1,35 @@
+.. _glossary:
+
+Glossary
+========
+
+.. glossary::
+ :sorted:
+
+ stream handler
+ A callback function that accepts stanza objects pulled directly
+ from the XML stream. A stream handler is encapsulated in a
+ object that includes a :term:`Matcher` object, and which provides
+ additional semantics. For example, the ``Waiter`` handler wrapper
+ blocks thread execution until a matching stanza is received.
+
+ event handler
+ A callback function that responds to events raised by
+ ``XMLStream.event``. An event handler may be marked as
+ threaded, allowing it to execute outside of the main processing
+ loop.
+
+ stanza object
+ Informally may refer both to classes which extend ``ElementBase``
+ or ``StanzaBase``, and to objects of such classes.
+
+ A stanza object is a wrapper for an XML object which exposes ``dict``
+ like interfaces which may be assigned to, read from, or deleted.
+
+ stanza plugin
+ A :term:`stanza object` which has been registered as a potential child
+ of another stanza object. The plugin stanza may accessed through the
+ parent stanza using the plugin's ``plugin_attrib`` as an interface.
+
+ substanza
+ See :term:`stanza plugin`
diff --git a/docs/guide_xep_0030.rst b/docs/guide_xep_0030.rst
new file mode 100644
index 00000000..cb8d7d25
--- /dev/null
+++ b/docs/guide_xep_0030.rst
@@ -0,0 +1,201 @@
+XEP-0030: Working with Service Discovery
+========================================
+
+XMPP networks can be composed of many individual clients, components,
+and servers. Determining the JIDs for these entities and the various
+features they may support is the role of `XEP-0030, Service
+Discovery <http://xmpp.org/extensions/xep-0030.html>`_, or "disco" for short.
+
+Every XMPP entity may possess what are called nodes. A node is just a name for
+some aspect of an XMPP entity. For example, if an XMPP entity provides `Ad-Hoc
+Commands <http://xmpp.org/extensions/xep-0050.html>`_, then it will have a node
+named ``http://jabber.org/protocol/commands`` which will contain information
+about the commands provided. Other agents using these ad-hoc commands will
+interact with the information provided by this node. Note that the node name is
+just an identifier; there is no inherent meaning.
+
+Working with service discovery is about creating and querying these nodes.
+According to XEP-0030, a node may contain three types of information:
+identities, features, and items. (Further, extensible, information types are
+defined in `XEP-0128 <http://xmpp.org/extensions/xep-0128.html>`_, but they are
+not yet implemented by SleekXMPP.) SleekXMPP provides methods to configure each
+of these node attributes.
+
+Configuring Service Discovery
+-----------------------------
+The design focus for the XEP-0030 plug-in is handling info and items requests
+in a dynamic fashion, allowing for complex policy decisions of who may receive
+information and how much, or use alternate backend storage mechanisms for all
+of the disco data. To do this, each action that the XEP-0030 plug-in performs
+is handed off to what is called a "node handler," which is just a callback
+function. These handlers are arranged in a hierarchy that allows for a single
+handler to manage an entire domain of JIDs (say for a component), while allowing
+other handler functions to override that global behaviour for certain JIDs, or
+even further limited to only certain JID and node combinations.
+
+The Dynamic Handler Hierarchy
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* ``global``: (JID is None, node is None)
+
+ Handlers assigned at this level for an action (such as ``add_feature``) provide a global default
+ behaviour when the action is performed.
+
+* ``jid``: (JID assigned, node is None)
+
+ At this level, handlers provide a default behaviour for actions affecting any node owned by the
+ JID in question. This level is most useful for component connections; there is effectively no
+ difference between this and the global level when using a client connection.
+
+* ``node``: (JID assigned, node assigned)
+
+ A handler for this level is responsible for carrying out an action for only one node, and is the
+ most specific handler type available. These types of handlers will be most useful for "special"
+ nodes that require special processing different than others provided by the JID, such as using
+ access control lists, or consolidating data from other nodes.
+
+Default Static Handlers
+~~~~~~~~~~~~~~~~~~~~~~~
+The XEP-0030 plug-in provides a default set of handlers that work using in-memory
+disco stanzas. Each handler simply performs the appropriate lookup or storage
+operation using these stanzas without doing any complex operations such as
+checking an ACL, etc.
+
+You may find it necessary at some point to revert a particular node or JID to
+using the default, static handlers. To do so, use the method ``make_static()``.
+You may also elect to only convert a given set of actions instead.
+
+Creating a Node Handler
+~~~~~~~~~~~~~~~~~~~~~~~
+Every node handler receives three arguments: the JID, the node, and a data
+parameter that will contain the relevant information for carrying out the
+handler's action, typically a dictionary.
+
+The JID will always have a value, defaulting to ``xmpp.boundjid.full`` for
+components or ``xmpp.boundjid.bare`` for clients. The node value may be None or
+a string.
+
+Only handlers for the actions ``get_info`` and ``get_items`` need to have return
+values. For these actions, DiscoInfo or DiscoItems stanzas are exepected as
+output. It is also acceptable for handlers for these actions to generate an
+XMPPError exception when necessary.
+
+Example Node Handler:
++++++++++++++++++++++
+Here is one of the built-in default handlers as an example:
+
+.. code-block:: python
+
+ def add_identity(self, jid, node, data):
+ """
+ Add a new identity to the JID/node combination.
+
+ The data parameter may provide:
+ category -- The general category to which the agent belongs.
+ itype -- A more specific designation with the category.
+ name -- Optional human readable name for this identity.
+ lang -- Optional standard xml:lang value.
+ """
+ self.add_node(jid, node)
+ self.nodes[(jid, node)]['info'].add_identity(
+ data.get('category', ''),
+ data.get('itype', ''),
+ data.get('name', None),
+ data.get('lang', None))
+
+Adding Identities, Features, and Items
+--------------------------------------
+In order to maintain some backwards compatibility, the methods ``add_identity``,
+``add_feature``, and ``add_item`` do not follow the method signature pattern of
+the other API methods (i.e. jid, node, then other options), but rather retain
+the parameter orders from previous plug-in versions.
+
+Adding an Identity
+~~~~~~~~~~~~~~~~~~
+Adding an identity may be done using either the older positional notation, or
+with keyword parameters. The example below uses the keyword arguments, but in
+the same order as expected using positional arguments.
+
+.. code-block:: python
+
+ xmpp['xep_0030'].add_identity(category='client',
+ itype='bot',
+ name='Sleek',
+ node='foo',
+ jid=xmpp.boundjid.full,
+ lang='no')
+
+The JID and node values determine which handler will be used to perform the
+``add_identity`` action.
+
+The ``lang`` parameter allows for adding localized versions of identities using
+the ``xml:lang`` attribute.
+
+Adding a Feature
+~~~~~~~~~~~~~~~~
+The position ordering for ``add_feature()`` is to include the feature, then
+specify the node and then the JID. The JID and node values determine which
+handler will be used to perform the ``add_feature`` action.
+
+.. code-block:: python
+
+ xmpp['xep_0030'].add_feature(feature='jabber:x:data',
+ node='foo',
+ jid=xmpp.boundjid.full)
+
+Adding an Item
+~~~~~~~~~~~~~~
+The parameters to ``add_item()`` are potentially confusing due to the fact that
+adding an item requires two JID and node combinations: the JID and node of the
+item itself, and the JID and node that will own the item.
+
+.. code-block:: python
+
+ xmpp['xep_0030'].add_item(jid='myitemjid@example.com',
+ name='An Item!',
+ node='owner_node',
+ subnode='item_node',
+ ijid=xmpp.boundjid.full)
+
+.. note::
+
+ In this case, the owning JID and node are provided with the
+ parameters ``ijid`` and ``node``.
+
+Peforming Disco Queries
+-----------------------
+The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs
+and their nodes for disco information. Since these methods are wrappers for
+sending Iq stanzas, they also accept all of the parameters of the ``Iq.send()``
+method. The ``get_items()`` method may also accept the boolean parameter
+``iterator``, which when set to ``True`` will return an iterator object using
+the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in.
+
+.. code-block:: python
+
+ info = self['xep_0030'].get_info(jid='foo@example.com',
+ node='bar',
+ ifrom='baz@mycomponent.example.com',
+ block=True,
+ timeout=30)
+
+ items = self['xep_0030'].get_info(jid='foo@example.com',
+ node='bar',
+ iterator=True)
+
+For more examples on how to use basic disco queries, check the ``disco_browser.py``
+example in the ``examples`` directory.
+
+Local Queries
+~~~~~~~~~~~~~
+In some cases, it may be necessary to query the contents of a node owned by the
+client itself, or one of a component's many JIDs. The same method is used as for
+normal queries, with two differences. First, the parameter ``local=True`` must
+be used. Second, the return value will be a DiscoInfo or DiscoItems stanza, not
+a full Iq stanza.
+
+.. code-block:: python
+
+ info = self['xep_0030'].get_info(node='foo', local=True)
+ items = self['xep_0030'].get_items(jid='somejid@mycomponent.example.com',
+ node='bar',
+ local=True)
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 00000000..3b9e8298
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,130 @@
+SleekXMPP
+#########
+
+.. sidebar:: Get the Code
+
+ .. code-block:: sh
+
+ pip install sleekxmpp
+
+ The latest source code for SleekXMPP may be found on `Github
+ <http://github.com/fritzy/SleekXMPP>`_. Releases can be found in the
+ ``master`` branch, while the latest development version is in the
+ ``develop`` branch.
+
+ **Stable Releases**
+ - `1.0 Beta6.1 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta6.1>`_
+ - `1.0 Beta5 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta5>`_
+ - `1.0 Beta4 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta4>`_
+ - `1.0 Beta3 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta3>`_
+ - `1.0 Beta2 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta2>`_
+ - `1.0 Beta1 <http://github.com/fritzy/SleekXMPP/zipball/1.0-Beta1>`_
+
+ **Develop Releases**
+ - `Latest Develop Version <http://github.com/fritzy/SleekXMPP/zipball/develop>`_
+ - `External Roster (Based on Develop Version) <http://github.com/fritzy/SleekXMPP/zipball/roster>`_
+
+
+ A mailing list and XMPP chat room are available for discussing and getting
+ help with SleekXMPP.
+
+ **Mailing List**
+ http://groups.google.com/group/sleekxmpp-discussion
+
+ **Chat**
+ `sleek@conference.jabber.org <xmpp:sleek@conference.jabber.org?join>`_
+
+
+SleekXMPP is an :ref:`MIT licensed <license>` XMPP library for Python 2.6/3.1+,
+and is featured in examples in
+`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271>`_
+by Kevin Smith, Remko Tronçon, and Peter Saint-Andre. If you've arrived
+here from reading the Definitive Guide, please see the notes on updating
+the examples to the latest version of SleekXMPP.
+
+SleekXMPP's design goals and philosphy are:
+
+**Low number of dependencies**
+ Installing and using SleekXMPP should be as simple as possible, without
+ having to deal with long dependency chains.
+
+ As part of reducing the number of dependencies, some third party
+ modules are included with SleekXMPP in the ``thirdparty`` directory.
+ Imports from this module first try to import an existing installed
+ version before loading the packaged version, when possible.
+
+**Every XEP as a plugin**
+ Following Python's "batteries included" approach, the goal is to
+ provide support for all currently active XEPs (final and draft). Since
+ adding XEP support is done through easy to create plugins, the hope is
+ to also provide a solid base for implementing and creating experimental
+ XEPs.
+
+**Rewarding to work with**
+ As much as possible, SleekXMPP should allow things to "just work" using
+ sensible defaults and appropriate abstractions. XML can be ugly to work
+ with, but it doesn't have to be that way.
+
+SleekXMPP Architecture and Design
+---------------------------------
+.. toctree::
+ :maxdepth: 2
+
+ architecture.rst
+
+Tutorials, FAQs, and How To Guides
+----------------------------------
+.. toctree::
+ :maxdepth: 2
+
+ quickstart
+ xmpp_tdg
+ create_plugin
+ guide_xep_0030
+
+
+API Reference
+-------------
+.. toctree::
+ :maxdepth: 2
+
+ event_index
+ api/clientxmpp
+
+Additional Info
+---------------
+.. toctree::
+ :hidden:
+
+ glossary
+ license
+
+* :ref:`license`
+* :ref:`glossary`
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+Credits
+-------
+**Main Author:** Nathan Fritz
+ `fritzy@netflint.net <xmpp:fritzy@netflint.net?message>`_,
+ `@fritzy <http://twitter.com/fritzy>`_
+
+ Nathan is also the author of XMPPHP and `Seesmic-AS3-XMPP
+ <http://code.google.com/p/seesmic-as3-xmpp/>`_, and a member of the XMPP
+ Council.
+
+**Co-Author:** Lance Stout
+ `lancestout@gmail.com <xmpp:lancestout@gmail.com?message>`_,
+ `@lancestout <http://twitter.com/lancestout>`_
+
+**Contributors:**
+ - Brian Beggs (`macdiesel <http://github.com/macdiesel>`_)
+ - Dann Martens (`dannmartens <http://github.com/dannmartens>`_)
+ - Florent Le Coz (`louiz <http://github.com/louiz>`_)
+ - Kevin Smith (`Kev <http://github.com/Kev>`_, http://kismith.co.uk)
+ - Remko Tronçon (`remko <http://github.com/remko>`_, http://el-tramo.be)
+ - Te-jé Rogers (`te-je <http://github.com/te-je>`_)
+ - Thom Nichols (`tomstrummer <http://github.com/tomstrummer>`_)
+
diff --git a/docs/license.rst b/docs/license.rst
new file mode 100644
index 00000000..cbcf5c11
--- /dev/null
+++ b/docs/license.rst
@@ -0,0 +1,5 @@
+.. _license:
+
+License (MIT)
+=============
+.. include:: ../LICENSE
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 00000000..d97407a6
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,170 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\SleekXMPP.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\SleekXMPP.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ if errorlevel 1 exit /b 1
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
new file mode 100644
index 00000000..5994052a
--- /dev/null
+++ b/docs/quickstart.rst
@@ -0,0 +1,300 @@
+====================
+SleekXMPP Quickstart
+====================
+
+.. note::
+
+ If you have any issues working through this quickstart guide
+ or the other tutorials here, please either send a message to the
+ `mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
+ or join the chat room at `sleek@conference.jabber.org
+ <xmpp:sleek@conference.jabber.org?join>`_.
+
+If you have not yet installed SleekXMPP, do so now by either checking out a version
+from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
+or ``easy_install``.
+
+.. code-block:: sh
+
+ pip install sleekxmpp # Or: easy_install sleekxmpp
+
+
+As a basic starting project, we will create an echo bot which will reply to any
+messages sent to it. We also go through adding some basic command line configuration
+for enabling or disabling debug log outputs and setting the username and password
+for the bot.
+
+For the command line options processing, we will use the built-in ``optparse``
+module and the ``getpass`` module for reading in passwords.
+
+TL;DR Just Give me the Boilerplate
+----------------------------------
+As you wish: :ref:`the completed example <echobot_complete>`.
+
+Overview
+--------
+
+To get started, here is a brief outline of the structure that the final project will have:
+
+.. code-block:: python
+
+ #!/usr/bin/env python
+ # -*- coding: utf-8 -*-
+
+ import sys
+ import logging
+ import getpass
+ from optparse import OptionParser
+
+ import sleekxmpp
+
+ '''Here we will create out echo bot class'''
+
+ if __name__ == '__main__':
+ '''Here we will configure and read command line options'''
+
+ '''Here we will instantiate our echo bot'''
+
+ '''Finally, we connect the bot and start listening for messages'''
+
+Creating the EchoBot Class
+--------------------------
+
+There are three main types of entities within XMPP — servers, components, and
+clients. Since our echo bot will only be responding to a few people, and won't need
+to remember thousands of users, we will use a client connection. A client connection
+is the same type that you use with your standard IM client such as Pidgin or Psi.
+
+SleekXMPP comes with a :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` class
+which we can extend to add our message echoing feature. :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>`
+requires the parameters ``jid`` and ``password``, so we will let our ``EchoBot`` class accept those
+as well.
+
+.. code-block:: python
+
+ class EchoBot(sleekxmpp.ClientXMPP):
+
+ def __init__(self, jid, password):
+ super(EchoBot, self).__init__(jid, password)
+
+Handling Session Start
+~~~~~~~~~~~~~~~~~~~~~~
+The XMPP spec requires clients to broadcast its presence and retrieve its roster (buddy list) once
+it connects and establishes a session with the XMPP server. Until these two tasks are completed,
+some servers may not deliver or send messages or presence notifications to the client. So we now
+need to be sure that we retrieve our roster and send an initial presence once the session has
+started. To do that, we will register an event handler for the :term:`session_start` event.
+
+.. code-block:: python
+
+ def __init__(self, jid, password):
+ super(EchoBot, self).__init__(jid, password)
+
+ self.add_event_handler('session_start', self.start)
+
+
+Since we want the method ``self.start`` to execute when the :term:`session_start` event is triggered,
+we also need to define the ``self.start`` handler.
+
+.. code-block:: python
+
+ def start(self, event):
+ self.send_presence()
+ self.get_roster()
+
+.. warning::
+
+ Not sending an initial presence and retrieving the roster when using a client instance can
+ prevent your program from receiving presence notifications or messages depending on the
+ XMPP server you have chosen.
+
+Our event handler, like every event handler, accepts a single parameter which typically is the stanza
+that was received that caused the event. In this case, ``event`` will just be an empty dictionary since
+there is no associated data.
+
+Our first task of sending an initial presence is done using :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>`.
+Calling :meth:`send_presence <sleekxmpp.basexmpp.BaseXMPP.send_presence>` without any arguments will send the simplest
+stanza allowed in XMPP:
+
+.. code-block:: xml
+
+ <presence />
+
+
+The second requirement is fulfilled using :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>`, which
+will send an IQ stanza requesting the roster to the server and then wait for the response. You may be wondering
+what :meth:`get_roster <sleekxmpp.clientxmpp.ClientXMPP.get_roster>` returns since we are not saving any return
+value. The roster data is saved by an internal handler to ``self.roster``, and in the case of a :class:`ClientXMPP
+<sleekxmpp.clientxmpp.ClientXMPP>` instance to ``self.client_roster``. (The difference between ``self.roster`` and
+``self.client_roster`` is that ``self.roster`` supports storing roster information for multiple JIDs, which is useful
+for components, whereas ``self.client_roster`` stores roster data for just the client's JID.)
+
+It is possible for a timeout to occur while waiting for the server to respond, which can happen if the
+network is excessively slow or the server is no longer responding. In that case, an :class:`IQTimeout
+<sleekxmpp.exceptions.IQTimeout>` is raised. Similarly, an :class:`IQError <sleekxmpp.exceptions.IQError>` exception can
+be raised if the request contained bad data or requested the roster for the wrong user. In either case, you can wrap the
+``get_roster()`` call in a ``try``/``except`` block to retry the roster retrieval process.
+
+The XMPP stanzas from the roster retrieval process could look like this:
+
+.. code-block:: xml
+
+ <iq type="get">
+ <query xmlns="jabber:iq:roster" />
+ </iq>
+
+ <iq type="result" to="echobot@example.com" from="example.com">
+ <query xmlns="jabber:iq:roster">
+ <item jid="friend@example.com" subscription="both" />
+ </query>
+ </iq>
+
+Responding to Messages
+~~~~~~~~~~~~~~~~~~~~~~
+Now that an ``EchoBot`` instance handles :term:`session_start`, we can begin receiving and responding
+to messages. The :term:`message` event is fired whenever a ``<message />`` stanza is received, including
+for group chat messages, errors, etc. Properly responding to messages thus requires checking the ``'type'``
+interface of the message :term:`stanza object`.
+
+
+.. _echobot_complete:
+
+The Final Product
+-----------------
+Here then is the final result you should have after working through the guide above.
+
+.. code-block:: python
+
+ #!/usr/bin/env python
+ # -*- coding: utf-8 -*-
+ import sys
+ import logging
+ import time
+ import getpass
+ from optparse import OptionParser
+
+ import sleekxmpp
+
+ # Python versions before 3.0 do not use UTF-8 encoding
+ # by default. To ensure that Unicode is handled properly
+ # throughout SleekXMPP, we will set the default encoding
+ # ourselves to UTF-8.
+ if sys.version_info < (3, 0):
+ reload(sys)
+ sys.setdefaultencoding('utf8')
+
+
+ class EchoBot(sleekxmpp.ClientXMPP):
+
+ """
+ A simple SleekXMPP bot that will echo messages it
+ receives, along with a short thank you message.
+ """
+
+ def __init__(self, jid, password):
+ sleekxmpp.ClientXMPP.__init__(self, jid, password)
+
+ # The session_start event will be triggered when
+ # the bot establishes its connection with the server
+ # and the XML streams are ready for use. We want to
+ # listen for this event so that we we can intialize
+ # our roster.
+ self.add_event_handler("session_start", self.start)
+
+ # The message event is triggered whenever a message
+ # stanza is received. Be aware that that includes
+ # MUC messages and error messages.
+ self.add_event_handler("message", self.message)
+
+ def start(self, event):
+ """
+ Process the session_start event.
+
+ Typical actions for the session_start event are
+ requesting the roster and broadcasting an intial
+ presence stanza.
+
+ Arguments:
+ event -- An empty dictionary. The session_start
+ event does not provide any additional
+ data.
+ """
+ self.send_presence()
+ self.get_roster()
+
+ def message(self, msg):
+ """
+ Process incoming message stanzas. Be aware that this also
+ includes MUC messages and error messages. It is usually
+ a good idea to check the messages's type before processing
+ or sending replies.
+
+ Arguments:
+ msg -- The received message stanza. See the documentation
+ for stanza objects and the Message stanza to see
+ how it may be used.
+ """
+ msg.reply("Thanks for sending\n%(body)s" % msg).send()
+
+
+ if __name__ == '__main__':
+ # Setup the command line arguments.
+ optp = OptionParser()
+
+ # Output verbosity options.
+ optp.add_option('-q', '--quiet', help='set logging to ERROR',
+ action='store_const', dest='loglevel',
+ const=logging.ERROR, default=logging.INFO)
+ optp.add_option('-d', '--debug', help='set logging to DEBUG',
+ action='store_const', dest='loglevel',
+ const=logging.DEBUG, default=logging.INFO)
+ optp.add_option('-v', '--verbose', help='set logging to COMM',
+ action='store_const', dest='loglevel',
+ const=5, default=logging.INFO)
+
+ # JID and password options.
+ optp.add_option("-j", "--jid", dest="jid",
+ help="JID to use")
+ optp.add_option("-p", "--password", dest="password",
+ help="password to use")
+
+ opts, args = optp.parse_args()
+
+ # Setup logging.
+ logging.basicConfig(level=opts.loglevel,
+ format='%(levelname)-8s %(message)s')
+
+ if opts.jid is None:
+ opts.jid = raw_input("Username: ")
+ if opts.password is None:
+ opts.password = getpass.getpass("Password: ")
+
+ # Setup the EchoBot and register plugins. Note that while plugins may
+ # have interdependencies, the order in which you register them does
+ # not matter.
+ xmpp = EchoBot(opts.jid, opts.password)
+ xmpp.register_plugin('xep_0030') # Service Discovery
+ xmpp.register_plugin('xep_0004') # Data Forms
+ xmpp.register_plugin('xep_0060') # PubSub
+ xmpp.register_plugin('xep_0199') # XMPP Ping
+
+ # If you are working with an OpenFire server, you may need
+ # to adjust the SSL version used:
+ # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
+
+ # If you want to verify the SSL certificates offered by a server:
+ # xmpp.ca_certs = "path/to/ca/cert"
+
+ # Connect to the XMPP server and start processing XMPP stanzas.
+ if xmpp.connect():
+ # If you do not have the pydns library installed, you will need
+ # to manually specify the name of the server if it does not match
+ # the one in the JID. For example, to use Google Talk you would
+ # need to use:
+ #
+ # if xmpp.connect(('talk.google.com', 5222)):
+ # ...
+ xmpp.process(threaded=False)
+ print("Done")
+ else:
+ print("Unable to connect.")
diff --git a/docs/xmpp_tdg.rst b/docs/xmpp_tdg.rst
new file mode 100644
index 00000000..3d12b1b6
--- /dev/null
+++ b/docs/xmpp_tdg.rst
@@ -0,0 +1,249 @@
+Following *XMPP: The Definitive Guide*
+======================================
+
+SleekXMPP was featured in the first edition of the O'Reilly book
+`XMPP: The Definitive Guide <http://oreilly.com/catalog/9780596521271/>`_
+by Peter Saint-Andre, Kevin Smith, and Remko Tronçon. The original source code
+for the book's examples can be found at http://github.com/remko/xmpp-tdg. An
+updated version of the source code, maintained to stay current with the latest
+SleekXMPP release, is available at http://github.com/legastero/xmpp-tdg.
+
+However, since publication, SleekXMPP has advanced from version 0.2.1 to version
+1.0 and there have been several major API changes. The most notable is the
+introduction of :term:`stanza objects <stanza object>` which have simplified and
+standardized interactions with the XMPP XML stream.
+
+What follows is a walk-through of *The Definitive Guide* highlighting the
+changes needed to make the code examples work with version 1.0 of SleekXMPP.
+These changes have been kept to a minimum to preserve the correlation with
+the book's explanations, so be aware that some code may not use current best
+practices.
+
+Example 2-2. (Page 26)
+----------------------
+
+**Implementation of a basic bot that echoes all incoming messages back to its sender.**
+
+The echo bot example requires a change to the ``handleIncomingMessage`` method
+to reflect the use of the ``Message`` :term:`stanza object`. The
+``"jid"`` field of the message object should now be ``"from"`` to match the
+``from`` attribute of the actual XML message stanza. Likewise, ``"message"``
+changes to ``"body"`` to match the ``body`` element of the message stanza.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingMessage(self, message):
+ self.xmpp.sendMessage(message["from"], message["body"])
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/EchoBot/EchoBot.py>`_
+
+Example 14-1. (Page 215)
+------------------------
+
+**CheshiR IM bot implementation.**
+
+The main event handling method in the Bot class is meant to process both message
+events and presence update events. With the new changes in SleekXMPP 1.0,
+extracting a CheshiR status "message" from both types of stanzas
+requires accessing different attributes. In the case of a message stanza, the
+``"body"`` attribute would contain the CheshiR message. For a presence event,
+the information is stored in the ``"status"`` attribute. To handle both cases,
+we can test the type of the given event object and look up the proper attribute
+based on the type.
+
+Like in the EchoBot example, the expression ``event["jid"]`` needs to change
+to ``event["from"]`` in order to get a JID object for the stanza's sender.
+Because other functions in CheshiR assume that the JID is a string, the ``jid``
+attribute is used to access the string version of the JID. A check is also added
+in case ``user`` is ``None``, but the check could (and probably should) be
+placed in ``addMessageFromUser``.
+
+Another change is needed in ``handleMessageAddedToBackend`` where
+an HTML-IM response is created. The HTML content should be enclosed in a single
+element, such as a ``<p>`` tag.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingXMPPEvent(self, event):
+ msgLocations = {sleekxmpp.stanza.presence.Presence: "status",
+ sleekxmpp.stanza.message.Message: "body"}
+
+ message = event[msgLocations[type(event)]]
+ user = self.backend.getUserFromJID(event["from"].jid)
+ if user is not None:
+ self.backend.addMessageFromUser(message, user)
+
+ def handleMessageAddedToBackend(self, message) :
+ body = message.user + ": " + message.text
+ htmlBody = "<p><a href='%(uri)s'>%(user)s</a>: %(message)s</p>" % {
+ "uri": self.url + "/" + message.user,
+ "user" : message.user, "message" : message.text }
+ for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
+ self.xmpp.sendMessage(subscriberJID, body, mhtml=htmlBody)
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Bot.py>`_
+
+
+Example 14-3. (Page 217)
+------------------------
+**Configurable CheshiR IM bot implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+The main difference for the configurable IM bot is the handling for the
+data form in ``handleConfigurationCommand``. The test for equality
+with the string ``"1"`` is no longer required; SleekXMPP converts
+boolean data form fields to the values ``True`` and ``False``
+automatically.
+
+For the method ``handleIncomingXMPPPresence``, the attribute
+``"jid"`` is again converted to ``"from"`` to get a JID
+object for the presence stanza's sender, and the ``jid`` attribute is
+used to access the string version of that JID object. A check is also added in
+case ``user`` is ``None``, but the check could (and probably
+should) be placed in ``getShouldMonitorPresenceFromUser``.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleConfigurationCommand(self, form, sessionId):
+ values = form.getValues()
+ monitorPresence =values["monitorPresence"]
+ jid = self.xmpp.plugin["xep_0050"].sessions[sessionId]["jid"]
+ user = self.backend.getUserFromJID(jid)
+ self.backend.setShouldMonitorPresenceFromUser(user, monitorPresence)
+
+ def handleIncomingXMPPPresence(self, event):
+ user = self.backend.getUserFromJID(event["from"].jid)
+ if user is not None:
+ if self.backend.getShouldMonitorPresenceFromUser(user):
+ self.handleIncomingXMPPEvent(event)
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/ConfigurableBot.py>`_
+
+
+Example 14-4. (Page 220)
+------------------------
+**CheshiR IM server component implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+Like several previous examples, a needed change is to replace
+``subscription["from"]`` with ``subscription["from"].jid`` because the
+``BaseXMPP`` method ``makePresence`` requires the JID to be a string.
+
+A correction needs to be made in ``handleXMPPPresenceProbe`` because a line was
+left out of the original implementation; the variable ``user`` is undefined. The
+JID of the user can be extracted from the presence stanza's ``from`` attribute.
+
+Since this implementation of CheshiR uses an XMPP component, it must
+include a ``from`` attribute in all messages that it sends. Adding the
+``from`` attribute is done by including ``mfrom=self.xmpp.jid`` in calls to
+``self.xmpp.sendMessage``.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleXMPPPresenceProbe(self, event) :
+ self.xmpp.sendPresence(pto = event["from"])
+
+ def handleXMPPPresenceSubscription(self, subscription) :
+ if subscription["type"] == "subscribe" :
+ userJID = subscription["from"].jid
+ self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribed")
+ self.xmpp.sendPresence(pto = userJID)
+ self.xmpp.sendPresenceSubscription(pto=userJID, ptype="subscribe")
+
+ def handleMessageAddedToBackend(self, message) :
+ body = message.user + ": " + message.text
+ for subscriberJID in self.backend.getSubscriberJIDs(message.user) :
+ self.xmpp.sendMessage(subscriberJID, body, mfrom=self.xmpp.jid)
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/SimpleComponent.py>`_
+
+
+Example 14-6. (Page 223)
+------------------------
+**CheshiR IM server component with in-band registration support.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous sections for
+ corrections to code that is not marked as new in the book example.
+
+After applying the changes from Example 14-4 above, the registrable component
+implementation should work correctly.
+
+.. tip::
+ To see how to implement in-band registration as a SleekXMPP plugin,
+ see the tutorial :ref:`tutorial-create-plugin`.
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/RegistrableComponent.py>`_
+
+Example 14-7. (Page 225)
+------------------------
+**Extended CheshiR IM server component implementation.**
+
+.. note::
+ Since the CheshiR examples build on each other, see previous
+ sections for corrections to code that is not marked as new in the book
+ example.
+
+While the final code example can look daunting with all of the changes
+made, it requires very few modifications to work with the latest version of
+SleekXMPP. Most differences are the result of CheshiR's backend functions
+expecting JIDs to be strings so that they can be stripped to bare JIDs. To
+resolve these, use the ``jid`` attribute of the JID objects. Also,
+references to ``"message"`` and ``"jid"`` attributes need to
+be changed to either ``"body"`` or ``"status"``, and either
+``"from"`` or ``"to"`` depending on if the object is a message
+or presence stanza and which of the JIDs from the stanza is needed.
+
+Updated Code
+~~~~~~~~~~~~
+
+.. code-block:: python
+
+ def handleIncomingXMPPMessage(self, event) :
+ message = self.addRecipientToMessage(event["body"], event["to"].jid)
+ user = self.backend.getUserFromJID(event["from"].jid)
+ self.backend.addMessageFromUser(message, user)
+
+ def handleIncomingXMPPPresence(self, event) :
+ if event["to"].jid == self.componentDomain :
+ user = self.backend.getUserFromJID(event["from"].jid)
+ self.backend.addMessageFromUser(event["status"], user)
+
+ ...
+
+ def handleXMPPPresenceSubscription(self, subscription) :
+ if subscription["type"] == "subscribe" :
+ userJID = subscription["from"].jid
+ user = self.backend.getUserFromJID(userJID)
+ contactJID = subscription["to"]
+ self.xmpp.sendPresenceSubscription(
+ pfrom=contactJID, pto=userJID, ptype="subscribed", pnick=user)
+ self.sendPresenceOfContactToUser(contactJID=contactJID, userJID=userJID)
+ if contactJID == self.componentDomain :
+ self.sendAllContactSubscriptionRequestsToUser(userJID)
+
+`View full source <http://github.com/legastero/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_ |
+`View original code <http://github.com/remko/xmpp-tdg/blob/master/code/CheshiR/Component.py>`_