summaryrefslogtreecommitdiffstats
path: root/docs/en/cowboy/2.2/guide/ws_handlers/index.html
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2017-12-11 11:27:17 +0100
committerLoïc Hoguin <[email protected]>2017-12-11 11:27:17 +0100
commit1b863c350ba1f9b8ad1cb458df514ab0fe6bb127 (patch)
treef3f88acba06cce7095a047da8163ac0f92b1a64a /docs/en/cowboy/2.2/guide/ws_handlers/index.html
parent35825f89b61579d4270d6970609047945277acf7 (diff)
downloadninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.tar.gz
ninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.tar.bz2
ninenines.eu-1b863c350ba1f9b8ad1cb458df514ab0fe6bb127.zip
Add documentation for Cowboy 2.2
Diffstat (limited to 'docs/en/cowboy/2.2/guide/ws_handlers/index.html')
-rw-r--r--docs/en/cowboy/2.2/guide/ws_handlers/index.html430
1 files changed, 430 insertions, 0 deletions
diff --git a/docs/en/cowboy/2.2/guide/ws_handlers/index.html b/docs/en/cowboy/2.2/guide/ws_handlers/index.html
new file mode 100644
index 00000000..28f16a6a
--- /dev/null
+++ b/docs/en/cowboy/2.2/guide/ws_handlers/index.html
@@ -0,0 +1,430 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="">
+ <meta name="author" content="Loïc Hoguin based on a design from (Soft10) Pol Cámara">
+
+ <meta name="generator" content="Hugo 0.30.2" />
+
+ <title>Nine Nines: Websocket handlers</title>
+
+ <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700,400italic' rel='stylesheet' type='text/css'>
+ <link href="/css/99s.css?r=1" rel="stylesheet">
+
+ <link rel="shortcut icon" href="/img/ico/favicon.ico">
+ <link rel="apple-touch-icon-precomposed" sizes="114x114" href="/img/ico/apple-touch-icon-114.png">
+ <link rel="apple-touch-icon-precomposed" sizes="72x72" href="/img/ico/apple-touch-icon-72.png">
+ <link rel="apple-touch-icon-precomposed" href="/img/ico/apple-touch-icon-57.png">
+
+
+</head>
+
+
+<body class="">
+ <header id="page-head">
+ <div id="topbar" class="container">
+ <div class="row">
+ <div class="span2">
+ <h1 id="logo"><a href="/" title="99s">99s</a></h1>
+ </div>
+ <div class="span10">
+
+ <div id="side-header">
+ <nav>
+ <ul>
+ <li><a title="Hear my thoughts" href="/articles">Articles</a></li>
+ <li><a title="Watch my talks" href="/talks">Talks</a></li>
+ <li class="active"><a title="Read the docs" href="/docs">Documentation</a></li>
+ <li><a title="Request my services" href="/services">Consulting & Training</a></li>
+ </ul>
+ </nav>
+ <ul id="social">
+ <li>
+ <a href="https://github.com/ninenines" title="Check my Github repositories"><img src="/img/ico_github.png" data-hover="/img/ico_github_alt.png" alt="Github"></a>
+ </li>
+ <li>
+ <a title="Keep in touch!" href="http://twitter.com/lhoguin"><img src="/img/ico_microblog.png" data-hover="/img/ico_microblog_alt.png"></a>
+ </li>
+ <li>
+ <a title="Contact me" href="mailto:[email protected]"><img src="/img/ico_mail.png" data-hover="/img/ico_mail_alt.png"></a>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+
+
+</header>
+
+<div id="contents" class="two_col">
+<div class="container">
+<div class="row">
+<div id="docs" class="span9 maincol">
+
+<h1 class="lined-header"><span>Websocket handlers</span></h1>
+
+<div class="paragraph"><p>Websocket handlers provide an interface for upgrading HTTP/1.1
+connections to Websocket and sending or receiving frames on
+the Websocket connection.</p></div>
+<div class="paragraph"><p>As Websocket connections are established through the HTTP/1.1
+upgrade mechanism, Websocket handlers need to be able to first
+receive the HTTP request for the upgrade, before switching to
+Websocket and taking over the connection. They can then receive
+or send Websocket frames, handle incoming Erlang messages or
+close the connection.</p></div>
+<div class="sect1">
+<h2 id="_upgrade">Upgrade</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The <code>init/2</code> callback is called when the request is received.
+To establish a Websocket connection, you must switch to the
+<code>cowboy_websocket</code> module:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>Cowboy will perform the Websocket handshake immediately. Note
+that the handshake will fail if the client did not request an
+upgrade to Websocket.</p></div>
+<div class="paragraph"><p>The Req object becomes unavailable after this function returns.
+Any information required for proper execution of the Websocket
+handler must be saved in the state.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_subprotocol">Subprotocol</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The client may provide a list of Websocket subprotocols it
+supports in the sec-websocket-protocol header. The server <strong>must</strong>
+select one of them and send it back to the client or the
+handshake will fail.</p></div>
+<div class="paragraph"><p>For example, a client could understand both STOMP and MQTT over
+Websocket, and provide the header:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>sec-websocket-protocol: v12.stomp, mqtt</code></pre>
+</div></div>
+<div class="paragraph"><p>If the server only understands MQTT it can return:</p></div>
+<div class="listingblock">
+<div class="content">
+<pre><code>sec-websocket-protocol: mqtt</code></pre>
+</div></div>
+<div class="paragraph"><p>This selection must be done in <code>init/2</code>. An example usage could
+be:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:parse_header</span></span>(<span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"sec-websocket-protocol"</span><span style="color: #990000">&gt;&gt;</span>, <span style="color: #009900">Req0</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span>
+ <span style="color: #000080">undefined</span> <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req0</span>, <span style="color: #009900">State</span>};
+ <span style="color: #009900">Subprotocols</span> <span style="color: #990000">-&gt;</span>
+ <span style="font-weight: bold"><span style="color: #0000FF">case</span></span> <span style="font-weight: bold"><span style="color: #000000">lists:keymember</span></span>(<span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"mqtt"</span><span style="color: #990000">&gt;&gt;</span>, <span style="color: #993399">1</span>, <span style="color: #009900">Subprotocols</span>) <span style="font-weight: bold"><span style="color: #0000FF">of</span></span>
+ <span style="color: #000080">true</span> <span style="color: #990000">-&gt;</span>
+ <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:set_resp_header</span></span>(<span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"sec-websocket-protocol"</span><span style="color: #990000">&gt;&gt;</span>,
+ <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"mqtt"</span><span style="color: #990000">&gt;&gt;</span>, <span style="color: #009900">Req0</span>),
+ {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>};
+ <span style="color: #000080">false</span> <span style="color: #990000">-&gt;</span>
+ <span style="color: #009900">Req</span> <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #000000">cowboy_req:reply</span></span>(<span style="color: #993399">400</span>, <span style="color: #009900">Req0</span>),
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>}
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span><span style="color: #990000">.</span></tt></pre></div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_post_upgrade_initialization">Post-upgrade initialization</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Cowboy has separate processes for handling the connection
+and requests. Because Websocket takes over the connection,
+the Websocket protocol handling occurs in a different
+process than the request handling.</p></div>
+<div class="paragraph"><p>This is reflected in the different callbacks Websocket
+handlers have. The <code>init/2</code> callback is called from the
+temporary request process and the <code>websocket_</code> callbacks
+from the connection process.</p></div>
+<div class="paragraph"><p>This means that some initialization cannot be done from
+<code>init/2</code>. Anything that would require the current pid,
+or be tied to the current pid, will not work as intended.
+The optional <code>websocket_init/1</code> can be used instead:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ <span style="font-weight: bold"><span style="color: #000000">erlang:start_timer</span></span>(<span style="color: #993399">1000</span>, <span style="font-weight: bold"><span style="color: #000080">self</span></span>(), <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">&gt;&gt;</span>),
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>All Websocket callbacks share the same return values. This
+means that we can send frames to the client right after
+the upgrade:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">&gt;&gt;</span>}, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_receiving_frames">Receiving frames</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Cowboy will call <code>websocket_handle/2</code> whenever a text, binary,
+ping or pong frame arrives from the client.</p></div>
+<div class="paragraph"><p>The handler can handle or ignore the frames. It can also
+send frames back to the client or stop the connection.</p></div>
+<div class="paragraph"><p>The following snippet echoes back any text frame received and
+ignores all others:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">Frame</span> <span style="color: #990000">=</span> {<span style="color: #FF6600">text</span>, <span style="color: #990000">_</span>}, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, <span style="color: #009900">Frame</span>, <span style="color: #009900">State</span>};
+<span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">_Frame</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>Note that ping and pong frames require no action from the
+handler as Cowboy will automatically reply to ping frames.
+They are provided for informative purposes only.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_receiving_erlang_messages">Receiving Erlang messages</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Cowboy will call <code>websocket_info/2</code> whenever an Erlang message
+arrives.</p></div>
+<div class="paragraph"><p>The handler can handle or ignore the messages. It can also
+send frames to the client or stop the connection.</p></div>
+<div class="paragraph"><p>The following snippet forwards log messages to the client
+and ignores all others:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>({<span style="font-weight: bold"><span style="color: #000080">log</span></span>, <span style="color: #009900">Text</span>}, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #009900">Text</span>}, <span style="color: #009900">State</span>};
+<span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_sending_frames">Sending frames</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>All <code>websocket_</code> callbacks share return values. They may
+send zero, one or many frames to the client.</p></div>
+<div class="paragraph"><p>To send nothing, just return an ok tuple:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>To send one frame, return a reply tuple with the frame to send:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">&gt;&gt;</span>}, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>You can send frames of any type: text, binary, ping, pong
+or close frames.</p></div>
+<div class="paragraph"><p>To send many frames at once, return a reply tuple with the
+list of frames to send:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, [
+ {<span style="color: #FF6600">text</span>, <span style="color: #FF0000">"Hello"</span>},
+ {<span style="color: #FF6600">text</span>, <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"world!"</span><span style="color: #990000">&gt;&gt;</span>},
+ {<span style="font-weight: bold"><span style="color: #000080">binary</span></span>, <span style="color: #990000">&lt;&lt;</span><span style="color: #993399">0</span><span style="color: #990000">:</span><span style="color: #993399">8000</span><span style="color: #990000">&gt;&gt;</span>}
+ ], <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>They are sent in the given order.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_keeping_the_connection_alive">Keeping the connection alive</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>Cowboy will automatically respond to ping frames sent by
+the client. They are still forwarded to the handler for
+informative purposes, but no further action is required.</p></div>
+<div class="paragraph"><p>Cowboy does not send ping frames itself. The handler can
+do it if required. A better solution in most cases is to
+let the client handle pings. Doing it from the handler
+would imply having an additional timer per connection and
+this can be a considerable cost for servers that need to
+handle large numbers of connections.</p></div>
+<div class="paragraph"><p>Cowboy can be configured to close idle connections
+automatically. It is highly recommended to configure
+a timeout here, to avoid having processes linger longer
+than needed.</p></div>
+<div class="paragraph"><p>The <code>init/2</code> callback can set the timeout to be used
+for the connection. For example, this would make Cowboy
+close connections idle for more than 30 seconds:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">init</span></span>(<span style="color: #009900">Req</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">cowboy_websocket</span>, <span style="color: #009900">Req</span>, <span style="color: #009900">State</span>, #{
+ <span style="color: #0000FF">idle_timeout</span> <span style="color: #990000">=&gt;</span> <span style="color: #993399">30000</span>}}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>This value cannot be changed once it is set. It defaults to
+<code>60000</code>.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_saving_memory">Saving memory</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The Websocket connection process can be set to hibernate
+after the callback returns.</p></div>
+<div class="paragraph"><p>Simply add an <code>hibernate</code> field to the ok or reply tuples:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_init</span></span>(<span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span>
+
+<span style="font-weight: bold"><span style="color: #000000">websocket_handle</span></span>(<span style="color: #009900">_Frame</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">ok</span>, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span>
+
+<span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">reply</span>, {<span style="color: #FF6600">text</span>, <span style="color: #990000">&lt;&lt;</span><span style="color: #FF0000">"Hello!"</span><span style="color: #990000">&gt;&gt;</span>}, <span style="color: #009900">State</span>, <span style="color: #FF6600">hibernate</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>It is highly recommended to write your handlers with
+hibernate enabled, as this allows to greatly reduce the
+memory usage. Do note however that an increase in the
+CPU usage or latency can be observed instead, in particular
+for the more busy connections.</p></div>
+</div>
+</div>
+<div class="sect1">
+<h2 id="_closing_the_connection">Closing the connection</h2>
+<div class="sectionbody">
+<div class="paragraph"><p>The connection can be closed at any time, either by telling
+Cowboy to stop it or by sending a close frame.</p></div>
+<div class="paragraph"><p>To tell Cowboy to close the connection, use a stop tuple:</p></div>
+<div class="listingblock">
+<div class="content"><!-- Generator: GNU source-highlight 3.1.8
+by Lorenzo Bettini
+http://www.lorenzobettini.it
+http://www.gnu.org/software/src-highlite -->
+<pre><tt><span style="font-weight: bold"><span style="color: #000000">websocket_info</span></span>(<span style="color: #009900">_Info</span>, <span style="color: #009900">State</span>) <span style="color: #990000">-&gt;</span>
+ {<span style="color: #FF6600">stop</span>, <span style="color: #009900">State</span>}<span style="color: #990000">.</span></tt></pre></div></div>
+<div class="paragraph"><p>Sending a <code>close</code> frame will immediately initiate the closing
+of the Websocket connection. Note that when sending a list of
+frames that include a close frame, any frame found after the
+close frame will not be sent.</p></div>
+</div>
+</div>
+
+
+
+
+
+
+
+
+
+
+ <nav style="margin:1em 0">
+
+ <a style="float:left" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/ws_protocol/">
+ The Websocket protocol
+ </a>
+
+
+
+ <a style="float:right" href="https://ninenines.eu/docs/en/cowboy/2.2/guide/streams/">
+ Streams
+ </a>
+
+ </nav>
+
+
+
+
+</div>
+
+<div class="span3 sidecol">
+
+
+<h3>
+ Cowboy
+ 2.2
+
+ User Guide
+</h3>
+
+<ul>
+
+ <li><a href="/docs/en/cowboy/2.2/guide">User Guide</a></li>
+
+
+ <li><a href="/docs/en/cowboy/2.2/manual">Function Reference</a></li>
+
+
+</ul>
+
+<h4 id="docs-nav">Navigation</h4>
+
+<h4>Version select</h4>
+<ul>
+
+
+
+ <li><a href="/docs/en/cowboy/2.2/guide">2.2</a></li>
+
+ <li><a href="/docs/en/cowboy/2.1/guide">2.1</a></li>
+
+ <li><a href="/docs/en/cowboy/2.0/guide">2.0</a></li>
+
+ <li><a href="/docs/en/cowboy/1.0/guide">1.0</a></li>
+
+</ul>
+
+</div>
+</div>
+</div>
+</div>
+
+ <footer>
+ <div class="container">
+ <div class="row">
+ <div class="span6">
+ <p id="scroll-top"><a href="#">↑ Scroll to top</a></p>
+ <nav>
+ <ul>
+ <li><a href="mailto:[email protected]" title="Contact us">Contact us</a></li><li><a href="https://github.com/ninenines/ninenines.github.io" title="Github repository">Contribute to this site</a></li>
+ </ul>
+ </nav>
+ </div>
+ <div class="span6 credits">
+ <p><img src="/img/footer_logo.png"></p>
+ <p>Copyright &copy; Loïc Hoguin 2012-2016</p>
+ </div>
+ </div>
+ </div>
+ </footer>
+
+
+ <script src="/js/custom.js"></script>
+ </body>
+</html>
+
+