Skip to content

Instantly share code, notes, and snippets.

@wallrj
Created September 22, 2013 15:00
Show Gist options
  • Select an option

  • Save wallrj/6660768 to your computer and use it in GitHub Desktop.

Select an option

Save wallrj/6660768 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Twisted Names</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="generator" content="Org-mode" />
<style type="text/css">
<!--/*--><![CDATA[/*><!--*/
.title { text-align: center; }
.todo { font-family: monospace; color: red; }
.done { color: green; }
.tag { background-color: #eee; font-family: monospace;
padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.right { margin-left: auto; margin-right: 0px; text-align: right; }
.left { margin-left: 0px; margin-right: auto; text-align: left; }
.center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
border: 1px solid #ccc;
box-shadow: 3px 3px 3px #eee;
padding: 8pt;
font-family: monospace;
overflow: auto;
margin: 1.2em;
}
pre.src {
position: relative;
overflow: visible;
padding-top: 1.2em;
}
pre.src:before {
display: none;
position: absolute;
background-color: white;
top: -10px;
right: 10px;
padding: 3px;
border: 1px solid black;
}
pre.src:hover:before { display: inline;}
pre.src-sh:before { content: 'sh'; }
pre.src-bash:before { content: 'sh'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-R:before { content: 'R'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-java:before { content: 'Java'; }
pre.src-sql:before { content: 'SQL'; }
table { border-collapse:collapse; }
td, th { vertical-align:top; }
th.right { text-align: center; }
th.left { text-align: center; }
th.center { text-align: center; }
td.right { text-align: right; }
td.left { text-align: left; }
td.center { text-align: center; }
dt { font-weight: bold; }
.footpara:nth-child(2) { display: inline; }
.footpara { display: block; }
.footdef { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.inlinetask {
padding: 10px;
border: 2px solid gray;
margin: 10px;
background: #ffffcc;
}
#org-div-home-and-up
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
{ background-color: #ffff00; color: #000000; font-weight: bold; }
/*]]>*/-->
</style>
<script type="text/javascript">
/*
@licstart The following is the entire license notice for the
JavaScript code in this tag.
Copyright (C) 2012 Free Software Foundation, Inc.
The JavaScript code in this tag is free software: you can
redistribute it and/or modify it under the terms of the GNU
General Public License (GNU GPL) as published by the Free Software
Foundation, either version 3 of the License, or (at your option)
any later version. The code is distributed WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
As additional permission under GNU GPL version 3 section 7, you
may distribute non-source (e.g., minimized or compacted) forms of
that code without the copy of the GNU GPL normally required by
section 4, provided you include this license notice and a URL
through which recipients can access the Corresponding Source.
@licend The above is the entire license notice
for the JavaScript code in this tag.
*/
<!--/*--><![CDATA[/*><!--*/
function CodeHighlightOn(elem, id)
{
var target = document.getElementById(id);
if(null != target) {
elem.cacheClassElem = elem.className;
elem.cacheClassTarget = target.className;
target.className = "code-highlighted";
elem.className = "code-highlighted";
}
}
function CodeHighlightOff(elem, id)
{
var target = document.getElementById(id);
if(elem.cacheClassElem)
elem.className = elem.cacheClassElem;
if(elem.cacheClassTarget)
target.className = elem.cacheClassTarget;
}
/*]]>*///-->
</script>
</head>
<body>
<div id="content">
<h1 class="title">Twisted Names</h1>
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1">Twisted Names Modules</h2>
<div class="outline-text-2" id="text-1">
</div><div id="outline-container-sec-1-1" class="outline-3">
<h3 id="sec-1-1">twisted.names.dns</h3>
<div class="outline-text-3" id="text-1-1">
</div><div id="outline-container-sec-1-1-1" class="outline-4">
<h4 id="sec-1-1-1">dns.DNSDatagramProtocol (Client)</h4>
<div class="outline-text-4" id="text-1-1-1">
<div class="org-src-container">
<pre class="src src-python"><code>from twisted.internet import task
from twisted.names import dns
def main(reactor):
proto = dns.DNSDatagramProtocol(controller=None)
reactor.listenUDP(0, proto)
d = proto.query(('8.8.8.8', 53), [dns.Query('www.example.com', dns.AAAA)])
d.addCallback(printResult)
return d
def printResult(res):
print 'ANSWERS: ', [a.payload for a in res.answers]
task.react(main)
</code></pre>
</div>
<p>
example1.py
</p>
</div>
<ul class="org-ul"><li>Output<br /><div class="outline-text-5" id="text-1-1-1-1">
<div class="org-src-container">
<pre class="src src-sh"><code>$ python example1.py
ANSWERS: [&lt;AAAA address=2606:2800:220:6d:26bf:1447:1097:aa7 ttl=10091&gt;]
</code></pre>
</div>
</div>
</li></ul>
</div>
<div id="outline-container-sec-1-1-2" class="outline-4">
<h4 id="sec-1-1-2">dns.DNSDatagramProtocol (Server)</h4>
<div class="outline-text-4" id="text-1-1-2">
<div class="org-src-container">
<pre class="src src-python"><code>from twisted.internet import defer, task
from twisted.names import dns
def main(reactor):
proto = dns.DNSDatagramProtocol(controller=Controller())
reactor.listenUDP(10053, proto)
return defer.Deferred()
class Controller(object):
def messageReceived(self, message, proto, address):
print "MESSAGE_RECEIVED", message.queries, "FROM", address
message.answers = [
dns.RRHeader(message.queries[0].name.name,
payload=dns.Record_A('192.0.2.1'))
]
proto.writeMessage(message, address)
task.react(main)
</code></pre>
</div>
<p>
example2.py
</p>
</div>
<ul class="org-ul"><li>Output<br /><div class="outline-text-5" id="text-1-1-2-1">
<div class="org-src-container">
<pre class="src src-sh"><code>$ dig -p 10053 @localhost foo.bar A +short
;; Warning: query response not set
192.0.2.1
</code></pre>
</div>
<div class="org-src-container">
<pre class="src src-sh"><code>$ python example2.py
MESSAGE_RECEIVED [Query('foo.bar', 1, 1)] FROM ('127.0.0.1', 51515)
</code></pre>
</div>
</div>
</li></ul>
</div>
</div>
<div id="outline-container-sec-1-2" class="outline-3">
<h3 id="sec-1-2">twisted.names.client</h3>
<div class="outline-text-3" id="text-1-2">
</div><div id="outline-container-sec-1-2-1" class="outline-4">
<h4 id="sec-1-2-1">client.lookupPointer</h4>
<div class="outline-text-4" id="text-1-2-1">
<div class="org-src-container">
<pre class="src src-python"><code>from netaddr import IPNetwork
from twisted.internet import defer, task
from twisted.names import client
def main(reactor):
pending = []
for addr in IPNetwork('79.170.40.0/24'):
d = client.lookupPointer(addr.reverse_dns, timeout=(1,))
pending.append(d)
return defer.DeferredList(pending, consumeErrors=True).addCallback(printResult)
def printResult(results):
good = 0
for success, result in results:
if success:
answers, authority, additional = result
print 'RESULT: ', [(a.name.name, a.payload) for a in answers]
good += 1
print good, 'responses to', len(results), 'queries'
task.react(main)
</code></pre>
</div>
<p>
example3.py
</p>
</div>
</div>
<div id="outline-container-sec-1-2-2" class="outline-4">
<h4 id="sec-1-2-2">Output</h4>
<div class="outline-text-4" id="text-1-2-2">
<div class="org-src-container">
<pre class="src src-sh"><code>$ time python example3.py
RESULT: [('2.40.170.79.in-addr.arpa', &lt;PTR name=ns1.mainnameserver.com ttl=10441&gt;)]
RESULT: [('3.40.170.79.in-addr.arpa', &lt;PTR name=ns2.mainnameserver.com ttl=10515&gt;)]
...
RESULT: [('92.40.170.79.in-addr.arpa', &lt;PTR name=mail92.extendcp.co.uk ttl=10515&gt;)]
RESULT: [('94.40.170.79.in-addr.arpa', &lt;PTR name=mail94.extendcp.co.uk ttl=10440&gt;)]
73 responses to 256 queries
real 0m1.490s
user 0m0.655s
sys 0m0.112s
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-sec-1-3" class="outline-3">
<h3 id="sec-1-3">twisted.names.server</h3>
<div class="outline-text-3" id="text-1-3">
</div><div id="outline-container-sec-1-3-1" class="outline-4">
<h4 id="sec-1-3-1">twistd dns</h4>
<div class="outline-text-4" id="text-1-3-1">
<div class="org-src-container">
<pre class="src src-sh"><code>$ twistd dns --help
Usage: twistd [options] dns [options]
Options:
-c, --cache Enable record caching
-r, --recursive Perform recursive lookups
-v, --verbose Increment verbosity level
-i, --interface= The interface to which to bind [default: ]
-p, --port= The port on which to listen [default: 53]
--resolv-conf= Override location of resolv.conf (implies --recursive)
--hosts-file= Perform lookups with a hosts file
--help Display this help and exit.
--version Display Twisted version and exit.
--secondary= Act as secondary for the specified domain, performing zone
transfers from the specified IP (IP/domain)
--pyzone= Specify the filename of a Python syntax zone definition
--bindzone= Specify the filename of a BIND9 syntax zone definition
</code></pre>
</div>
</div>
</div>
<div id="outline-container-sec-1-3-2" class="outline-4">
<h4 id="sec-1-3-2">Output</h4>
<div class="outline-text-4" id="text-1-3-2">
<div class="org-src-container">
<pre class="src src-sh"><code>$ twistd -n dns --port 10053 --recursive
2013-09-20 04:36:08+0100 [-] Log opened.
2013-09-20 04:36:08+0100 [-] twistd 13.1.0 (/usr/bin/python 2.7.5) starting up.
2013-09-20 04:36:08+0100 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
2013-09-20 04:36:08+0100 [-] DNSServerFactory starting on 10053
2013-09-20 04:36:08+0100 [-] DNSDatagramProtocol starting on 10053
2013-09-20 04:36:08+0100 [-] Starting protocol &lt;twisted.names.dns.DNSDatagramProtocol object at 0x288da50&gt;
2013-09-20 04:36:40+0100 [DNSDatagramProtocol (UDP)] DNSDatagramProtocol starting on 61406
2013-09-20 04:36:40+0100 [DNSDatagramProtocol (UDP)] Starting protocol &lt;twisted.names.dns.DNSDatagramProtocol object at 0x2895450&gt;
2013-09-20 04:36:40+0100 [-] (UDP Port 61406 Closed)
2013-09-20 04:36:40+0100 [-] Stopping protocol &lt;twisted.names.dns.DNSDatagramProtocol object at 0x2895450&gt;
</code></pre>
</div>
<div class="org-src-container">
<pre class="src src-sh"><code>$ dig -p 10053 @localhost www.example.com A +short
93.184.216.119
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-sec-1-4" class="outline-3">
<h3 id="sec-1-4">twisted.names.authority</h3>
<div class="outline-text-3" id="text-1-4">
<div class="org-src-container">
<pre class="src src-python"><code>zone = [
SOA(
'example.com',
mname = "ns1.example.com",
rname = "dnsmaster.example.com",
serial = 2013092001,
refresh = "1H",
retry = "1H",
expire = "1H",
minimum = "1H"
),
NS('example.com', 'ns1.example.com'),
MX('example.com', 0, 'mail.example.com'),
A('example.com', '192.0.2.10'),
CNAME('www.example.com', 'example.com'),
A('mail.example.com', '192.0.2.20'),
A('ns1.example.com', '192.0.2.30'),
]
</code></pre>
</div>
<p>
example.com.py
</p>
</div>
<div id="outline-container-sec-1-4-1" class="outline-4">
<h4 id="sec-1-4-1">Output</h4>
<div class="outline-text-4" id="text-1-4-1">
<div class="org-src-container">
<pre class="src src-sh"><code>$ twistd -n dns --port 10053 --pyzone=examples/example.com.py
</code></pre>
</div>
<div class="org-src-container">
<pre class="src src-sh"><code>$ dig -p 10053 @localhost www.example.com A +short
example.com.
192.0.2.10
</code></pre>
</div>
</div>
</div>
</div>
<div id="outline-container-sec-1-5" class="outline-3">
<h3 id="sec-1-5">twisted.names.cache</h3>
</div>
<div id="outline-container-sec-1-6" class="outline-3">
<h3 id="sec-1-6">twisted.names.root</h3>
</div>
<div id="outline-container-sec-1-7" class="outline-3">
<h3 id="sec-1-7">twisted.names.secondary</h3>
</div>
<div id="outline-container-sec-1-8" class="outline-3">
<h3 id="sec-1-8">twisted.names.resolve</h3>
</div>
</div>
<div id="outline-container-sec-2" class="outline-2">
<h2 id="sec-2">What's New and Exciting in Twisted</h2>
<div class="outline-text-2" id="text-2">
</div><div id="outline-container-sec-2-1" class="outline-3">
<h3 id="sec-2-1">New Contributors</h3>
<div class="outline-text-3" id="text-2-1">
</div><div id="outline-container-sec-2-1-1" class="outline-4">
<h4 id="sec-2-1-1">ashfall, kaizhang, introom, hynek, shira, rwall, and others.</h4>
</div>
</div>
<div id="outline-container-sec-2-2" class="outline-3">
<h3 id="sec-2-2">New Features</h3>
<div class="outline-text-3" id="text-2-2">
</div><div id="outline-container-sec-2-2-1" class="outline-4">
<h4 id="sec-2-2-1">Hostname Endpoints ("Happy Eyeballs") &#x2013; ashfall, exarkun</h4>
<div class="outline-text-4" id="text-2-2-1">
<p>
<a href="https://twistedmatrix.com/trac/ticket/4859">https://twistedmatrix.com/trac/ticket/4859</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-2" class="outline-4">
<h4 id="sec-2-2-2">Deferred Cancellation &#x2013; kaizhang, itamar</h4>
<div class="outline-text-4" id="text-2-2-2">
<p>
<a href="http://kaigsoc.tumblr.com/">http://kaigsoc.tumblr.com/</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-3" class="outline-4">
<h4 id="sec-2-2-3">Stream parsing &#x2013; dash, simpson, introom</h4>
<div class="outline-text-4" id="text-2-2-3">
<p>
<a href="https://github.com/twisted/parsley-protocols">https://github.com/twisted/parsley-protocols</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-4" class="outline-4">
<h4 id="sec-2-2-4">Twisted Mail Updates &#x2013; shira</h4>
<div class="outline-text-4" id="text-2-2-4">
<p>
<a href="http://labs.twistedmatrix.com/2013/07/introducing-our-new-google-summer-of.html">http://labs.twistedmatrix.com/2013/07/introducing-our-new-google-summer-of.html</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-5" class="outline-4">
<h4 id="sec-2-2-5">Tubes &#x2013; glyph, dreid etc</h4>
<div class="outline-text-4" id="text-2-2-5">
<blockquote>
<p>
"Tubes": Create a composable, flow-control and back-pressure
friendly way to arrange parsing, processing, and emitting data
</p>
</blockquote>
<p>
<a href="https://twistedmatrix.com/trac/ticket/1956">https://twistedmatrix.com/trac/ticket/1956</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-6" class="outline-4">
<h4 id="sec-2-2-6">SSL Certificate Chains Secure SSL by Default &#x2013; AlexGaynor,hynek</h4>
<div class="outline-text-4" id="text-2-2-6">
<blockquote>
<p>
We wanted to address a few issues with existing cryptography libraries in Python:
</p>
<ul class="org-ul">
<li>Lack of PyPy and Python 3 support.
</li>
<li>Lack of maintenance.
</li>
<li>Use of poor implementations of algorithms (i.e. ones with known side-channel attacks).
</li>
<li>Lack of high level, “Cryptography for humans”, APIs.
</li>
<li>Absence of algorithms such as AES-GCM.
</li>
<li>Poor introspectability, and thus poor testability.
</li>
<li>Extremely error prone APIs, and bad defaults.
</li>
</ul>
</blockquote>
<p>
<a href="https://cryptography.readthedocs.org/en/latest/">https://cryptography.readthedocs.org/en/latest/</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-7" class="outline-4">
<h4 id="sec-2-2-7">Structured Logging &#x2013; hynek</h4>
<div class="outline-text-4" id="text-2-2-7">
<blockquote>
<p>
Structured logging means that you don’t write hard-to-parse and
hard-to-keep-consistent prose in your logs but that you log events
that happen in a context instead.
</p>
</blockquote>
<p>
<a href="http://www.structlog.org/en/0.2.0-0/">http://www.structlog.org/en/0.2.0-0/</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-8" class="outline-4">
<h4 id="sec-2-2-8">EDNS / DNSSEC &#x2013; rwall, bobnovas, philmayers</h4>
<div class="outline-text-4" id="text-2-2-8">
<blockquote>
<p>
With the addition of EDNS(0) and DNSSEC, Twisted Names will be an
even more flexible platform on which to base new and pioneering
DNS software.
</p>
</blockquote>
<p>
<a href="https://twistedmatrix.com/trac/wiki/EDNS0">https://twistedmatrix.com/trac/wiki/EDNS0</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-9" class="outline-4">
<h4 id="sec-2-2-9">twisted.positioning &#x2013; lvh</h4>
<div class="outline-text-4" id="text-2-2-9">
<p>
<a href="https://twistedmatrix.com/trac/ticket/3926">https://twistedmatrix.com/trac/ticket/3926</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-10" class="outline-4">
<h4 id="sec-2-2-10">WebSocket Server &#x2013; simpson, therve</h4>
<div class="outline-text-4" id="text-2-2-10">
<p>
<a href="https://twistedmatrix.com/trac/ticket/4173">https://twistedmatrix.com/trac/ticket/4173</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-11" class="outline-4">
<h4 id="sec-2-2-11">Sendfile Support &#x2013; therve</h4>
<div class="outline-text-4" id="text-2-2-11">
<p>
<a href="https://twistedmatrix.com/trac/ticket/585">https://twistedmatrix.com/trac/ticket/585</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-12" class="outline-4">
<h4 id="sec-2-2-12">Systemd Socket Activation - exarkun</h4>
<div class="outline-text-4" id="text-2-2-12">
<p>
<a href="https://twistedmatrix.com/documents/current/core/howto/systemd.html">https://twistedmatrix.com/documents/current/core/howto/systemd.html</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-13" class="outline-4">
<h4 id="sec-2-2-13">Crochet &#x2013; itamar</h4>
<div class="outline-text-4" id="text-2-2-13">
<blockquote>
<p>
Crochet is an MIT-licensed library that makes it easier for
threaded applications like Flask or Django to use the Twisted
networking framework, by providing:
</p>
<p>
An API to help threads interact with Twisted APIs, which are not thread-safe by default.
The ability to easily run the Twisted reactor in the background.
</p>
</blockquote>
<p>
<a href="https://github.com/itamarst/crochet">https://github.com/itamarst/crochet</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-14" class="outline-4">
<h4 id="sec-2-2-14">Treq &#x2013; dreid</h4>
<div class="outline-text-4" id="text-2-2-14">
<blockquote>
<p>
treq is an HTTP library inspired by requests but written on top of Twisted's Agents.
</p>
<p>
It provides a simple, higher level API for making HTTP requests when using Twisted.
</p>
</blockquote>
<p>
<a href="https://github.com/dreid/treq">https://github.com/dreid/treq</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-15" class="outline-4">
<h4 id="sec-2-2-15">Klein &#x2013; dreid</h4>
<div class="outline-text-4" id="text-2-2-15">
<blockquote>
<p>
Klein is a micro-framework for developing production ready web
services with python. It is 'micro' in that it has an incredibly
small API similar to bottle and flask. It is not 'micro' in that
it depends on things outside the standard library. This is
primarily because it is built on widely used and well tested
components like werkzeug and Twisted.
</p>
</blockquote>
<p>
<a href="https://github.com/twisted/klein">https://github.com/twisted/klein</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-16" class="outline-4">
<h4 id="sec-2-2-16">Python3 compatibility &#x2013; Thijs</h4>
<div class="outline-text-4" id="text-2-2-16">
<blockquote>
<p>
To have Twisted available on Python 3.3 and newer, with the same
functionality as is currently available on Python 2.x.
</p>
</blockquote>
<p>
<a href="https://twistedmatrix.com/trac/wiki/Plan/Python3">https://twistedmatrix.com/trac/wiki/Plan/Python3</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-17" class="outline-4">
<h4 id="sec-2-2-17">PyPy speedups &#x2013; Fijal, AlexGaynor</h4>
</div>
<div id="outline-container-sec-2-2-18" class="outline-4">
<h4 id="sec-2-2-18">Sphinx Documentation &#x2013; khorn</h4>
</div>
<div id="outline-container-sec-2-2-19" class="outline-4">
<h4 id="sec-2-2-19">Twisted As A House For Sale &#x2013; magmatt</h4>
<div class="outline-text-4" id="text-2-2-19">
<blockquote>
<p>
"Umm&#x2026;", you're beginning to doubt that this is really the house you want.
</p>
<p>
You step onto the porch and examine the doors. From left to right,
they are labeled "reactor.listen," "TCP4ServerEndpoint" and
"serverFromString." You reach for TCP4ServerEndpoint, but second
guess yourself and instead open the "reactor.listen" door. You're
standing in a small entryway. There's ample light coming from a
fluorescent fixture, though the light seems a bit sterile. Kind of
like an old hospital.
</p>
</blockquote>
<p>
<a href="https://twistedmatrix.com/pipermail/twisted-python/2013-August/027321.html">https://twistedmatrix.com/pipermail/twisted-python/2013-August/027321.html</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-20" class="outline-4">
<h4 id="sec-2-2-20">Twisted For The Win &#x2013; magmatt</h4>
<div class="outline-text-4" id="text-2-2-20">
<div class="figure">
<p><img src="images/twisted-for-the-win.png" alt="twisted-for-the-win.png" />
</p>
</div>
<p>
<a href="http://twistedftw.org/">http://twistedftw.org/</a>
</p>
</div>
</div>
<div id="outline-container-sec-2-2-21" class="outline-4">
<h4 id="sec-2-2-21">&#x2026;many more</h4>
</div>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="date">Date: Friday 20 September 2013</p>
<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 24.3.1 (<a href="http://orgmode.org">Org</a> mode 8.1.2)</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment