-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
548 lines (463 loc) · 24.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Ruth's talk about CSS Houdini">
<title>CSS Houdini</title>
<link rel="stylesheet" type="text/css" href="reveal.js-3.8.0/css/reveal.css">
<link rel="stylesheet" href="reveal.js-3.8.0/css/theme/rumyra.css" id="theme">
<link rel="stylesheet" href="reveal.js-3.8.0/lib/css/zenburn.css">
<style type="text/css">
/* these are really just here for reference but yeh cool */
:root {
--purple: hsla(273, 36%, 64%, 1);
--pink: hsla(346, 63%, 64%, 1);
--orange: hsla(5, 74%, 67%, 1);
--green: hsla(131, 30%, 63%, 1);
--blue: hsla(179, 38%, 58%, 1);
}
.reveal {
--mainColour: var(--purple);
background-image: paint(dots);
}
.button {
--unit: 1.2rem;
display: block; margin: 0 auto;
padding: var(--unit) calc(var(--unit)*2);
width: calc(30% + 20px);
background: transparent linear-gradient(180deg, transparent, white) no-repeat top left;
background-position: 0% 0%;
border: none;
border-top: 4px solid var(--mainColour);
border-radius: 2px;
font-size: calc(var(--unit)*2); color: var(--mainColour);
/*font-family: "zillaslab", serif;*/
cursor: pointer;
transform: scale(0.95);
}
.hover .button {
background: var(--mainColour) linear-gradient(180deg, var(--mainColour), var(--lighterMain)) no-repeat left top;
color: white;
border-color: var(--mainColour);
transform: scale(1);
}
</style>
</head>
<body>
<!-- TALK +++++++++++++++++++++++++++++++++ -->
<div class="reveal">
<div class="slides">
<section class="dark" data-background-color="hsla(315, 3%, 25%, 1)">
<h1>Escape the box with Houdini</h1>
<h2>Ruth John | @rumyra</h2>
</section>
<section class="purple" data-state="purple">
<h1>Hello</h1>
<h2>I'm Ruth | @rumyra</h2>
<h2><b class="fragment">👩🏻💻</b> <b class="fragment">🎙</b> <b class="fragment">🎓</b></h2>
<aside class="notes">
<p>ctrl-i dev tools - paint worklet in sublime</p>
<p>Hi everyone, quick intro - I'm Ruth. You can find me on everything as @rumyra</p>
<p>I'm a creative dev, I run a podcast, I teach</p>
</aside>
</section>
<section class="purple">
<h1 class="purple">CSS Houdini</h1>
<h2>🧚🏻♀️ ✨</h2>
<aside class="notes">
<p>This is an introductory talk to what's involved with houdini</p>
<p>So today, we're going to have a lesson on CSS Houdini. Back last year I helped write some demos for MDN docs</p>
<p>I'm going to share with you what I learnt whilst doing this.</p>
</aside>
</section>
<section class="purple">
<h1>What is Houdini?</h1>
<h2 class="fragment">Suite of APIs</h2>
<h2 class="fragment">Extend CSS through JS</h2>
<aside class="notes">
<p>🚨 Houdini is basically just a buzz word. Someone came up with it and it stuck, because there's a whole bunch of apis that are being drafted and written, which allow us as developers better access to CSS, through javascript. Houdini is just the word that describes all of them together 🚨</p>
<p>At the moment, if a new feature comes out in CSS, say conic gradient, as we see with new features, it may take some time for those features to be implemented by browsers, polyfills as they stand are cumbersome and unperformant, and so Houdini looks to solve this problem.</p>
<p>It is not, and I say this strongly, a new shiny css thing we are going to polyfill.</p>
<p>Let's take a look at the api's currently under the suite of Houdini.</p>
</aside>
</section>
<section class="lists purple">
<div class="list-left">
<ul>
<li><h3>Typed OM</h3></li>
<li class="fragment"><h3>CSS Paint API</h3></li>
<li class="fragment"><h3>Properties & Values</h3></li>
<li class="fragment"><h3>Layout API</h3></li>
<li class="fragment"><h3>Animation Worklet</h3></li>
</ul>
</div>
<aside class="notes">
<p>So there's Typed OM, Pant API, Properties & Values, Layout API and Animation Worklet. This is what I'm going to be talking about today</p>
<p>Today I am going to deep dive into Typed OM, Paint * properties & values. and discuss Layout and animation.</p>
<p>time & I'll show you why</p>
</aside>
</section>
<section class="purple" data-state="purple">
<img src="ihry.jpg" />
<p><a data-preview-link href="https://ishoudinireadyyet.com/">https://ishoudinireadyyet.com/</a></p>
<aside class="notes">
<p>This is the support for CSS Houdini as it stands at the time of this talk.</p>
<p>I've omitted parser & font metrics because they are red and there's no implememntation yet</p>
<p>Talk about each api</p>
<p>So let's start from the top - with probably what I deem to be the most important - Typed OM.</p>
</aside>
</section>
<section class="blue" data-state="blue">
<h1 class="blue">Typed OM</h1>
<h2>Access to CSS Values as types in JS</h2>
<aside class="notes">
<p>So let's start from the top - with probably what I deem to be the most important - Typed OM.</p>
<p>This pretty much underpins all the other APIs, standalone its very verbose and can seem cumbersome as I'm just about to take you through it</p>
<p>To sum it up: Access to CSS values as types in javascript</p>
<p>Now the easiest way for me to explain this is to show you how we access styles in js at the moment</p>
</aside>
</section>
<section class="blue">
<button class="button">Click Me</button>
<pre><code data-trim data-noescape>button {
border-width-top: 4px;
}</code></pre>
<aside class="notes">
<p>Just a little bit of syntax before we move on. Selectors, properties, values.</p>
</aside>
</section>
<section data-state="style" class="blue">
<button class="button">Click Me</button>
<pre><code data-trim data-noescape>const borderWidth = window.getComputedStyle(buttonEl).borderTopWidth; // "4px"
// some string matching, testing & calculation...
buttonEl.style.borderWidth = "2px";</code></pre>
<aside class="notes">
<p>If we want to compute a new top border value with javascript, for whatever reason. As it stands this is how we access that value, and re add it to our button. To do the calculation we have to do some weird string thing where we count back from the string because there could be any number of numbers at the beginning, and that's because we're sure it's pixels and not some other unit, like rem,
<p>Extracting the number isn't easy.</p> <p>Then we gotta do the math and string it back together and it's 2020.</p>
<p>Wouldn't it be cool if we could do something like this:</p>
</aside>
</section>
<section data-state="typed" class="blue">
<button class="button">Click Me</button>
<pre><code data-trim data-noescape>buttonEl.computedStyleMap() // returns all css!
const borderWidth = buttonEl.computedStyleMap().get('border-top-width');
// Returns: {value: 4, unit: "px"}
// So we can now do:
const newWidth = borderWidth.value + 2; // gives us 6
</code></pre>
<aside class="notes">
<p>This is a new method 'computedStyleMap' which you invoke on an element and it will return all the CSS styles available on that element.</p>
<p>With the get method you can specify one property, but the really good thing about this interface, is the value is returned as an object</p>
<p>An object containing the value and the unit. The value is numerical, so it's easy to use out the box.</p>
<p>The type of value that is returned is a CSSUnitValue.</p>
</aside>
</section>
<!-- different types and creating different types -->
<section class="lists blue">
<div class="list-left">
<ul>
<li><code>CSSStyleValue</code></li>
<li class="fragment"><code>CSSNumericValue</code></li>
<li class="fragment"><code>CSSUnitValue</code></li>
<li class="fragment"><code>CSSMathSum</code></li>
</ul>
</div>
<aside class="notes">
<p> This is a sub class of a parent type called 🚨 CSSNumericValue</p>
<p>CSSStyleValue is the parent class of all the different types</p>
<p>There's lots of these value types - this is the idea behind typed om, that eventually all values in css will have a type</p>
<p>As well as CSSUnitValue, we have CSSMathSum for when you use the calc function in CSS</p>
<!-- <p>These are the numeric values and they all work in a similar way to the CSS unit we have seen. Returning an object configured specifically for that type.</p> -->
</aside>
</section>
<section class="lists blue">
<div class="list-left">
<ul>
<li class="fragment"><code>CSSTransformValue</code></li>
<li class="fragment"><code>CSSKeywordValue</code></li>
<li class="fragment"><code>CSSUnparsedValue</code></li>
<li class="fragment"><code>CSSImageValue</code></li>
</ul>
</div>
<aside class="notes">
<p>As well as our numeric values, there are a number of others:</p>
<p>transform value, this is for any values we would use in the transform property: translate, rotate, skew...</p>
<p>keyword value so a word that's not a incased in quotes like a string. So inherit or auto, or block, inline</p>
<p>unparsed - values that aren't known, like when we declare custom properties.<p>CSSImageValue is a type for where you would use an image, background, border, mask. But can be an actual image or a gradient or custom paint, so is intentionally opache at this time.</p>
<p>There's going to be more - css colour value</p>
</aside>
</section>
<section class="blue">
<pre><code data-trim data-noescape>button {transform: rotate(30deg);}
// Returns: {
// angle: {value: 30, unit: "deg"},
// is2D: true
//}
</code></pre>
<aside class="notes">
<p>All these different value types return an object similarly to what we've seen with unit value.</p>
<p>For instance a rotate value would look a little something like this:</p>
</aside>
</section>
<!-- how do we create a value -->
<section data-state="make" class="blue">
<button class="button" id="butt">Click Me</button>
<pre><code data-trim data-noescape>new CSSUnitValue(10, px);
CSS.px(10);
// both create {value: 10, unit: "px"}
</code></pre>
<aside class="notes">
<p>So we've seen how we get a CSS value affecting an element, and the different types of values we could receive. How do we create one, and then set it?</p>
<p>We create the CSSStyleValue</p>
<p>Couple of ways - we can use the class constructor new - or (if it's a CSSUnitValue) the easier factory method of CSS.px (units)</p>
</aside>
</section>
<!-- how do we set an attribute -->
<section class="blue">
<button class="button" id="butt">Click Me</button>
<pre><code data-trim data-noescape>buttonEl.attributeStyleMap().set('border-top-width', CSS.px(10));
buttonEl.attributeStyleMap.has('border-top-width') // returns true
buttonEl.attributeStyleMap.delete('border-top-width') // removes from attribute styles
buttonEl.attributeStyleMap.clear() // removes all attribute styles
buttonEl.attributeStyleMap().get('border-top-width') // returns CSSUnitValue
</code></pre>
<aside class="notes">
<p>we saw .style method earlier. In js as it stands at the moment we set values on the style attribute - this doesn't change but we have access to that via the styleAttributeMap</p>
<p>This represents all the styles within the style attribute.</p>
<p>And we get a few more methods, </p>
<p>Couple of other methods on the sytleattrmap - get has delete clear</p>
</aside>
</section>
<section class="blue">
<pre><code data-trim data-noescape>let sum = CSS.px(54).add(CSS.px(30));
// Returns: CSSUnitValue {value: 84, unit: "px"}
const cm = CSS.in(2).to('cm');
// Returns: CSSUnitValue {value: 5.08, unit: "cm"}
const fontSize = CSS.em(1.2);
CSS.em(1.2).equals(fontSize); // true
</code></pre>
<aside class="notes">
<p>If you're working with numeric types there's a few methods to be aware of:</p>
<p>You can add subtract divide and multiply with methods.</p>
<p>You can convert units! there's a 'to' method. Only works on absolute units are this time, but still handy</p>
<p>There's an equals method for testing if two unit values are a match.</p>
<p>And these are just a few. It seemed a bit cumbersome before with all the value types right. But if we are getting this functionality for all our values in the future, it really changes how we power our styles with javascript.</p>
</aside>
</section>
<section class="pink" data-state="pink">
<h1 class="pink">Properties & Values</h1>
<h2>Custom Properties</h2>
<aside class="notes">
<p>So we know Typed OM is cool, but it might seem a little strange to start, and a _lot_. Sometimes you just want to add styles, or you have classList and you can toggle now and that's ok. Be careful of performance. But the real thing with Typed OM is how it underpins all the other APIs.</p>
<p>This is easily seen with properties & values. We've all seen css variables - I'm using them for the button:</p>
</aside>
</section>
<section class="pink" data-state="getMain">
<pre><code data-trim data-noescape>button {
--mainColour: blue;
background-color: --mainColour;
}</code></pre>
<aside class="notes">
<p>So I have always struggled with the term CSS variables and I won't fight with people over this because I have better things to do with my life, but when you set a variable in a program you write, to update that variable, you reset it further in your code.</p>
<p>Custom properties in CSS are live, I update them in my js and they update in real time: like this...</p>
</aside>
</section>
<section class="pink">
<button class="button">Click Me</button>
<pre><code data-trim data-noescape>buttonEl.style.setProperty("--mainColour", "pink")</code></pre>
<aside class="notes">
<p>This is how I'm changing the colour of the button in this talk. It's the same as the backgrounds - they're all running from this mainColour property, which I update for every section - but this is not properties and values just yet. </p>
<!-- <p>Properties and values is sort of an extension of this - think back to typed om - this is cool, but there's no typing - we're still using strings. What if, you could register a custom property, with the value being typed</p> -->
</aside>
</section>
<section class="pink hover">
<button class="button">Click Me</button>
<pre><code data-trim data-noescape>background-image:
linear-gradient(180deg, var(--mainColour), var(--lighterMain))
;</code></pre>
<aside class="notes">
<p>The hover style for the button uses a background gradient</p>
<p>Now this can get a little bit annoying - because now I have to list all the different colours in the talk, purple, blue, pink & their relative lighter versions - I'm not using any preprocessors, like sass, so I have no access to any colour functions like lighter - which may or may not be coming into spec</p>
<p>So let's use houdini to polyfill and generate a lighter colour</p>
</aside>
</section>
<section class="pink">
<pre><code data-trim data-noescape data-line-numbers="1">const mainColour = revealOuter.attributeStyleMap.get("--mainColour");
// split string into dif vals & add more to lum
const splitCol = colFromHsla(mainColour[0]);
splitCol.lum = splitCol.lum+10;
// lighter col string
const lighterCol = `hsla(${splitCol.hue}, ${splitCol.sat}%, ${splitCol.lum}%, ${splitCol.op})`;</code></pre>
<aside class="notes">
<p>First of all let's use javascript to generate a lighter colour - now remember we don't have a colour type in typed om yet - when we do this _will_ be easier.</p>
<p>typed om attristylemap to get our main colour</p>
</aside>
</section>
<section class="pink">
<pre><code data-trim data-noescape data-line-numbers="3-5">const mainColour = revealOuter.attributeStyleMap.get("--mainColour");
// split string into dif vals & add more to lum
const splitCol = colFromHsla(mainColour[0]);
splitCol.lum = splitCol.lum+10;
// lighter col string
const lighterCol = `hsla(${splitCol.hue}, ${splitCol.sat}%, ${splitCol.lum}%, ${splitCol.op})`;</code></pre>
<aside class="notes">
<p>I'm running a function here to split the hsla string to hue, sat, lum & op vals</p>
<p>It's worth mentioning, when we get CSSColourVals in Typed OM I won't need to do this and my life will be amazing and wow.</p>
<p>Now I can use props and vals & register this new colour as a custom property - this is the properties and values api.</p>
</aside>
</section>
<section class="pink">
<pre><code data-trim data-noescape data-line-numbers="7-8">const mainColour = revealOuter.attributeStyleMap.get("--mainColour");
// split string into dif vals & add more to lum
const splitCol = colFromHsla(mainColour[0]);
splitCol.lum = splitCol.lum+10;
// lighter col string
const lighterCol = `hsla(${splitCol.hue}, ${splitCol.sat}%, ${splitCol.lum}%, ${splitCol.op})`;</code></pre>
<aside class="notes">
<p>Then I'm putting the string back together</p>
<p>Now, now I can use props and vals & register this new colour as a custom property - this is the properties and values api.</p>
</aside>
</section>
<section class="pink">
<pre><code data-trim data-noescape>CSS.registerProperty({
name: '--lighterMain',
syntax: '<color>',
inherits: true,
initialValue: lighterCol
});</code></pre>
<aside class="notes">
<p>We use the registerProperty method, we define a name - we have to do this and give it the dash dash</p>
<p>Syntax is the type, and this sort of matches up with typed om, that's whats underneath the hood</p>
<p>Inherits is set to false by default, this means elements further down the dom tree don't have access to it - or rather the value - unles we se that to true</p>
<p>Then we have the initial value, now we have to be pretty explicit with this. If you're defining the unit, the initial value needs the unit.</p>
<p>I didn't need to do all that in CSS, I have the power of javascript to do the colour changes.</p>
</aside>
</section>
<section class="pink" data-state="pink">
<h1>TYPES</h1>
<h2>Animatable</h2>
<aside class="notes">
<p>Types are related to Typed OM - there will be all eventually</p>
<p>They are animatable</p>
</aside>
</section>
<section class="pink" data-state="pink">
<h2>Ana Tudor<br />@thebabydino</h2>
<img src="ana.jpg" />
<aside class="notes">
<p>If you're interested in more, check out ana tudors work on codepen</p>
</aside>
</section>
<section class="purple" data-state="purple">
<h1 class="purple">Workers & Worklets</h1>
<aside class="notes">
<p>ASIDE - before I move on I just want to break, aside for just a moment to mention workers and worklets.</p>
<p>Workers in javascript mean running a script off the main thread, you have your javascript file, you register it as a worker and you can send messgaes (data) to and from it from your main script or main thread and it runs off the main thread - yes we're all ok good</p>
<p>A worklet is also running off the main thread, but it has a predefined class, with built in props and methods exposed (api) - again you register and make.</p>
<p>Cool ok I can move on</p>
</aside>
</section>
<section class="green" data-state="green">
<h1 class="green">CSS Paint API</h1>
<h2>🎨</h2>
<aside class="notes">
<p>Allows us to register a paint worklet (see what I did there) in js, for use whereever we might want to use an image in our css - so backgrounds, borders, image masking - now you might think - we have images, but, my class, we can draw it. This means resizing, no downloading. The worklet harnesses the canvas api. let me show you.</p>
</aside>
</section>
<section class="green">
<pre><code data-trim data-noescape>.slide {
background-image: paint(dots);
}</code></pre>
<pre><code data-trim data-noescape>CSS.paintWorklet.addModule('dots.js');</code></pre>
<aside class="notes">
<p>The backgrounds you have seen all the way through this talk, have been using the paint api - and actually, if I refresh this page, it should change colour.</p>
<p>If I resize the window, the highlight will change too. THis is how you do it. You register the paint worklet in your main script, you create this worklet. Then you call it within your css, where you would use an image in your css.</p>
</aside>
</section>
<section class="green" data-state="green">
<pre><code data-trim data-noescape>registerPaint('dots', class {
// use this function to retrieve any custom props defined for the element
static get inputProperties() { return ['--mainColour']; }
paint(ctx, size, props) {
// set colour
const colour = props.get('--mainColour');
// draw dots here - using html5 canvas api
}
});</code></pre>
<aside class="notes">
<p>Which is your worklet.</p>
<p>Function pass in name and class</p>
<p>Automatically registered as a paint worklet class</p>
<p>that gives you dimensions, any custom properties which are affecting the element. And in there you can use the canvas api to draw whatever you want as your _image_</p>
<p>CUSTOM ARGUMENTS</p>
<p>Paint worklet - this is the class</p>
</aside>
</section>
<section class="pink" data-state="pink">
<h2>Jeremy Wagner | @malchata</h2>
<h2><a href="https://paintlets.herokuapp.com/">https://paintlets.herokuapp.com/</a></h2>
<img src="jeremy.jpg" />
<aside class="notes">
<p>If you're interested in more, Jeremy Wagner has a great site showcasing some paint worklets he has put together</p>
</aside>
</section>
<section class="orange" data-state="orange">
<h1 class="orange">Layout API</h1>
<h2>Works much like CSS Paint</h2>
<aside class="notes">
<p>OK these last two I don't have any demos for, they are the least supported and we don't have too much time left, but worth a mention</p>
<p>Layout API, works much like CSS Paint in that you register a layout worklet, and that gives you access to layout features of an element and it's child elements.</p>
</aside>
</section>
<section class="orange">
<pre><code data-trim data-noescape>.slide {
display: layout(coolLayout);
}</code></pre>
<pre><code data-trim data-noescape>CSS.layoutWorklet.addModule('myCoolLayout.js');</code></pre>
<aside class="notes">
<p>You use the layout function, where you reference your registered layout worklet, as a value for the display property</p>
<p>Inside the registerLayout worklet you get access to children, edges, constraints, the Typed OM style map, that's enough to do clever maths of positioning things.</p>
</aside>
</section>
<section class="orange" data-state="orange">
<h1 class="orange">Animation Worklet</h1>
<h2></h2>
<aside class="notes">
<p>There's a lot of worklets all of a sudden isn't there! This one works a little differently than before</p>
<p>We set it up as usual, but we need both keyframes, which is our actual animation, and a timeline.</p>
</aside>
</section>
<section class="purple" data-state="purple">
<h1 class="purple">CSS Houdini</h1>
<h2>🧚🏻♀️</h2>
<aside class="notes">
<p>Well done class! There will be more about layout and animation in version two of this class, which will probably end up being a workshop actually.</p>
</aside>
</section>
<section class="purple" data-state="purple">
<h1 class="purple">Resources</h1>
<h3>Check my twitter | @rumyra</h3>
<aside class="notes">
<p>Well done class! There will be more about layout and animation in version two of this class, which will probably end up being a workshop actually.</p>
<p>Check out my twitter after this, I've got a list of articles & demos which you can refer to.</p>
<p>Follow the following people because they are awesome:</p>
</aside>
</section>
<section class="dark" data-background-color="hsla(315, 3%, 25%, 1)">
<h1>Thank You</h1>
<h2>Ruth John | @rumyra</h2>
<aside class="notes">
<p>And y'all thought this was about audio huh :D</p>
<p>Ask me questions</p>
<p>Thank you very much for inviting me here and making me do a _serious_ talk Bruce, Gabi. I'll see you at the next one.</p>
</aside>
</section>
</div><!--slides-->
</div><!--.reveal-->
<!-- TALK ++++++++++++++++++++++++++++++++ -->
<script type="text/javascript" src="reveal.js-3.8.0/js/reveal.js"></script>
<script type="text/javascript" src="revealInit.js"></script>
<script type="text/javascript" src="index.js"></script>
</body>
</html>