Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1011 lines (836 sloc) 27.7 KB
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>(Clojure School)</title>
<meta name="author" content="(Likely)"/>
<link rel="stylesheet" href="./reveal.js/css/reveal.min.css"/>
<link rel="stylesheet" href="./reveal.js/css/theme/moon.css" id="theme"/>
<link rel="stylesheet" href="css/zenburn.css"/>
<link rel="stylesheet" href="./reveal.js/css/print/pdf.css" type="text/css" media="print"/>
<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>Clojure School</h1>
<h2>Likely</h2>
<h2><a href="mailto:"></a></h2>
<h2></h2></section>
<section>
<section id="sec-1" >
<h2>One I prepared earlier</h2>
<div class="org-src-container">
<pre class="src src-sh">git clone git://github.com/likely/sketchy.git
<span style="color: #b0c4de;">cd</span> sketchy
lein start-server
<span style="color: #ff7f24;"># </span><span style="color: #ff7f24;">To connect to the REPL:</span>
lein repl :connect 7888
</pre>
</div>
</section>
</section>
<section>
<section id="sec-2" >
<h2>A quick refresher</h2>
<ul class="org-ul">
<li>Requests and responses are just maps
</li>
<li>Handlers are functions for turning requests into responses
</li>
<li>Atoms allow state to be mutated with pure functions
</li>
<li>Changes are atomic and thread safe
</li>
<li>We proved this by starting threads with future
</li>
</ul>
</section>
</section>
<section>
<section id="sec-3" >
<h2>Today's lesson</h2>
<ul class="org-ul">
<li>How does defroutes help turn requests into responses?
</li>
<li>What are other ways of dealing with concurrency?
</li>
<li>Can we use these ideas to make an interactive, multi-person app?
</li>
</ul>
</section>
</section>
<section>
<section id="sec-4" >
<h2>We'll be covering</h2>
<ul class="org-ul">
<li>Macros
</li>
<li>core.async
</li>
<li>ClojureScript
</li>
</ul>
</section>
</section>
<section>
<section id="sec-5" >
<h2>Caveat: these are big topics!</h2>
<p>
We could easily spend a day on each one.
</p>
<p>
We'll give you an understanding of the basics, and hopefully the hunger to find out more.
</p>
</section>
</section>
<section>
<section id="sec-6" >
<h2>In LISPs, (= Code Data)</h2>
<p>
(inc 0) is simply a list of two elements - the symbol 'inc', and the value '0'.
</p>
<p>
The REPL evaluates lists by treating the first argument as a function, and the rest as arguments to that function:
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (<span style="color: #b0c4de;">inc</span> 0)
1
</pre>
</div>
<p>
We can ask the REPL not to eval a form by quoting it:
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; '(<span style="color: #b0c4de;">inc</span> 0)
(<span style="color: #b0c4de;">inc</span> 0)
</pre>
</div>
<p>
This is why you needed to quote 'requires' in the first week - to stop the REPL trying to evaluate it!
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (<span style="color: #b0c4de;">require</span> '[clj-http.core <span style="color: #7fffd4;">:reload</span> <span style="color: #7fffd4;">:all</span>])
nil
</pre>
</div>
</section>
</section>
<section>
<section id="sec-7" >
<h2>Exercise</h2>
<p>
Try this on a 'defn' from last week - what does it return (literally)?
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; '(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">your-fn</span> [your-params] (do-something ...))
???
</pre>
</div>
</section>
</section>
<section>
<section id="sec-8" >
<h2>Eval is the opposite of quote</h2>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (<span style="color: #b0c4de;">eval</span> '(<span style="color: #b0c4de;">inc</span> 0))
1
</pre>
</div>
<p>
This is what the REPL is doing to your code!
</p>
</section>
</section>
<section>
<section id="sec-9" >
<h2>Macros</h2>
<p>
A macro is just a function that receives its arguments <b>unevaluated</b> at compile time.
</p>
<p>
Because the unevaluated arguments are <b>code</b>, macros can operate on the code <b>as if it were data</b>.
</p>
</section>
</section>
<section>
<section id="sec-10" >
<h2>Macros we've already used</h2>
<p>
'when', 'and' and 'or' are macros - because they need to control the execution order of their parameters.
</p>
<p>
If 'when' were a function, it could be implemented thus:
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">bad-when</span> [test &amp; then]
(<span style="color: #00ffff;">if</span> test
then
nil))
</pre>
</div>
<p>
But look what happens when the test is false:
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (bad-when (<span style="color: #b0c4de;">=</span> 1 0)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"uh oh!"</span>))
uh oh!
nil
</pre>
</div>
</section>
</section>
<section>
<section id="sec-11" >
<h2></h2>
<p>
Because functions' parameters are evaluated before the function is called, we will always evaluate the 'then' block!
</p>
<p>
<b>This will not do!</b>
</p>
<p>
So 'when' <b>must</b> be a macro.
</p>
</section>
</section>
<section>
<section id="sec-12" >
<h2>Macroexpand</h2>
<p>
You can use the function macroexpand and macroexpand-1 to see the effect of macros (indentation mine):
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (<span style="color: #b0c4de;">macroexpand-1</span> '(<span style="color: #00ffff;">when</span> (<span style="color: #b0c4de;">=</span> 1 0)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"uh oh!"</span>)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"this isn't good!"</span>)))
(<span style="color: #00ffff;">if</span> (<span style="color: #b0c4de;">=</span> 1 0)
(<span style="color: #00ffff;">do</span>
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"uh oh!"</span>)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"this isn't good!"</span>)))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-13" >
<h2>Exercise</h2>
<p>
What does the following expand to?
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">and</span> (<span style="color: #b0c4de;">=</span> 1 0) (<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"Hello World"</span>))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-14" >
<h2>Other macros in Clojure.core</h2>
<p>
and, or, when, while, for, cond, -&gt;, -&gt;&gt;
</p>
<p>
-&gt; and -&gt;&gt; are the threading macros - they restructure heavily nested code to make it more legible:
</p>
</section>
</section>
<section>
<section id="sec-15" >
<h2>Threading macros</h2>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [my-map {<span style="color: #7fffd4;">:b</span> 2
<span style="color: #7fffd4;">:c</span> {<span style="color: #7fffd4;">:d</span> 3
<span style="color: #7fffd4;">:e</span> 5}}]
(<span style="color: #b0c4de;">vals</span> (<span style="color: #b0c4de;">update-in</span> (<span style="color: #b0c4de;">assoc</span> my-map <span style="color: #7fffd4;">:b</span> 3) [<span style="color: #7fffd4;">:c</span> <span style="color: #7fffd4;">:e</span>] inc)))
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">could be better written as</span>
(<span style="color: #00ffff;">-&gt;</span> {<span style="color: #7fffd4;">:b</span> 2
<span style="color: #7fffd4;">:c</span> {<span style="color: #7fffd4;">:d</span> 3
<span style="color: #7fffd4;">:e</span> 5}}
(<span style="color: #b0c4de;">assoc</span> <span style="color: #7fffd4;">:b</span> 3)
(<span style="color: #b0c4de;">update-in</span> [<span style="color: #7fffd4;">:c</span> <span style="color: #7fffd4;">:e</span>] inc)
vals)
</pre>
</div>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [forecast-days (forecast <span style="color: #ffa07a;">"london,uk"</span> {<span style="color: #7fffd4;">:cnt</span> 10})]
(<span style="color: #b0c4de;">count</span> (<span style="color: #b0c4de;">remove</span> cloudy? forecast-days)))
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">could be written as:</span>
(<span style="color: #00ffff;">-&gt;&gt;</span> (forecast <span style="color: #ffa07a;">"london,uk"</span> {<span style="color: #7fffd4;">:cnt</span> 10})
(<span style="color: #b0c4de;">remove</span> cloudy?)
count)
</pre>
</div>
</section>
</section>
<section>
<section id="sec-16" >
<h2>Exercise</h2>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">Re-write the below using -&gt; threading macro</span>
(<span style="color: #b0c4de;">/</span> (<span style="color: #b0c4de;">*</span> (<span style="color: #b0c4de;">+</span> 10 2) 5) (<span style="color: #b0c4de;">*</span> 2 5))
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">Re-write the below using -&gt;&gt; threading macro</span>
(<span style="color: #b0c4de;">*</span> 10 (<span style="color: #b0c4de;">apply</span> + (<span style="color: #b0c4de;">map</span> inc (<span style="color: #b0c4de;">range</span> 10))))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-17" >
<h2>Macro magic: core.async</h2>
<p>
An implementation of Communicating Sequential Processes (CSP).
</p>
<p>
CSP is an old idea, but basis of concurrency in languages such as Google's Go.
</p>
<p>
The processes are more lightweight than threads, suitable for highly parallel web apps.
</p>
</section>
</section>
<section>
<section id="sec-18" >
<h2>core.async</h2>
<p>
<b>Channels</b> are the fundamental building blocks of core.async:
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (<span style="color: #b0c4de;">require</span> '[clojure.core.async <span style="color: #7fffd4;">:as</span> a])
nil
user=&gt; (a/chan)
#&lt;<span style="color: #b0c4de;">ManyToManyChannel</span> clojure.core.async.impl.channels.ManyToManyChannel@30804b08&gt;
</pre>
</div>
<p>
Normally, all operations on channels are blocking, but (so that we can
test the examples on the upcoming slides) we can asynchronously put a
value on a channel with 'put!':
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [out (a/chan)]
(put! out 5)
out)
</pre>
</div>
</section>
</section>
<section>
<section id="sec-19" >
<h2>Go!</h2>
<p>
Operations in core.async are usually found within 'go' blocks.
</p>
<p>
A 'go' block transparently translates your beautiful synchronous code
into the asynchronous callback-hell-style code you would have had to
write otherwise.
</p>
<p>
'Go' blocks return a channel eventually containing a single value - the result of the 'go' block:
</p>
<div class="org-src-container">
<pre class="src src-clojure">user=&gt; (go 5)
#&lt;<span style="color: #b0c4de;">ManyToManyChannel</span> clojure.core.async.impl.channels.ManyToManyChannel@30804b08&gt;
</pre>
</div>
</section>
</section>
<section>
<section id="sec-20" >
<h2>Taking from a channel</h2>
<p>
On the surface, &lt;! ('take') appears to accept a channel and synchronously return a value from it.
</p>
<p>
&lt;! must be used inside a go block.
</p>
<div class="org-src-container">
<pre class="src src-clojure">user&gt; (go
(<span style="color: #00ffff;">let</span> [value (&lt;! (go 5))]
(<span style="color: #b0c4de;">println</span> value)))
#&lt;<span style="color: #b0c4de;">ManyToManyChannel</span> clojure.core.async.impl.channels.ManyToManyChannel@5636e34&gt;
5
</pre>
</div>
<p>
It helps you avoid the following callback-hell: (pseudo-code)
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [ch (go 5)]
(on-receive ch
(<span style="color: #00ffff;">fn</span> [msg]
(<span style="color: #00ffff;">let</span> [value msg]
(<span style="color: #b0c4de;">println</span> value)))))
</pre>
</div>
<p>
See also: &gt;!
</p>
</section>
</section>
<section>
<section id="sec-21" >
<h2>Exercise</h2>
<p>
Create a channel, 'put!' two values onto it, and use a 'go' block to print them in a single vector.
</p>
</section>
</section>
<section>
<section id="sec-22" >
<h2>Exercise - Answer</h2>
<p>
Create a channel, 'put!' two values onto it, and use a 'go' block to print them in a single vector.
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [ch (a/chan)]
(go
(<span style="color: #00ffff;">let</span> [val-1 (&lt;! ch)
val-2 (&lt;! ch)]
(<span style="color: #b0c4de;">prn</span> [val-1 val-2])))
(put! out 42)
(put! out 64))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-23" >
<h2>Synchronous</h2>
<p>
The semantics of CSP are that takes and puts are synchronous.
</p>
<p>
If you take, it will block until something puts.
</p>
<p>
It you put, it will block until something takes.
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [c (chan)]
(go
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"We are here"</span>)
(&lt;! c)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"We won't get here"</span>)))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-24" >
<h2>Channels</h2>
<p>
Channels allow goroutines to talk to each other.
</p>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">Order doesn't matter</span>
user=&gt; (<span style="color: #00ffff;">let</span> [c (chan)]
(go
(&gt;! c <span style="color: #ffa07a;">"A message"</span>))
(go
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"We are here"</span>)
(&lt;! c)
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"We made progress"</span>)))
<span style="color: #b0c4de;">We</span> are here
#&lt;<span style="color: #b0c4de;">ManyToManyChannel</span> clojure.core.async.impl.channels.ManyToManyChannel@27d198c3&gt;
<span style="color: #b0c4de;">We</span> made progress
</pre>
</div>
</section>
</section>
<section>
<section id="sec-25" >
<h2>Looping</h2>
<p>
Clojure does have a 'loop' macro
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">loop</span> [a 1
b 10]
(<span style="color: #00ffff;">when</span> (<span style="color: #b0c4de;">&lt;</span> a b)
(<span style="color: #b0c4de;">prn</span> {<span style="color: #7fffd4;">:a</span> a <span style="color: #7fffd4;">:b</span> b})
(<span style="color: #00ffff;">recur</span> (<span style="color: #b0c4de;">inc</span> a) (<span style="color: #b0c4de;">dec</span> b))))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-26" >
<h2>Application to channels</h2>
<p>
Reading every message ever put on a channel:
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [ch (a/chan)]
(go
(<span style="color: #00ffff;">loop</span> []
(<span style="color: #00ffff;">when-let</span> [msg (&lt;! ch)]
(<span style="color: #b0c4de;">println</span> <span style="color: #ffa07a;">"Message received! -"</span> msg)
(<span style="color: #00ffff;">recur</span>)))))
</pre>
</div>
<p>
'go' and 'loop' are used together so often, that there is a 'go-loop' short-hand:
</p>
<div class="org-src-container">
<pre class="src src-clojure">(go-loop []
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">...</span>
(<span style="color: #00ffff;">recur</span>))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-27" >
<h2>Exercise:</h2>
<p>
In your REPL:
</p>
<ul class="org-ul">
<li>Define a channel with (def my-chan (a/chan))
</li>
<li>Set off a go-loop that asynchronously prints every message
</li>
<li>Put messages on your channel, and see them printed on the console!
</li>
</ul>
</section>
</section>
<section>
<section id="sec-28" >
<h2>ClojureScript</h2>
<p>
You can write client-side JavaScript in Clojure too!
</p>
</section>
</section>
<section>
<section id="sec-29" >
<h2>Writing Clojurescript</h2>
<p>
Open the file
</p>
<p>
/src/cljs/sketchy/client.cljs
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">ns</span> sketchy.client
(<span style="color: #7fffd4;">:require</span> [...]))
(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">greet</span> [name]
(<span style="color: #b0c4de;">str</span> <span style="color: #ffa07a;">"Hello "</span> name))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-30" >
<h2>Reload the page</h2>
<p>
And in your JavaScript console, type
</p>
<div class="org-src-container">
<pre class="src src-js">chitter.client.greet(<span style="color: #ffa07a;">"World"</span>);
=&gt; <span style="color: #ffa07a;">"Hello World"</span>
</pre>
</div>
</section>
</section>
<section>
<section id="sec-31" >
<h2>Javascript Interop</h2>
<p>
Property access
</p>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">obj.x becomes:</span>
(<span style="color: #b0c4de;">.-x</span> obj)
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">obj.x = y becomes:</span>
(set! (<span style="color: #b0c4de;">.-x</span> obj) y)
</pre>
</div>
<p>
Calling functions
</p>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">obj.call(something);</span>
(<span style="color: #b0c4de;">.call</span> obj something)
</pre>
</div>
<p>
Access global javascript object
</p>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">console.log("message") becomes:</span>
(js/console.log <span style="color: #ffa07a;">"message"</span>)
</pre>
</div>
</section>
</section>
<section>
<section id="sec-32" >
<h2>Exercise</h2>
<p>
Create an event handler in ClojureScript that will print out the mouse coordinates.
</p>
<div class="org-src-container">
<pre class="src src-js"><span style="color: #ff7f24;">// </span><span style="color: #ff7f24;">In javascript this would be</span>
window.addEventListener(<span style="color: #ffa07a;">"mousemove"</span>,
<span style="color: #00ffff;">function</span>(<span style="color: #eedd82;">event</span>) {
console.log(event);
});
</pre>
</div>
</section>
</section>
<section>
<section id="sec-33" >
<h2>Load JavaScript on page load</h2>
<p>
Add to bottom of ClojureScript:
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">main</span> []
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">do something interesting</span>
)
(set! (<span style="color: #b0c4de;">.-onload</span> js/window) main)
</pre>
</div>
<p>
We're calling a function called 'main' on page load.
</p>
</section>
</section>
<section>
<section id="sec-34" >
<h2>Putting UI events on a channel</h2>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">events</span> [el type]
(<span style="color: #00ffff;">let</span> [out (chan)]
(d/listen! el type
(<span style="color: #00ffff;">fn</span> [e]
(put! out e)))
out))
</pre>
</div>
<p>
We're outside a go block so we can't use &gt;!. We use the asynchronous version put!
</p>
</section>
</section>
<section>
<section id="sec-35" >
<h2>Exercise</h2>
<p>
Inside your main function, create a go loop that prints out the mousemove events
</p>
</section>
</section>
<section>
<section id="sec-36" >
<h2>Channels are like sequences</h2>
<p>
They have map and reduce too!
</p>
<div class="org-src-container">
<pre class="src src-clojure"><span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">Takes a function and a source channel, and returns a channel which</span>
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">contains the values produced by applying f to each value taken from</span>
<span style="color: #ff7f24;">;; </span><span style="color: #ff7f24;">the source channel</span>
(map&lt; some-fn some-channel)
</pre>
</div>
<p>
See also map&gt;, reduce, filter&gt;, filter&lt;, remove&gt;, remove&lt;
</p>
</section>
</section>
<section>
<section id="sec-37" >
<h2>Exercise</h2>
<p>
Adapt your main function to print out a vector containing only the x and y components of the mousemove event.
</p>
</section>
</section>
<section>
<section id="sec-38" >
<h2>Reading from more than one channel</h2>
<p>
core.async has a function 'alts!', that takes multiple channels, and
returns the first message from <b>any</b> of those channels:
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">let</span> [ch-1 (a/chan)
ch-2 (a/chan)]
(go-loop []
(<span style="color: #00ffff;">let</span> [[v c] (a/alts! [ch-1 ch-2])]
(<span style="color: #00ffff;">if</span> (<span style="color: #b0c4de;">=</span> c ch-1)
(handle-message-from-ch-1 ...)
(handle-message-from-ch-2 ...))
(<span style="color: #00ffff;">recur</span>))))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-39" >
<h2>Drawing into the canvas</h2>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">draw-point</span> [canvas [x y]]
(<span style="color: #00ffff;">let</span> [context (<span style="color: #b0c4de;">.getContext</span> canvas <span style="color: #ffa07a;">"2d"</span>)]
(<span style="color: #b0c4de;">.fillRect</span> context x y 10 10)))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-40" >
<h2>Exercise (+ homework)</h2>
<p>
Using the functions we have so far - finish the drawing app!
</p>
<p>
You'll need:
</p>
<ul class="org-ul">
<li>3 event channels - listening to mousemove, mousedown and mouseup events respectively
</li>
<li>A go-loop inside your 'main' fn - to react to events on all 3 channels and draw points if the mouse is down (hint: 'alts!')
</li>
<li>Any problems - let us know!
</li>
</ul>
</section>
</section>
<section>
<section id="sec-41" >
<h2>What we covered</h2>
<ul class="org-ul">
<li>Macros
</li>
<li>core.async
</li>
<li>ClojureScript
</li>
</ul>
</section>
</section>
<section>
<section id="sec-42" >
<h2>Thank You</h2>
</section>
</section>
<section>
<section id="sec-43" >
<h2>Not covered:</h2>
</section>
</section>
<section>
<section id="sec-44" >
<h2>Skip to the end</h2>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">main</span> []
(<span style="color: #00ffff;">let</span> [canvas (sel1 <span style="color: #7fffd4;">:#canvas</span>)
move (map&lt; e-&gt;v (events canvas <span style="color: #ffa07a;">"mousemove"</span>))
down (events canvas <span style="color: #ffa07a;">"mousedown"</span>)
up (events canvas <span style="color: #ffa07a;">"mouseup"</span>)]
(go-loop [draw-point? false]
(<span style="color: #00ffff;">let</span> [[v sc] (alts! [move down up])]
(<span style="color: #00ffff;">condp</span> = sc
down (<span style="color: #00ffff;">recur</span> true)
up (<span style="color: #00ffff;">recur</span> false)
move (<span style="color: #00ffff;">do</span> (<span style="color: #00ffff;">when</span> draw-point?
(js/console.log (<span style="color: #b0c4de;">pr-str</span> v)))
(<span style="color: #00ffff;">recur</span> draw-point?)))))))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-45" >
<h2>Websockets</h2>
<p>
Websockets are long-lived connections between the client and the server through which messages can be sent in both directions.
</p>
</section>
</section>
<section>
<section id="sec-46" >
<h2>Creating a channel from a websocket</h2>
<p>
Uncomment includes at the top of the handler
</p>
<div class="org-src-container">
<pre class="src src-clojure">(<span style="color: #00ffff;">defn</span> <span style="color: #87cefa;">socket-handler</span> [request]
(with-channel request ws-ch
(go-loop []
(<span style="color: #00ffff;">let</span> [{<span style="color: #7fffd4;">:keys</span> [message]} (&lt;! ws-ch)]
(&gt;! ws-ch message)
(<span style="color: #00ffff;">recur</span>)))))
</pre>
</div>
</section>
</section>
<section>
<section id="sec-47" >
<h2>In your browser's js console&#x2026;</h2>
<div class="org-src-container">
<pre class="src src-js"><span style="color: #00ffff;">var</span> <span style="color: #eedd82;">socket</span> = <span style="color: #00ffff;">new</span> <span style="color: #98fb98;">WebSocket</span>(<span style="color: #ffa07a;">"ws://localhost:3000/ws"</span>);
socket.onmessage = <span style="color: #00ffff;">function</span>(<span style="color: #eedd82;">event</span>) { console.log(event.data); }
socket.send(<span style="color: #ffa07a;">"Data to be sent"</span>);
</pre>
</div>
<p>
You should see the data you sent echoed back.
</p>
</section>
</section>
<section>
<section id="sec-48" >
<h2>Create a collaborative drawing app!</h2>
<p>
Adapt the server side keep an atom of clients, return events to all of them.
</p>
</section>
</section>
</div>
</div>
<script src="./reveal.js/lib/js/head.min.js"></script>
<script src="./reveal.js/js/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
rollingLinks: false,
keyboard: true,
overview: true,
// slide width
// slide height
// slide margin
// slide minimum scaling factor
// slide maximum scaling factor
theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
transition: Reveal.getQueryHash().transition || 'fade', // default/cube/page/concave/zoom/linear/fade/none
transitionSpeed: 'default',
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: './reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }
,{ src: './reveal.js/plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }
,{ src: './reveal.js/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }
,{ src: './reveal.js/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
,{ src: './reveal.js/plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }
,{ src: './reveal.js/plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
// { src: './reveal.js/plugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }
// { src: './reveal.js/plugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>