introduction.html 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4. <head>
  5. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6. <title>celery - Distributed Task Queue for Django. &mdash; Celery v0.3.2 (unstable) documentation</title>
  7. <link rel="stylesheet" href="static/agogo.css" type="text/css" />
  8. <link rel="stylesheet" href="static/pygments.css" type="text/css" />
  9. <script type="text/javascript">
  10. var DOCUMENTATION_OPTIONS = {
  11. URL_ROOT: '',
  12. VERSION: '0.3.2 (unstable)',
  13. COLLAPSE_MODINDEX: false,
  14. FILE_SUFFIX: '.html',
  15. HAS_SOURCE: true
  16. };
  17. </script>
  18. <script type="text/javascript" src="static/jquery.js"></script>
  19. <script type="text/javascript" src="static/doctools.js"></script>
  20. <link rel="top" title="Celery v0.3.2 (unstable) documentation" href="index.html" />
  21. <link rel="next" title="Frequently Asked Questions" href="faq.html" />
  22. <link rel="prev" title="Welcome to Celery’s documentation!" href="index.html" />
  23. </head>
  24. <body>
  25. <div class="header-wrapper">
  26. <div class="header">
  27. <h1><a href="index.html">Celery v0.3.2 (unstable) documentation</a></h1>
  28. <div class="rel">
  29. <a href="genindex.html" title="General Index"
  30. accesskey="I">index</a> |
  31. <a href="modindex.html" title="Global Module Index"
  32. accesskey="M">modules</a> |
  33. <a href="faq.html" title="Frequently Asked Questions"
  34. accesskey="N">next</a> |
  35. <a href="index.html" title="Welcome to Celery’s documentation!"
  36. accesskey="P">previous</a>
  37. </div>
  38. </div>
  39. </div>
  40. <div class="content-wrapper">
  41. <div class="content">
  42. <div class="document">
  43. <div class="documentwrapper">
  44. <div class="bodywrapper">
  45. <div class="body">
  46. <div class="section" id="celery-distributed-task-queue-for-django">
  47. <h1>celery - Distributed Task Queue for Django.<a class="headerlink" href="#celery-distributed-task-queue-for-django" title="Permalink to this headline">¶</a></h1>
  48. <table class="docutils field-list" frame="void" rules="none">
  49. <col class="field-name" />
  50. <col class="field-body" />
  51. <tbody valign="top">
  52. <tr class="field"><th class="field-name">Version:</th><td class="field-body">0.3.2</td>
  53. </tr>
  54. </tbody>
  55. </table>
  56. <div class="section" id="introduction">
  57. <h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
  58. <p><tt class="docutils literal"><span class="pre">celery</span></tt> is a distributed task queue framework for Django.</p>
  59. <p>It is used for executing tasks <em>asynchronously</em>, routed to one or more
  60. worker servers, running concurrently using multiprocessing.</p>
  61. <p>It is designed to solve certain problems related to running websites
  62. demanding high-availability and performance.</p>
  63. <p>It is perfect for filling caches, posting updates to twitter, mass
  64. downloading data like syndication feeds or web scraping. Use-cases are
  65. plentiful. Implementing these features asynchronously using <tt class="docutils literal"><span class="pre">celery</span></tt> is
  66. easy and fun, and the performance improvements can make it more than
  67. worthwhile.</p>
  68. </div>
  69. <div class="section" id="features">
  70. <h2>Features<a class="headerlink" href="#features" title="Permalink to this headline">¶</a></h2>
  71. <ul class="simple">
  72. <li>Uses AMQP messaging (RabbitMQ, ZeroMQ) to route tasks to the
  73. worker servers.</li>
  74. <li>You can run as many worker servers as you want, and still
  75. be <em>guaranteed that the task is only executed once.</em></li>
  76. <li>Tasks are executed <em>concurrently</em> using the Python 2.6
  77. <tt class="docutils literal"><span class="pre">multiprocessing</span></tt> module (also available as a back-port
  78. to older python versions)</li>
  79. <li>Supports <em>periodic tasks</em>, which makes it a (better) replacement
  80. for cronjobs.</li>
  81. <li>When a task has been executed, the return value is stored using either
  82. a MySQL/Oracle/PostgreSQL/SQLite database, memcached,
  83. or Tokyo Tyrant back-end.</li>
  84. <li>If the task raises an exception, the exception instance is stored,
  85. instead of the return value.</li>
  86. <li>All tasks has a Universally Unique Identifier (UUID), which is the
  87. task id, used for querying task status and return values.</li>
  88. <li>Supports <em>task-sets</em>, which is a task consisting of several sub-tasks.
  89. You can find out how many, or if all of the sub-tasks has been executed.
  90. Excellent for progress-bar like functionality.</li>
  91. <li>Has a <tt class="docutils literal"><span class="pre">map</span></tt> like function that uses tasks, called <tt class="docutils literal"><span class="pre">dmap</span></tt>.</li>
  92. <li>However, you rarely want to wait for these results in a web-environment.
  93. You&#8217;d rather want to use Ajax to poll the task status, which is
  94. available from a URL like <tt class="docutils literal"><span class="pre">celery/&lt;task_id&gt;/status/</span></tt>. This view
  95. returns a JSON-serialized data structure containing the task status,
  96. and the return value if completed, or exception on failure.</li>
  97. </ul>
  98. </div>
  99. <div class="section" id="api-reference-documentation">
  100. <h2>API Reference Documentation<a class="headerlink" href="#api-reference-documentation" title="Permalink to this headline">¶</a></h2>
  101. <p>The <a class="reference external" href="http://ask.github.com/celery/">API Reference</a> is hosted at Github
  102. (<a class="reference external" href="http://ask.github.com/celery">http://ask.github.com/celery</a>)</p>
  103. </div>
  104. <div class="section" id="installation">
  105. <h2>Installation<a class="headerlink" href="#installation" title="Permalink to this headline">¶</a></h2>
  106. <p>You can install <tt class="docutils literal"><span class="pre">celery</span></tt> either via the Python Package Index (PyPI)
  107. or from source.</p>
  108. <p>To install using <tt class="docutils literal"><span class="pre">pip</span></tt>,:</p>
  109. <div class="highlight-python"><pre>$ pip install celery</pre>
  110. </div>
  111. <p>To install using <tt class="docutils literal"><span class="pre">easy_install</span></tt>,:</p>
  112. <div class="highlight-python"><pre>$ easy_install celery</pre>
  113. </div>
  114. <p>If you have downloaded a source tarball you can install it
  115. by doing the following,:</p>
  116. <div class="highlight-python"><pre>$ python setup.py build
  117. # python setup.py install # as root</pre>
  118. </div>
  119. </div>
  120. <div class="section" id="usage">
  121. <h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline">¶</a></h2>
  122. <div class="section" id="installing-rabbitmq">
  123. <h3>Installing RabbitMQ<a class="headerlink" href="#installing-rabbitmq" title="Permalink to this headline">¶</a></h3>
  124. <p>See <a class="reference external" href="http://www.rabbitmq.com/install.html">Installing RabbitMQ</a> over at RabbitMQ&#8217;s website. For Mac OS X
  125. see <a class="reference external" href="http://playtype.net/past/2008/10/9/installing_rabbitmq_on_osx/">Installing RabbitMQ on OS X</a>.</p>
  126. </div>
  127. <div class="section" id="setting-up-rabbitmq">
  128. <h3>Setting up RabbitMQ<a class="headerlink" href="#setting-up-rabbitmq" title="Permalink to this headline">¶</a></h3>
  129. <p>To use celery we need to create a RabbitMQ user, a virtual host and
  130. allow that user access to that virtual host:</p>
  131. <div class="highlight-python"><pre>$ rabbitmqctl add_user myuser mypassword
  132. $ rabbitmqctl add_vhost myvhost
  133. $ rabbitmqctl map_user_vhost myuser myvhost</pre>
  134. </div>
  135. </div>
  136. <div class="section" id="configuring-your-django-project-to-use-celery">
  137. <h3>Configuring your Django project to use Celery<a class="headerlink" href="#configuring-your-django-project-to-use-celery" title="Permalink to this headline">¶</a></h3>
  138. <p>You only need three simple steps to use celery with your Django project.</p>
  139. <ol class="arabic">
  140. <li><p class="first">Add <tt class="docutils literal"><span class="pre">celery</span></tt> to <tt class="docutils literal"><span class="pre">INSTALLED_APPS</span></tt>.</p>
  141. </li>
  142. <li><p class="first">Create the celery database tables:</p>
  143. <div class="highlight-python"><pre>$ python manage.py syncdb</pre>
  144. </div>
  145. </li>
  146. <li><dl class="first docutils">
  147. <dt>Configure celery to use the AMQP user and virtual host we created</dt>
  148. <dd><p class="first">before, by adding the following to your <tt class="docutils literal"><span class="pre">settings.py</span></tt>:</p>
  149. <div class="last highlight-python"><div class="highlight"><pre><span class="n">AMQP_HOST</span> <span class="o">=</span> <span class="s">&quot;localhost&quot;</span>
  150. <span class="n">AMQP_PORT</span> <span class="o">=</span> <span class="mf">5672</span>
  151. <span class="n">AMQP_USER</span> <span class="o">=</span> <span class="s">&quot;myuser&quot;</span>
  152. <span class="n">AMQP_PASSWORD</span> <span class="o">=</span> <span class="s">&quot;mypassword&quot;</span>
  153. <span class="n">AMQP_VHOST</span> <span class="o">=</span> <span class="s">&quot;myvhost&quot;</span>
  154. </pre></div>
  155. </div>
  156. </dd>
  157. </dl>
  158. </li>
  159. </ol>
  160. <p>That&#8217;s it.</p>
  161. <p>There are more options available, like how many processes you want to process
  162. work in parallel (the <tt class="docutils literal"><span class="pre">CELERY_CONCURRENCY</span></tt> setting), and the backend used
  163. for storing task statuses. But for now, this should do. For all of the options
  164. available, please consult the <a class="reference external" href="http://ask.github.com/celery/">API Reference</a></p>
  165. <p><strong>Note</strong>: If you&#8217;re using SQLite as the Django database back-end,
  166. <tt class="docutils literal"><span class="pre">celeryd</span></tt> will only be able to process one task at a time, this is
  167. because SQLite doesn&#8217;t allow concurrent writes.</p>
  168. </div>
  169. <div class="section" id="running-the-celery-worker-daemon">
  170. <h3>Running the celery worker daemon<a class="headerlink" href="#running-the-celery-worker-daemon" title="Permalink to this headline">¶</a></h3>
  171. <p>To test this we&#8217;ll be running the worker daemon in the foreground, so we can
  172. see what&#8217;s going on without consulting the logfile:</p>
  173. <div class="highlight-python"><pre>$ python manage.py celeryd</pre>
  174. </div>
  175. <p>However, in production you&#8217;ll probably want to run the worker in the
  176. background as a daemon instead:</p>
  177. <div class="highlight-python"><pre>$ python manage.py celeryd --daemon</pre>
  178. </div>
  179. <p>For help on command line arguments to the worker daemon, you can execute the
  180. help command:</p>
  181. <div class="highlight-python"><pre>$ python manage.py help celeryd</pre>
  182. </div>
  183. </div>
  184. <div class="section" id="defining-and-executing-tasks">
  185. <h3>Defining and executing tasks<a class="headerlink" href="#defining-and-executing-tasks" title="Permalink to this headline">¶</a></h3>
  186. <p><strong>Please note</strong> All of these tasks has to be stored in a real module, they can&#8217;t
  187. be defined in the python shell or ipython/bpython. This is because the celery
  188. worker server needs access to the task function to be able to run it.
  189. So while it looks like we use the python shell to define the tasks in these
  190. examples, you can&#8217;t do it this way. Put them in the <tt class="docutils literal"><span class="pre">tasks</span></tt> module of your
  191. Django application. The worker daemon will automatically load any <tt class="docutils literal"><span class="pre">tasks.py</span></tt>
  192. file for all of the applications listed in <tt class="docutils literal"><span class="pre">settings.INSTALLED_APPS</span></tt>.
  193. Executing tasks using <tt class="docutils literal"><span class="pre">delay</span></tt> and <tt class="docutils literal"><span class="pre">apply_async</span></tt> can be done from the
  194. python shell, but keep in mind that since arguments are pickled, you can&#8217;t
  195. use custom classes defined in the shell session.</p>
  196. <p>While you can use regular functions, the recommended way is to define
  197. a task class. With this way you can cleanly upgrade the task to use the more
  198. advanced features of celery later.</p>
  199. <p>This is a task that basically does nothing but take some arguments,
  200. and return a value:</p>
  201. <div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyTask</span><span class="p">(</span><span class="n">Task</span><span class="p">):</span>
  202. <span class="gp">... </span> <span class="n">name</span> <span class="o">=</span> <span class="s">&quot;myapp.mytask&quot;</span>
  203. <span class="gp">... </span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">some_arg</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
  204. <span class="gp">... </span> <span class="n">logger</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_logger</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  205. <span class="gp">... </span> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;Did something: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">some_arg</span><span class="p">)</span>
  206. <span class="gp">... </span> <span class="k">return</span> <span class="mf">42</span>
  207. <span class="gp">&gt;&gt;&gt; </span><span class="n">tasks</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">MyTask</span><span class="p">)</span>
  208. </pre></div>
  209. </div>
  210. <p>Now if we want to execute this task, we can use the <tt class="docutils literal"><span class="pre">delay</span></tt> method of the
  211. task class (this is a handy shortcut to the <tt class="docutils literal"><span class="pre">apply_async</span></tt> method which gives
  212. you greater control of the task execution).</p>
  213. <div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">myapp.tasks</span> <span class="kn">import</span> <span class="n">MyTask</span>
  214. <span class="gp">&gt;&gt;&gt; </span><span class="n">MyTask</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="n">some_arg</span><span class="o">=</span><span class="s">&quot;foo&quot;</span><span class="p">)</span>
  215. </pre></div>
  216. </div>
  217. <p>At this point, the task has been sent to the message broker. The message
  218. broker will hold on to the task until a celery worker server has successfully
  219. picked it up.</p>
  220. <p>Right now we have to check the celery worker logfiles to know what happened with
  221. the task. This is because we didn&#8217;t keep the <tt class="docutils literal"><span class="pre">AsyncResult</span></tt> object returned
  222. by <tt class="docutils literal"><span class="pre">delay</span></tt>.</p>
  223. <p>The <tt class="docutils literal"><span class="pre">AsyncResult</span></tt> lets us find the state of the task, wait for the task to
  224. finish and get its return value (or exception if the task failed).</p>
  225. <p>So, let&#8217;s execute the task again, but this time we&#8217;ll keep track of the task:</p>
  226. <div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">result</span> <span class="o">=</span> <span class="n">MyTask</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="s">&quot;do_something&quot;</span><span class="p">,</span> <span class="n">some_arg</span><span class="o">=</span><span class="s">&quot;foo bar baz&quot;</span><span class="p">)</span>
  227. <span class="gp">&gt;&gt;&gt; </span><span class="n">result</span><span class="o">.</span><span class="n">ready</span><span class="p">()</span> <span class="c"># returns True if the task has finished processing.</span>
  228. <span class="go">False</span>
  229. <span class="gp">&gt;&gt;&gt; </span><span class="n">result</span><span class="o">.</span><span class="n">result</span> <span class="c"># task is not ready, so no return value yet.</span>
  230. <span class="go">None</span>
  231. <span class="gp">&gt;&gt;&gt; </span><span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">()</span> <span class="c"># Waits until the task is done and return the retval.</span>
  232. <span class="go">42</span>
  233. <span class="gp">&gt;&gt;&gt; </span><span class="n">result</span><span class="o">.</span><span class="n">result</span>
  234. <span class="go">42</span>
  235. <span class="gp">&gt;&gt;&gt; </span><span class="n">result</span><span class="o">.</span><span class="n">success</span><span class="p">()</span> <span class="c"># returns True if the task didn&#39;t end in failure.</span>
  236. <span class="go">True</span>
  237. </pre></div>
  238. </div>
  239. <p>If the task raises an exception, the <tt class="docutils literal"><span class="pre">result.success()</span></tt> will be <tt class="xref docutils literal"><span class="pre">False</span></tt>,
  240. and <tt class="docutils literal"><span class="pre">result.result</span></tt> will contain the exception instance raised.</p>
  241. </div>
  242. <div class="section" id="auto-discovery-of-tasks">
  243. <h3>Auto-discovery of tasks<a class="headerlink" href="#auto-discovery-of-tasks" title="Permalink to this headline">¶</a></h3>
  244. <p><tt class="docutils literal"><span class="pre">celery</span></tt> has an auto-discovery feature like the Django Admin, that
  245. automatically loads any <tt class="docutils literal"><span class="pre">tasks.py</span></tt> module in the applications listed
  246. in <tt class="docutils literal"><span class="pre">settings.INSTALLED_APPS</span></tt>. This autodiscovery is used by the celery
  247. worker to find registered tasks for your Django project.</p>
  248. </div>
  249. <div class="section" id="periodic-tasks">
  250. <h3>Periodic Tasks<a class="headerlink" href="#periodic-tasks" title="Permalink to this headline">¶</a></h3>
  251. <p>Periodic tasks are tasks that are run every <tt class="docutils literal"><span class="pre">n</span></tt> seconds.
  252. Here&#8217;s an example of a periodic task:</p>
  253. <div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">celery.task</span> <span class="kn">import</span> <span class="n">tasks</span><span class="p">,</span> <span class="n">PeriodicTask</span>
  254. <span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">timedelta</span>
  255. <span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyPeriodicTask</span><span class="p">(</span><span class="n">PeriodicTask</span><span class="p">):</span>
  256. <span class="gp">... </span> <span class="n">name</span> <span class="o">=</span> <span class="s">&quot;foo.my-periodic-task&quot;</span>
  257. <span class="gp">... </span> <span class="n">run_every</span> <span class="o">=</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">seconds</span><span class="o">=</span><span class="mf">30</span><span class="p">)</span>
  258. <span class="gp">...</span>
  259. <span class="gp">... </span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
  260. <span class="gp">... </span> <span class="n">logger</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_logger</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
  261. <span class="gp">... </span> <span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s">&quot;Running periodic task!&quot;</span><span class="p">)</span>
  262. <span class="gp">...</span>
  263. <span class="gp">&gt;&gt;&gt; </span><span class="n">tasks</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">MyPeriodicTask</span><span class="p">)</span>
  264. </pre></div>
  265. </div>
  266. <p><strong>Note:</strong> Periodic tasks does not support arguments, as this doesn&#8217;t
  267. really make sense.</p>
  268. </div>
  269. </div>
  270. <div class="section" id="license">
  271. <h2>License<a class="headerlink" href="#license" title="Permalink to this headline">¶</a></h2>
  272. <p>This software is licensed under the <tt class="docutils literal"><span class="pre">New</span> <span class="pre">BSD</span> <span class="pre">License</span></tt>. See the <tt class="docutils literal"><span class="pre">LICENSE</span></tt>
  273. file in the top distribution directory for the full license text.</p>
  274. </div>
  275. </div>
  276. </div>
  277. </div>
  278. </div>
  279. </div>
  280. <div class="sidebar">
  281. <h3>Contents</h3>
  282. <ul class="current">
  283. <li class="toctree-l1 current"><a class="current reference external" href="">celery - Distributed Task Queue for Django.</a><ul>
  284. <li class="toctree-l2"><a class="reference external" href="#introduction">Introduction</a></li>
  285. <li class="toctree-l2"><a class="reference external" href="#features">Features</a></li>
  286. <li class="toctree-l2"><a class="reference external" href="#api-reference-documentation">API Reference Documentation</a></li>
  287. <li class="toctree-l2"><a class="reference external" href="#installation">Installation</a></li>
  288. <li class="toctree-l2"><a class="reference external" href="#usage">Usage</a></li>
  289. <li class="toctree-l2"><a class="reference external" href="#license">License</a></li>
  290. </ul>
  291. </li>
  292. <li class="toctree-l1"><a class="reference external" href="faq.html">Frequently Asked Questions</a></li>
  293. <li class="toctree-l1"><a class="reference external" href="reference/index.html">Module API Reference</a></li>
  294. <li class="toctree-l1"><a class="reference external" href="changelog.html">Change history</a></li>
  295. </ul>
  296. <h3 style="margin-top: 1.5em;">Search</h3>
  297. <form class="search" action="search.html" method="get">
  298. <input type="text" name="q" size="18" />
  299. <input type="submit" value="Go" />
  300. <input type="hidden" name="check_keywords" value="yes" />
  301. <input type="hidden" name="area" value="default" />
  302. </form>
  303. <p class="searchtip" style="font-size: 90%">
  304. Enter search terms or a module, class or function name.
  305. </p>
  306. </div>
  307. <div class="clearer"></div>
  308. </div>
  309. </div>
  310. <div class="footer-wrapper">
  311. <div class="footer">
  312. <div class="left">
  313. <a href="genindex.html" title="General Index"
  314. >index</a> |
  315. <a href="modindex.html" title="Global Module Index"
  316. >modules</a> |
  317. <a href="faq.html" title="Frequently Asked Questions"
  318. >next</a> |
  319. <a href="index.html" title="Welcome to Celery’s documentation!"
  320. >previous</a>
  321. <br/>
  322. <a href="sources/introduction.txt"
  323. rel="nofollow">Show Source</a>
  324. </div>
  325. <div class="right">
  326. &copy; Copyright 2009, Ask Solem.<br/>
  327. Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 0.6.1.
  328. </div>
  329. <div class="clearer"></div>
  330. </div>
  331. </div>
  332. </body>
  333. </html>