Start of docs for 1.0
This commit is contained in:
		
							
								
								
									
										130
									
								
								docs/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								docs/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -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."
 | 
				
			||||||
							
								
								
									
										452
									
								
								docs/_static/agogo.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										452
									
								
								docs/_static/agogo.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										532
									
								
								docs/_static/basic.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								docs/_static/basic.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										256
									
								
								docs/_static/default.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								docs/_static/default.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/Museo_Slab_500.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/Museo_Slab_500.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/Museo_Slab_500italic.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/Museo_Slab_500italic.otf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/OFLGoudyStMTT-Italic.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/OFLGoudyStMTT-Italic.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/OFLGoudyStMTT.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/OFLGoudyStMTT.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Bold.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Bold.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Light.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Light.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Regular.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Regular.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Thin.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/fonts/YanoneKaffeesatz-Thin.ttf
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										406
									
								
								docs/_static/haiku.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										406
									
								
								docs/_static/haiku.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docs/_static/header.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/header.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								docs/_static/images/arch_layers.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/images/arch_layers.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										70
									
								
								docs/_static/ir_black.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								docs/_static/ir_black.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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 */
 | 
				
			||||||
							
								
								
									
										245
									
								
								docs/_static/nature.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								docs/_static/nature.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								docs/_static/noise_dk.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								docs/_static/noise_dk.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 22 KiB  | 
							
								
								
									
										70
									
								
								docs/_static/pygments.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								docs/_static/pygments.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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 */
 | 
				
			||||||
							
								
								
									
										339
									
								
								docs/_static/sphinxdoc.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								docs/_static/sphinxdoc.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								docs/_templates/defindex.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								docs/_templates/defindex.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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 %}
 | 
				
			||||||
							
								
								
									
										61
									
								
								docs/_templates/indexcontent.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								docs/_templates/indexcontent.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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 & 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 %}
 | 
				
			||||||
							
								
								
									
										69
									
								
								docs/_templates/layout.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								docs/_templates/layout.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -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 %}
 | 
				
			||||||
 | 
					        «  <a href="{{ prev.link|e }}">{{ prev.title }}</a>
 | 
				
			||||||
 | 
					          ::  
 | 
				
			||||||
 | 
					        {%- endif %}
 | 
				
			||||||
 | 
					        <a class="uplink" href="{{ pathto(master_doc) }}">{{ _('Contents') }}</a>
 | 
				
			||||||
 | 
					        {%- if next %}
 | 
				
			||||||
 | 
					          ::  
 | 
				
			||||||
 | 
					        <a href="{{ next.link|e }}">{{ next.title }}</a>  »
 | 
				
			||||||
 | 
					        {%- 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 %}
 | 
				
			||||||
							
								
								
									
										19
									
								
								docs/api/clientxmpp.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								docs/api/clientxmpp.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
							
								
								
									
										269
									
								
								docs/architecture.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								docs/architecture.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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.
 | 
				
			||||||
							
								
								
									
										220
									
								
								docs/conf.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								docs/conf.py
									
									
									
									
									
										Normal file
									
								
							@@ -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)
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										677
									
								
								docs/create_plugin.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										677
									
								
								docs/create_plugin.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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()
 | 
				
			||||||
							
								
								
									
										271
									
								
								docs/event_index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								docs/event_index.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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`
 | 
				
			||||||
							
								
								
									
										35
									
								
								docs/glossary.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								docs/glossary.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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`
 | 
				
			||||||
							
								
								
									
										201
									
								
								docs/guide_xep_0030.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								docs/guide_xep_0030.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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)
 | 
				
			||||||
							
								
								
									
										130
									
								
								docs/index.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								docs/index.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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>`_)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								docs/license.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								docs/license.rst
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					.. _license: 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					License (MIT)
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					.. include:: ../LICENSE
 | 
				
			||||||
							
								
								
									
										170
									
								
								docs/make.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								docs/make.bat
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
				
			||||||
							
								
								
									
										300
									
								
								docs/quickstart.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										300
									
								
								docs/quickstart.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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.")
 | 
				
			||||||
							
								
								
									
										249
									
								
								docs/xmpp_tdg.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								docs/xmpp_tdg.rst
									
									
									
									
									
										Normal file
									
								
							@@ -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>`_ 
 | 
				
			||||||
		Reference in New Issue
	
	Block a user