From 976536d15ec7859313dcbce33c97fdfd69c00eb1 Mon Sep 17 00:00:00 2001 From: David Banham Date: Sun, 5 Aug 2012 23:48:55 +1000 Subject: [PATCH 1/9] Added multiplexing server --- README.md | 12 +++- index.html | 20 ++++++- js/reveal.js | 20 ++++--- package.json | 46 ++++++++------ plugin/multiplex/client.js | 12 ++++ plugin/multiplex/index.js | 62 +++++++++++++++++++ plugin/multiplex/master.js | 32 ++++++++++ plugin/multiplex/notes.html | 109 ++++++++++++++++++++++++++++++++++ plugin/speakernotes/client.js | 2 +- 9 files changed, 285 insertions(+), 30 deletions(-) create mode 100644 plugin/multiplex/client.js create mode 100644 plugin/multiplex/index.js create mode 100644 plugin/multiplex/master.js create mode 100644 plugin/multiplex/notes.html diff --git a/README.md b/README.md index 0e6da25c..8c583340 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,16 @@ By default, the slides will be served at [localhost:1947](http://localhost:1947) You can change the appearance of the speaker notes by editing the file at `plugin/speakernotes/notes.html`. +### Multiplexing + +The multiplex plugin allows your audience to view the slides on their own phone, tablet or laptop. As the master navigates the slides, all clients will update in real time. See a demo at [http://revealjs.jit.su/](http://revealjs.jit.su) + +Configuration is via the multiplex object in index.html. To generate unique secret and token values, visit [revealjs.jit.su/token](revealjs.jit.su/token) + +multiplex.secret should only be configured on those pages you wish to be able to control slide navigatoin for all clients. Multi-master configurations work, but if you don't wish your audience to be able to control your slides, set the secret to null. In this master/slave setup, you should create a publicly accessible page with secret set to null, and a protected page containing your secret. + +You are very welcome to use the server running at reveal.jit.su, however availability and stability are not guaranteed. For anything mission critical I recommend you run your own server. It is simple to deploy to nodejitsu or run on your own environment. + ### Known Issues - The notes page is supposed to show the current slide and the next slide, but when it first starts, it always shows the first slide in both positions. @@ -286,4 +296,4 @@ You can change the appearance of the speaker notes by editing the file at `plugi MIT licensed -Copyright (C) 2012 Hakim El Hattab, http://hakim.se \ No newline at end of file +Copyright (C) 2012 Hakim El Hattab, http://hakim.se diff --git a/index.html b/index.html index c6decbfe..95bcd272 100644 --- a/index.html +++ b/index.html @@ -278,6 +278,15 @@ function linkify( selector ) { + + + + + diff --git a/plugin/speakernotes/client.js b/plugin/speakernotes/client.js index 1aba8b8c..9f681737 100644 --- a/plugin/speakernotes/client.js +++ b/plugin/speakernotes/client.js @@ -2,7 +2,7 @@ // don't emit events from inside the previews themselves if ( window.location.search.match( /receiver/gi ) ) { return; } - var socket = io.connect(window.location.origin); + var socket = io.connect('127.0.0.1:1947'); var socketId = Math.random().toString().slice(2); console.log('View slide notes at ' + window.location.origin + '/notes/' + socketId); From ee12450458ded62e176dd8b500574463297c9baa Mon Sep 17 00:00:00 2001 From: David Banham Date: Sun, 5 Aug 2012 23:52:04 +1000 Subject: [PATCH 2/9] Tweaked heading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8c583340..9d2ceaaa 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ By default, the slides will be served at [localhost:1947](http://localhost:1947) You can change the appearance of the speaker notes by editing the file at `plugin/speakernotes/notes.html`. -### Multiplexing +## Multiplexing The multiplex plugin allows your audience to view the slides on their own phone, tablet or laptop. As the master navigates the slides, all clients will update in real time. See a demo at [http://revealjs.jit.su/](http://revealjs.jit.su) From a2e021ccdb9d6acfc9cfa92d334430fbc1d1366a Mon Sep 17 00:00:00 2001 From: David Banham Date: Mon, 6 Aug 2012 11:20:08 +1000 Subject: [PATCH 3/9] Don't suppress the whole event, just add context metadata --- js/reveal.js | 21 ++++++++++----------- plugin/multiplex/client.js | 2 +- plugin/multiplex/master.js | 2 +- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/js/reveal.js b/js/reveal.js index 7d726520..d8209439 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -653,7 +653,7 @@ var Reveal = (function(){ * Updates the visual slides to represent the currently * set indices. */ - function slide( h, v, fireEvent ) { + function slide( h, v, origin ) { // Remember where we were at before previousSlide = currentSlide; @@ -720,14 +720,13 @@ var Reveal = (function(){ // Dispatch an event if the slide changed if( indexh !== indexhBefore || indexv !== indexvBefore ) { - if( fireEvent !== false ) { - dispatchEvent( 'slidechanged', { - 'indexh': indexh, - 'indexv': indexv, - 'previousSlide': previousSlide, - 'currentSlide': currentSlide - } ); - } + dispatchEvent( 'slidechanged', { + 'origin': origin, + 'indexh': indexh, + 'indexv': indexv, + 'previousSlide': previousSlide, + 'currentSlide': currentSlide + } ); } else { // Ensure that the previous slide is never the same as the current @@ -903,8 +902,8 @@ var Reveal = (function(){ * @param {Number} h The horizontal index of the slide to show * @param {Number} v The vertical index of the slide to show */ - function navigateTo( h, v, fireEvent ) { - slide( h, v, fireEvent ); + function navigateTo( h, v, origin ) { + slide( h, v, origin ); } function navigateLeft() { diff --git a/plugin/multiplex/client.js b/plugin/multiplex/client.js index 5e6b5562..6fc0d4db 100644 --- a/plugin/multiplex/client.js +++ b/plugin/multiplex/client.js @@ -7,6 +7,6 @@ if (data.socketId !== socketId) { return; } if( window.location.host === 'localhost:1947' ) return; - Reveal.navigateTo(data.indexh, data.indexv, false); + Reveal.navigateTo(data.indexh, data.indexv, 'remote'); }); }()); diff --git a/plugin/multiplex/master.js b/plugin/multiplex/master.js index cf629d96..3704fa46 100644 --- a/plugin/multiplex/master.js +++ b/plugin/multiplex/master.js @@ -27,6 +27,6 @@ socketId : multiplex.id }; - socket.emit('slidechanged', slideData); + if( event.origin !== 'remote') socket.emit('slidechanged', slideData); } ); }()); From 7cf17ac0633b6082d118f5bad9d6201510c040dc Mon Sep 17 00:00:00 2001 From: David Banham Date: Mon, 6 Aug 2012 14:40:32 +1000 Subject: [PATCH 4/9] Removed unused code --- plugin/multiplex/index.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/plugin/multiplex/index.js b/plugin/multiplex/index.js index 7e3f872a..45c9c749 100644 --- a/plugin/multiplex/index.js +++ b/plugin/multiplex/index.js @@ -1,8 +1,6 @@ var express = require('express'); var fs = require('fs'); var io = require('socket.io'); -var _ = require('underscore'); -var Mustache = require('mustache'); var crypto = require('crypto'); var app = express.createServer(); @@ -49,14 +47,3 @@ var createHash = function(secret) { // Actually listen app.listen(opts.port || null); - -var brown = '\033[33m', - green = '\033[32m', - reset = '\033[0m'; - -var slidesLocation = "http://localhost" + ( opts.port ? ( ':' + opts.port ) : '' ); - -console.log( brown + "reveal.js - Speaker Notes" + reset ); -console.log( "1. Open the slides at " + green + slidesLocation + reset ); -console.log( "2. Click on the link your JS console to go to the notes page" ); -console.log( "3. Advance through your slides and your notes will advance automatically" ); From b27f21e527a9b189ac4bde6e930001754d7a737b Mon Sep 17 00:00:00 2001 From: David Banham Date: Wed, 15 Aug 2012 18:55:22 +1000 Subject: [PATCH 5/9] Not for github --- fixed.html | 455 +++++++++++++++++++++++++++++++++++++++++++++++ fixedmaster.html | 455 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 910 insertions(+) create mode 100644 fixed.html create mode 100644 fixedmaster.html diff --git a/fixed.html b/fixed.html new file mode 100644 index 00000000..8e182df4 --- /dev/null +++ b/fixed.html @@ -0,0 +1,455 @@ + + + + + + + There I Fixed It + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+

There I Fixed It

+

Dumb hacks that end up being great

+ +
+ +
+

Heads Up

+

+ This presentation uses a souped-up version of reveal.js +

+

+ Go here on your laptop, smartphone or tablet: +

+ +

http://www.pinion.gg/sydjs/index.html

+

http://bit.ly/Nlf8Aw

+
+ +
+
+

Who the hell are you?

+ + + +
+
+

What the hell is this?

+ +
+
+ +
+
+ + +
+
+

In the beginning.

+

+ There was SQL. +

+

+ And it was okay. +

+
+
+

And then...

+

There was noSQL!

+

And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy. +

+
+

But then you want to actually use it

+
+
+

+var request = http.request({
+  host: 'couchdb.internet.com',
+  path: '/awesomedb/_all_docs',
+  auth: 'zer0c00l:God'
+});
+request.end();
+
+var newrows = []
+request.on('response', function (response) {
+  response.on('data', function (data) {
+    data.rows.forEach(function(row){
+      row.value.walkThe = "dinosaur";
+      newrows.push(row.value);
+    });
+  });
+});
+request.end();
+
+var request = http.request({
+  host:   'couchdb.internet.com',
+  method: 'post'
+  path:   '/awesomedb/_bulk_docs',
+  auth:   'zer0c00l:God'
+});
+
+request.write(JSON.stringify({docs:newrows}));
+
+request.end()
+
+
+
+ +
+
+

unql-node

+

+ + https://github.com/sgentle/unql-node + +

+

It's like SQL for NoSQL

+ +
+
+

Deletin' stuff

+

+> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
+						
+
+
+

Why don't we take all the data...

+

+> create collection nag_old_users
+> insert into nag_old_users select {username: username, email: email} from user where last_login < (new Date()).getTime()-1000*60*60*24*7
+						
+

And put it over here!

+
+
+

Want to see my awesome LALR recursive descent parser?

+ +
+
+

Nope!

+

+handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
+  query = "update #{db} set _deleted = true"
+  query += " where #{expr}" if expr
+  processExpr query, cb
+						
+
+
+

There I fixed it.

+ +
+
+ +
+
+

noDB

+

So you want to add some persistence to your simple web app.

+
+
+

Okay so just require that each user have a couch installation.

+

Or make redis a dependency. Probably include some build scripts or something to make it easier since it's the only thing in the app that needs to be compiled.

+ +

Maybe it would be easier to build SQLite?

+
+
+

Nope!

+ +
+
+

noDB

+

SQL < noSQL < noDB

+
+
+

Super simple

+

+var users = JSON.parse(fs.readFileSync('data/users.json'))
+
+users.push({name: "newguy"});
+fs.writeFileSync('data/users.json', JSON.stringify(users));
+res.send('success');
+						
+
+
+

Session storage too!

+

+var store = new express.session.MemoryStore;
+store.sessions = JSON.parse(fs.readFileSync('data/sessions.json'));
+
+setInterval(function(){
+  fs.writeFileSync('data/sessions.json', JSON.stringify(store.sessions));
+}, 2000);
+						
+
+
+

It's basically Redis

+ It's not really +
+
+

But it is:

+
    +
  • Deployable
  • +
  • Dependency free
  • +
  • Easily backed up
  • +
  • Debuggable
  • +
+
+
+

Databases: Fixed

+ +
+
+ +
+
+

I would like to make some information available on the internet.

+
+
+

So find a shared hosting provider or something.

+

But they're kind of crappy

+
+
+

So I'll just run my own

+

On nginx or express or something!

+

But load balancing and updates and bugs and oh no.

+
+
+

Oh I know!

+ +
+
+ +
+
+
+ Augh. I wish I could just shove all this right on Akamai +
+
+
+

...

+
+
+

...

+
+
+

...

+
+
+

Why not?

+
+
+

Step 0: Generate static site

+

Use whatever you want. We really like Jade.

+
+
+

+!!! 5
+include includes/head.jade
+body
+  include includes/header.jade
+  // BEGIN Content 
+  .inner-bg
+  #content-wrapper
+    Welcome to zombocom!
+						
+
+
+

make

+

+JADE = $(shell find pages/*.jade)
+HTML = $(JADE:.jade=.html)
+
+all: $(HTML)
+
+%.html: %.jade
+      ./jade/bin/jade < $< --path $< > $@
+
+clean:
+      rm -f $(HTML)
+
+.PHONY: clean
+						
+ +
+ +
+

Rackspace == Akamai

+

It's cheap. 18c per GB

+

You don't have to deal directly with Akamai. Keep your soul!

+

http://www.rackspace.com/cloud/public/files/

+
+ +
+

Getting it there

+

There's a node library for that.

+

https://github.com/nodejitsu/node-cloudfiles

+
+ +
+

There's also some tooling for that.

+

https://github.com/PinionTech/cloud-loader

+

+coffee cloud-loader.coffee -x localDir cloudContainer
+						
+
+ +
+

Deep magic

+

+curl -i -X GET -H "X-Auth-User: pinion" -H "X-Auth-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "https://auth.api.rackspacecloud.com/v1.0"
+
+curl -X POST -H "X-Container-Meta-Web-Index: index.html" -H "X-Auth-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" "https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_ad499859-aaed-43c6-813b-5e1c545f85cf/pinion-www
+						
+
+ +
+

Relax

+

Never ever care about whether your website is up.

+

Go do something useful instead.

+
+

Yeah, it's harder to do pretty URLs.

+
+
+

So fixed

+ +
+
+
+
+

It's not always the right thing to just fix it

+
+
+

But sometimes it is

+ +
+
+ +
+

ALL FIXED

+

BY David Banham and Sam Gentle

+ +
+
+ + + + + +
+ +
+ + + + + + + diff --git a/fixedmaster.html b/fixedmaster.html new file mode 100644 index 00000000..a744a987 --- /dev/null +++ b/fixedmaster.html @@ -0,0 +1,455 @@ + + + + + + + There I Fixed It + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+

There I Fixed It

+

Dumb hacks that end up being great

+ +
+ +
+

Heads Up

+

+ This presentation uses a souped-up version of reveal.js +

+

+ Go here on your laptop, smartphone or tablet: +

+ +

http://www.pinion.gg/sydjs/index.html

+

http://bit.ly/Nlf8Aw

+
+ +
+
+

Who the hell are you?

+ + + +
+
+

What the hell is this?

+ +
+
+ +
+
+ + +
+
+

In the beginning.

+

+ There was SQL. +

+

+ And it was okay. +

+
+
+

And then...

+

There was noSQL!

+

And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy. +

+
+

But then you want to actually use it

+
+
+

+var request = http.request({
+  host: 'couchdb.internet.com',
+  path: '/awesomedb/_all_docs',
+  auth: 'zer0c00l:God'
+});
+request.end();
+
+var newrows = []
+request.on('response', function (response) {
+  response.on('data', function (data) {
+    data.rows.forEach(function(row){
+      row.value.walkThe = "dinosaur";
+      newrows.push(row.value);
+    });
+  });
+});
+request.end();
+
+var request = http.request({
+  host:   'couchdb.internet.com',
+  method: 'post'
+  path:   '/awesomedb/_bulk_docs',
+  auth:   'zer0c00l:God'
+});
+
+request.write(JSON.stringify({docs:newrows}));
+
+request.end()
+
+
+
+ +
+
+

unql-node

+

+ + https://github.com/sgentle/unql-node + +

+

It's like SQL for NoSQL

+ +
+
+

Deletin' stuff

+

+> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
+						
+
+
+

Why don't we take all the data...

+

+> create collection nag_old_users
+> insert into nag_old_users select {username: username, email: email} from user where last_login < (new Date()).getTime()-1000*60*60*24*7
+						
+

And put it over here!

+
+
+

Want to see my awesome LALR recursive descent parser?

+ +
+
+

Nope!

+

+handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
+  query = "update #{db} set _deleted = true"
+  query += " where #{expr}" if expr
+  processExpr query, cb
+						
+
+
+

There I fixed it.

+ +
+
+ +
+
+

noDB

+

So you want to add some persistence to your simple web app.

+
+
+

Okay so just require that each user have a couch installation.

+

Or make redis a dependency. Probably include some build scripts or something to make it easier since it's the only thing in the app that needs to be compiled.

+ +

Maybe it would be easier to build SQLite?

+
+
+

Nope!

+ +
+
+

noDB

+

SQL < noSQL < noDB

+
+
+

Super simple

+

+var users = JSON.parse(fs.readFileSync('data/users.json'))
+
+users.push({name: "newguy"});
+fs.writeFileSync('data/users.json', JSON.stringify(users));
+res.send('success');
+						
+
+
+

Session storage too!

+

+var store = new express.session.MemoryStore;
+store.sessions = JSON.parse(fs.readFileSync('data/sessions.json'));
+
+setInterval(function(){
+  fs.writeFileSync('data/sessions.json', JSON.stringify(store.sessions));
+}, 2000);
+						
+
+
+

It's basically Redis

+ It's not really +
+
+

But it is:

+
    +
  • Deployable
  • +
  • Dependency free
  • +
  • Easily backed up
  • +
  • Debuggable
  • +
+
+
+

Databases: Fixed

+ +
+
+ +
+
+

I would like to make some information available on the internet.

+
+
+

So find a shared hosting provider or something.

+

But they're kind of crappy

+
+
+

So I'll just run my own

+

On nginx or express or something!

+

But load balancing and updates and bugs and oh no.

+
+
+

Oh I know!

+ +
+
+ +
+
+
+ Augh. I wish I could just shove all this right on Akamai +
+
+
+

...

+
+
+

...

+
+
+

...

+
+
+

Why not?

+
+
+

Step 0: Generate static site

+

Use whatever you want. We really like Jade.

+
+
+

+!!! 5
+include includes/head.jade
+body
+  include includes/header.jade
+  // BEGIN Content 
+  .inner-bg
+  #content-wrapper
+    Welcome to zombocom!
+						
+
+
+

make

+

+JADE = $(shell find pages/*.jade)
+HTML = $(JADE:.jade=.html)
+
+all: $(HTML)
+
+%.html: %.jade
+      ./jade/bin/jade < $< --path $< > $@
+
+clean:
+      rm -f $(HTML)
+
+.PHONY: clean
+						
+ +
+ +
+

Rackspace == Akamai

+

It's cheap. 18c per GB

+

You don't have to deal directly with Akamai. Keep your soul!

+

http://www.rackspace.com/cloud/public/files/

+
+ +
+

Getting it there

+

There's a node library for that.

+

https://github.com/nodejitsu/node-cloudfiles

+
+ +
+

There's also some tooling for that.

+

https://github.com/PinionTech/cloud-loader

+

+coffee cloud-loader.coffee -x localDir cloudContainer
+						
+
+ +
+

Deep magic

+

+curl -i -X GET -H "X-Auth-User: pinion" -H "X-Auth-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "https://auth.api.rackspacecloud.com/v1.0"
+
+curl -X POST -H "X-Container-Meta-Web-Index: index.html" -H "X-Auth-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" "https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_ad499859-aaed-43c6-813b-5e1c545f85cf/pinion-www
+						
+
+ +
+

Relax

+

Never ever care about whether your website is up.

+

Go do something useful instead.

+
+

Yeah, it's harder to do pretty URLs.

+
+
+

So fixed

+ +
+
+
+
+

It's not always the right thing to just fix it

+
+
+

But sometimes it is

+ +
+
+ +
+

ALL FIXED

+

BY David Banham and Sam Gentle

+ +
+
+ + + + + +
+ +
+ + + + + + + From 7bae52248832fe8bccb95bb4cd201898514aa56a Mon Sep 17 00:00:00 2001 From: David Banham Date: Wed, 15 Aug 2012 18:57:48 +1000 Subject: [PATCH 6/9] Not got github --- plugin/multiplex/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugin/multiplex/index.js b/plugin/multiplex/index.js index 45c9c749..4665639e 100644 --- a/plugin/multiplex/index.js +++ b/plugin/multiplex/index.js @@ -32,6 +32,12 @@ app.configure(function() { app.get("/", function(req, res) { fs.createReadStream(opts.baseDir + '/index.html').pipe(res); }); +app.get("/fixed.html", function(req, res) { + fs.createReadStream(opts.baseDir + '/fixed.html').pipe(res); +}); +app.get("/fixedmaster.html", function(req, res) { + fs.createReadStream(opts.baseDir + '/fixedmaster.html').pipe(res); +}); app.get("/token", function(req,res) { var ts = new Date().getTime(); From 26d5febd7f24223900aa50d24d35e610c7c8a334 Mon Sep 17 00:00:00 2001 From: David Banham Date: Wed, 15 Aug 2012 19:01:14 +1000 Subject: [PATCH 7/9] Multiplex fixes --- fixed.html | 4 +--- fixedmaster.html | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/fixed.html b/fixed.html index 8e182df4..da8dc16b 100644 --- a/fixed.html +++ b/fixed.html @@ -51,9 +51,7 @@

Go here on your laptop, smartphone or tablet:

- -

http://www.pinion.gg/sydjs/index.html

-

http://bit.ly/Nlf8Aw

+

http://revealjs.jit.su/fixed.html

diff --git a/fixedmaster.html b/fixedmaster.html index a744a987..1d2fce10 100644 --- a/fixedmaster.html +++ b/fixedmaster.html @@ -51,9 +51,7 @@

Go here on your laptop, smartphone or tablet:

- -

http://www.pinion.gg/sydjs/index.html

-

http://bit.ly/Nlf8Aw

+

http://revealjs.jit.su/fixed.html

From 580a72c4449c57cb743e09f44eeeb374cd00f172 Mon Sep 17 00:00:00 2001 From: David Banham Date: Fri, 8 Mar 2013 11:51:58 +1100 Subject: [PATCH 8/9] Bring multiplex up to date --- fixed.html | 453 ------------------------------------- fixedmaster.html | 453 ------------------------------------- index.html | 12 +- js/reveal.js | 9 +- js/reveal.min.js | 4 +- package.json | 12 +- plugin/multiplex/client.js | 3 +- plugin/multiplex/index.js | 7 - plugin/multiplex/master.js | 3 +- 9 files changed, 31 insertions(+), 925 deletions(-) delete mode 100644 fixed.html delete mode 100644 fixedmaster.html diff --git a/fixed.html b/fixed.html deleted file mode 100644 index da8dc16b..00000000 --- a/fixed.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - There I Fixed It - - - - - - - - - - - - - - - - - - - - -
- - -
- - -
-
-

There I Fixed It

-

Dumb hacks that end up being great

- -
- -
-

Heads Up

-

- This presentation uses a souped-up version of reveal.js -

-

- Go here on your laptop, smartphone or tablet: -

-

http://revealjs.jit.su/fixed.html

-
- -
-
-

Who the hell are you?

- - - -
-
-

What the hell is this?

- -
-
- -
-
- - -
-
-

In the beginning.

-

- There was SQL. -

-

- And it was okay. -

-
-
-

And then...

-

There was noSQL!

-

And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy. -

-
-

But then you want to actually use it

-
-
-

-var request = http.request({
-  host: 'couchdb.internet.com',
-  path: '/awesomedb/_all_docs',
-  auth: 'zer0c00l:God'
-});
-request.end();
-
-var newrows = []
-request.on('response', function (response) {
-  response.on('data', function (data) {
-    data.rows.forEach(function(row){
-      row.value.walkThe = "dinosaur";
-      newrows.push(row.value);
-    });
-  });
-});
-request.end();
-
-var request = http.request({
-  host:   'couchdb.internet.com',
-  method: 'post'
-  path:   '/awesomedb/_bulk_docs',
-  auth:   'zer0c00l:God'
-});
-
-request.write(JSON.stringify({docs:newrows}));
-
-request.end()
-
-
-
- -
-
-

unql-node

-

- - https://github.com/sgentle/unql-node - -

-

It's like SQL for NoSQL

- -
-
-

Deletin' stuff

-

-> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
-						
-
-
-

Why don't we take all the data...

-

-> create collection nag_old_users
-> insert into nag_old_users select {username: username, email: email} from user where last_login < (new Date()).getTime()-1000*60*60*24*7
-						
-

And put it over here!

-
-
-

Want to see my awesome LALR recursive descent parser?

- -
-
-

Nope!

-

-handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
-  query = "update #{db} set _deleted = true"
-  query += " where #{expr}" if expr
-  processExpr query, cb
-						
-
-
-

There I fixed it.

- -
-
- -
-
-

noDB

-

So you want to add some persistence to your simple web app.

-
-
-

Okay so just require that each user have a couch installation.

-

Or make redis a dependency. Probably include some build scripts or something to make it easier since it's the only thing in the app that needs to be compiled.

- -

Maybe it would be easier to build SQLite?

-
-
-

Nope!

- -
-
-

noDB

-

SQL < noSQL < noDB

-
-
-

Super simple

-

-var users = JSON.parse(fs.readFileSync('data/users.json'))
-
-users.push({name: "newguy"});
-fs.writeFileSync('data/users.json', JSON.stringify(users));
-res.send('success');
-						
-
-
-

Session storage too!

-

-var store = new express.session.MemoryStore;
-store.sessions = JSON.parse(fs.readFileSync('data/sessions.json'));
-
-setInterval(function(){
-  fs.writeFileSync('data/sessions.json', JSON.stringify(store.sessions));
-}, 2000);
-						
-
-
-

It's basically Redis

- It's not really -
-
-

But it is:

-
    -
  • Deployable
  • -
  • Dependency free
  • -
  • Easily backed up
  • -
  • Debuggable
  • -
-
-
-

Databases: Fixed

- -
-
- -
-
-

I would like to make some information available on the internet.

-
-
-

So find a shared hosting provider or something.

-

But they're kind of crappy

-
-
-

So I'll just run my own

-

On nginx or express or something!

-

But load balancing and updates and bugs and oh no.

-
-
-

Oh I know!

- -
-
- -
-
-
- Augh. I wish I could just shove all this right on Akamai -
-
-
-

...

-
-
-

...

-
-
-

...

-
-
-

Why not?

-
-
-

Step 0: Generate static site

-

Use whatever you want. We really like Jade.

-
-
-

-!!! 5
-include includes/head.jade
-body
-  include includes/header.jade
-  // BEGIN Content 
-  .inner-bg
-  #content-wrapper
-    Welcome to zombocom!
-						
-
-
-

make

-

-JADE = $(shell find pages/*.jade)
-HTML = $(JADE:.jade=.html)
-
-all: $(HTML)
-
-%.html: %.jade
-      ./jade/bin/jade < $< --path $< > $@
-
-clean:
-      rm -f $(HTML)
-
-.PHONY: clean
-						
- -
- -
-

Rackspace == Akamai

-

It's cheap. 18c per GB

-

You don't have to deal directly with Akamai. Keep your soul!

-

http://www.rackspace.com/cloud/public/files/

-
- -
-

Getting it there

-

There's a node library for that.

-

https://github.com/nodejitsu/node-cloudfiles

-
- -
-

There's also some tooling for that.

-

https://github.com/PinionTech/cloud-loader

-

-coffee cloud-loader.coffee -x localDir cloudContainer
-						
-
- -
-

Deep magic

-

-curl -i -X GET -H "X-Auth-User: pinion" -H "X-Auth-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "https://auth.api.rackspacecloud.com/v1.0"
-
-curl -X POST -H "X-Container-Meta-Web-Index: index.html" -H "X-Auth-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" "https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_ad499859-aaed-43c6-813b-5e1c545f85cf/pinion-www
-						
-
- -
-

Relax

-

Never ever care about whether your website is up.

-

Go do something useful instead.

-
-

Yeah, it's harder to do pretty URLs.

-
-
-

So fixed

- -
-
-
-
-

It's not always the right thing to just fix it

-
-
-

But sometimes it is

- -
-
- -
-

ALL FIXED

-

BY David Banham and Sam Gentle

- -
-
- - - - - -
- -
- - - - - - - diff --git a/fixedmaster.html b/fixedmaster.html deleted file mode 100644 index 1d2fce10..00000000 --- a/fixedmaster.html +++ /dev/null @@ -1,453 +0,0 @@ - - - - - - - There I Fixed It - - - - - - - - - - - - - - - - - - - - -
- - -
- - -
-
-

There I Fixed It

-

Dumb hacks that end up being great

- -
- -
-

Heads Up

-

- This presentation uses a souped-up version of reveal.js -

-

- Go here on your laptop, smartphone or tablet: -

-

http://revealjs.jit.su/fixed.html

-
- -
-
-

Who the hell are you?

- - - -
-
-

What the hell is this?

- -
-
- -
-
- - -
-
-

In the beginning.

-

- There was SQL. -

-

- And it was okay. -

-
-
-

And then...

-

There was noSQL!

-

And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy. -

-
-

But then you want to actually use it

-
-
-

-var request = http.request({
-  host: 'couchdb.internet.com',
-  path: '/awesomedb/_all_docs',
-  auth: 'zer0c00l:God'
-});
-request.end();
-
-var newrows = []
-request.on('response', function (response) {
-  response.on('data', function (data) {
-    data.rows.forEach(function(row){
-      row.value.walkThe = "dinosaur";
-      newrows.push(row.value);
-    });
-  });
-});
-request.end();
-
-var request = http.request({
-  host:   'couchdb.internet.com',
-  method: 'post'
-  path:   '/awesomedb/_bulk_docs',
-  auth:   'zer0c00l:God'
-});
-
-request.write(JSON.stringify({docs:newrows}));
-
-request.end()
-
-
-
- -
-
-

unql-node

-

- - https://github.com/sgentle/unql-node - -

-

It's like SQL for NoSQL

- -
-
-

Deletin' stuff

-

-> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
-						
-
-
-

Why don't we take all the data...

-

-> create collection nag_old_users
-> insert into nag_old_users select {username: username, email: email} from user where last_login < (new Date()).getTime()-1000*60*60*24*7
-						
-

And put it over here!

-
-
-

Want to see my awesome LALR recursive descent parser?

- -
-
-

Nope!

-

-handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
-  query = "update #{db} set _deleted = true"
-  query += " where #{expr}" if expr
-  processExpr query, cb
-						
-
-
-

There I fixed it.

- -
-
- -
-
-

noDB

-

So you want to add some persistence to your simple web app.

-
-
-

Okay so just require that each user have a couch installation.

-

Or make redis a dependency. Probably include some build scripts or something to make it easier since it's the only thing in the app that needs to be compiled.

- -

Maybe it would be easier to build SQLite?

-
-
-

Nope!

- -
-
-

noDB

-

SQL < noSQL < noDB

-
-
-

Super simple

-

-var users = JSON.parse(fs.readFileSync('data/users.json'))
-
-users.push({name: "newguy"});
-fs.writeFileSync('data/users.json', JSON.stringify(users));
-res.send('success');
-						
-
-
-

Session storage too!

-

-var store = new express.session.MemoryStore;
-store.sessions = JSON.parse(fs.readFileSync('data/sessions.json'));
-
-setInterval(function(){
-  fs.writeFileSync('data/sessions.json', JSON.stringify(store.sessions));
-}, 2000);
-						
-
-
-

It's basically Redis

- It's not really -
-
-

But it is:

-
    -
  • Deployable
  • -
  • Dependency free
  • -
  • Easily backed up
  • -
  • Debuggable
  • -
-
-
-

Databases: Fixed

- -
-
- -
-
-

I would like to make some information available on the internet.

-
-
-

So find a shared hosting provider or something.

-

But they're kind of crappy

-
-
-

So I'll just run my own

-

On nginx or express or something!

-

But load balancing and updates and bugs and oh no.

-
-
-

Oh I know!

- -
-
- -
-
-
- Augh. I wish I could just shove all this right on Akamai -
-
-
-

...

-
-
-

...

-
-
-

...

-
-
-

Why not?

-
-
-

Step 0: Generate static site

-

Use whatever you want. We really like Jade.

-
-
-

-!!! 5
-include includes/head.jade
-body
-  include includes/header.jade
-  // BEGIN Content 
-  .inner-bg
-  #content-wrapper
-    Welcome to zombocom!
-						
-
-
-

make

-

-JADE = $(shell find pages/*.jade)
-HTML = $(JADE:.jade=.html)
-
-all: $(HTML)
-
-%.html: %.jade
-      ./jade/bin/jade < $< --path $< > $@
-
-clean:
-      rm -f $(HTML)
-
-.PHONY: clean
-						
- -
- -
-

Rackspace == Akamai

-

It's cheap. 18c per GB

-

You don't have to deal directly with Akamai. Keep your soul!

-

http://www.rackspace.com/cloud/public/files/

-
- -
-

Getting it there

-

There's a node library for that.

-

https://github.com/nodejitsu/node-cloudfiles

-
- -
-

There's also some tooling for that.

-

https://github.com/PinionTech/cloud-loader

-

-coffee cloud-loader.coffee -x localDir cloudContainer
-						
-
- -
-

Deep magic

-

-curl -i -X GET -H "X-Auth-User: pinion" -H "X-Auth-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "https://auth.api.rackspacecloud.com/v1.0"
-
-curl -X POST -H "X-Container-Meta-Web-Index: index.html" -H "X-Auth-Token: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" "https://storage101.dfw1.clouddrive.com/v1/MossoCloudFS_ad499859-aaed-43c6-813b-5e1c545f85cf/pinion-www
-						
-
- -
-

Relax

-

Never ever care about whether your website is up.

-

Go do something useful instead.

-
-

Yeah, it's harder to do pretty URLs.

-
-
-

So fixed

- -
-
-
-
-

It's not always the right thing to just fix it

-
-
-

But sometimes it is

- -
-
- -
-

ALL FIXED

-

BY David Banham and Sam Gentle

- -
-
- - - - - -
- -
- - - - - - - diff --git a/index.html b/index.html index bc2f3601..18c80a05 100644 --- a/index.html +++ b/index.html @@ -358,6 +358,13 @@ function linkify( selector ) { theme: Reveal.getQueryHash().theme, // available themes are in /css/theme transition: Reveal.getQueryHash().transition || 'default', // default/cube/page/concave/zoom/linear/fade/none + globals: { + //multiplex: { + // id: '206589480dc41733' + // , secret: '13627006143682682664' + // , url: 'revealjs.jit.su:80' + //} + }, // Optional libraries used to extend on reveal.js dependencies: [ @@ -366,8 +373,11 @@ function linkify( selector ) { { src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, { src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }, { src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } }, + // { src: 'plugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }, + // { src: 'socket.io/socket.io.js', async: true, condition: function() { return !!document.body.classList; } }, + // { src: 'plugin/multiplex/client.js', async: true, condition: function() { return !!document.body.classList; } }, + // { src: 'plugin/multiplex/master.js', async: true, condition: function() { return !!document.body.classList; } }, { src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } } - // { src: 'plugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } } ] }); diff --git a/js/reveal.js b/js/reveal.js index 2fa74df0..72f68cb0 100644 --- a/js/reveal.js +++ b/js/reveal.js @@ -160,6 +160,9 @@ var Reveal = (function(){ // Copy options over to our config object extend( config, options ); + + // Push up globals + window.globals = config.globals // Hide the address bar in mobile browsers hideAddressBar(); @@ -1002,8 +1005,9 @@ var Reveal = (function(){ * @param {int} v Vertical index of the target slide * @param {int} f Optional index of a fragment within the * target slide to activate + * @param {int} o Optional origin for use in multimaster environments */ - function slide( h, v, f ) { + function slide( h, v, f, o ) { // Remember where we were at before previousSlide = currentSlide; @@ -1098,7 +1102,8 @@ var Reveal = (function(){ 'indexh': indexh, 'indexv': indexv, 'previousSlide': previousSlide, - 'currentSlide': currentSlide + 'currentSlide': currentSlide, + 'origin': o } ); } else { diff --git a/js/reveal.min.js b/js/reveal.min.js index 98019d69..15c758e0 100644 --- a/js/reveal.min.js +++ b/js/reveal.min.js @@ -1,8 +1,8 @@ /*! - * reveal.js 2.3.0 (2013-02-28, 17:03) + * reveal.js 2.3.0 (2013-03-08, 12:41) * http://lab.hakim.se/reveal-js * MIT licensed * * Copyright (C) 2013 Hakim El Hattab, http://hakim.se */ -var Reveal=function(){"use strict";function e(e){return bt||wt?(window.addEventListener("load",h,!1),c(ft,e),n(),r(),void 0):(document.body.setAttribute("class","no-transforms"),void 0)}function t(){if(Lt.theme=document.querySelector("#theme"),Lt.wrapper=document.querySelector(".reveal"),Lt.slides=document.querySelector(".reveal .slides"),!Lt.wrapper.querySelector(".progress")&&ft.progress){var e=document.createElement("div");e.classList.add("progress"),e.innerHTML="",Lt.wrapper.appendChild(e)}if(!Lt.wrapper.querySelector(".controls")&&ft.controls){var t=document.createElement("aside");t.classList.add("controls"),t.innerHTML='',Lt.wrapper.appendChild(t)}if(!Lt.wrapper.querySelector(".state-background")){var n=document.createElement("div");n.classList.add("state-background"),Lt.wrapper.appendChild(n)}if(!Lt.wrapper.querySelector(".pause-overlay")){var r=document.createElement("div");r.classList.add("pause-overlay"),Lt.wrapper.appendChild(r)}Lt.progress=document.querySelector(".reveal .progress"),Lt.progressbar=document.querySelector(".reveal .progress span"),ft.controls&&(Lt.controls=document.querySelector(".reveal .controls"),Lt.controlsLeft=l(document.querySelectorAll(".navigate-left")),Lt.controlsRight=l(document.querySelectorAll(".navigate-right")),Lt.controlsUp=l(document.querySelectorAll(".navigate-up")),Lt.controlsDown=l(document.querySelectorAll(".navigate-down")),Lt.controlsPrev=l(document.querySelectorAll(".navigate-prev")),Lt.controlsNext=l(document.querySelectorAll(".navigate-next")))}function n(){/iphone|ipod|android/gi.test(navigator.userAgent)&&!/crios/gi.test(navigator.userAgent)&&(window.addEventListener("load",u,!1),window.addEventListener("orientationchange",u,!1))}function r(){function e(){n.length&&head.js.apply(null,n),o()}for(var t=[],n=[],r=0,s=ft.dependencies.length;s>r;r++){var a=ft.dependencies[r];(!a.condition||a.condition())&&(a.async?n.push(a.src):t.push(a.src),"function"==typeof a.callback&&head.ready(a.src.match(/([\w\d_\-]*)\.?js$|[^\\\/]*$/i)[0],a.callback))}t.length?(head.ready(e),head.js.apply(null,t)):e()}function o(){t(),a(),s(),P(),R(),setTimeout(function(){v("ready",{indexh:pt,indexv:ht,currentSlide:ct})},1)}function s(e){if(Lt.wrapper.classList.remove(ft.transition),"object"==typeof e&&c(ft,e),wt===!1&&(ft.transition="linear"),Lt.wrapper.classList.add(ft.transition),Lt.controls&&(Lt.controls.style.display=ft.controls&&Lt.controls?"block":"none"),Lt.progress&&(Lt.progress.style.display=ft.progress&&Lt.progress?"block":"none"),ft.rtl?Lt.wrapper.classList.add("rtl"):Lt.wrapper.classList.remove("rtl"),ft.center?Lt.wrapper.classList.add("center"):Lt.wrapper.classList.remove("center"),ft.mouseWheel?(document.addEventListener("DOMMouseScroll",V,!1),document.addEventListener("mousewheel",V,!1)):(document.removeEventListener("DOMMouseScroll",V,!1),document.removeEventListener("mousewheel",V,!1)),ft.rollingLinks?f():m(),ft.theme&&Lt.theme){var t=Lt.theme.getAttribute("href"),n=/[^\/]*?(?=\.css)/,r=t.match(n)[0];ft.theme!==r&&(t=t.replace(n,ft.theme),Lt.theme.setAttribute("href",t))}h()}function a(){if(xt=!0,window.addEventListener("hashchange",ot,!1),window.addEventListener("resize",st,!1),ft.touch&&(document.addEventListener("touchstart",Z,!1),document.addEventListener("touchmove",_,!1),document.addEventListener("touchend",Q,!1)),ft.keyboard&&document.addEventListener("keydown",$,!1),ft.progress&&Lt.progress&&Lt.progress.addEventListener("click",B,!1),ft.controls&&Lt.controls){var e="ontouchstart"in window&&null!=window.ontouchstart?"touchstart":"click";Lt.controlsLeft.forEach(function(t){t.addEventListener(e,G,!1)}),Lt.controlsRight.forEach(function(t){t.addEventListener(e,J,!1)}),Lt.controlsUp.forEach(function(t){t.addEventListener(e,et,!1)}),Lt.controlsDown.forEach(function(t){t.addEventListener(e,tt,!1)}),Lt.controlsPrev.forEach(function(t){t.addEventListener(e,nt,!1)}),Lt.controlsNext.forEach(function(t){t.addEventListener(e,rt,!1)})}}function i(){if(xt=!1,document.removeEventListener("keydown",$,!1),window.removeEventListener("hashchange",ot,!1),window.removeEventListener("resize",st,!1),ft.touch&&(document.removeEventListener("touchstart",Z,!1),document.removeEventListener("touchmove",_,!1),document.removeEventListener("touchend",Q,!1)),ft.progress&&Lt.progress&&Lt.progress.removeEventListener("click",B,!1),ft.controls&&Lt.controls){var e="ontouchstart"in window&&null!=window.ontouchstart?"touchstart":"click";Lt.controlsLeft.forEach(function(t){t.removeEventListener(e,G,!1)}),Lt.controlsRight.forEach(function(t){t.removeEventListener(e,J,!1)}),Lt.controlsUp.forEach(function(t){t.removeEventListener(e,et,!1)}),Lt.controlsDown.forEach(function(t){t.removeEventListener(e,tt,!1)}),Lt.controlsPrev.forEach(function(t){t.removeEventListener(e,nt,!1)}),Lt.controlsNext.forEach(function(t){t.removeEventListener(e,rt,!1)})}}function c(e,t){for(var n in t)e[n]=t[n]}function l(e){return Array.prototype.slice.call(e)}function d(e,t){var n=e.x-t.x,r=e.y-t.y;return Math.sqrt(n*n+r*r)}function u(){0===window.orientation?(document.documentElement.style.overflow="scroll",document.body.style.height="120%"):(document.documentElement.style.overflow="",document.body.style.height="100%"),setTimeout(function(){window.scrollTo(0,1)},10)}function v(e,t){var n=document.createEvent("HTMLEvents",1,2);n.initEvent(e,!0,!0),c(n,t),Lt.wrapper.dispatchEvent(n)}function f(){if(wt&&!("msPerspective"in document.body.style))for(var e=document.querySelectorAll(lt+" a:not(.image)"),t=0,n=e.length;n>t;t++){var r=e[t];if(!(!r.textContent||r.querySelector("*")||r.className&&r.classList.contains(r,"roll"))){var o=document.createElement("span");o.setAttribute("data-title",r.text),o.innerHTML=r.innerHTML,r.classList.add("roll"),r.innerHTML="",r.appendChild(o)}}}function m(){for(var e=document.querySelectorAll(lt+" a.roll"),t=0,n=e.length;n>t;t++){var r=e[t],o=r.querySelector("span");o&&(r.classList.remove("roll"),r.innerHTML=o.innerHTML)}}function p(e){var t=l(e);return t.forEach(function(e,t){e.hasAttribute("data-fragment-index")||e.setAttribute("data-fragment-index",t)}),t.sort(function(e,t){return e.getAttribute("data-fragment-index")-t.getAttribute("data-fragment-index")}),t}function h(){if(Lt.wrapper){var e=Lt.wrapper.offsetWidth,t=Lt.wrapper.offsetHeight;e-=t*ft.margin,t-=t*ft.margin;var n=ft.width,r=ft.height;if("string"==typeof n&&/%$/.test(n)&&(n=parseInt(n,10)/100*e),"string"==typeof r&&/%$/.test(r)&&(r=parseInt(r,10)/100*t),Lt.slides.style.width=n+"px",Lt.slides.style.height=r+"px",yt=Math.min(e/n,t/r),yt=Math.max(yt,ft.minScale),yt=Math.min(yt,ft.maxScale),void 0===Lt.slides.style.zoom||navigator.userAgent.match(/(iphone|ipod|ipad|android)/gi)){var o="translate(-50%, -50%) scale("+yt+") translate(50%, 50%)";Lt.slides.style.WebkitTransform=o,Lt.slides.style.MozTransform=o,Lt.slides.style.msTransform=o,Lt.slides.style.OTransform=o,Lt.slides.style.transform=o}else Lt.slides.style.zoom=yt;for(var s=l(document.querySelectorAll(lt)),a=0,i=s.length;i>a;a++){var c=s[a];"none"!==c.style.display&&(c.style.top=ft.center?c.classList.contains("stack")?0:Math.max(-(c.offsetHeight/2)-20,-r/2)+"px":"")}}}function g(e,t){e&&e.setAttribute("data-previous-indexv",t||0)}function y(e){return e&&e.classList.contains("stack")?parseInt(e.getAttribute("data-previous-indexv")||0,10):0}function L(){if(ft.overview){W();var e=Lt.wrapper.classList.contains("overview");Lt.wrapper.classList.add("overview"),Lt.wrapper.classList.remove("exit-overview"),clearTimeout(At),clearTimeout(kt),At=setTimeout(function(){for(var t=document.querySelectorAll(dt),n=0,r=t.length;r>n;n++){var o=t[n],s="translateZ(-2500px) translate("+105*(n-pt)+"%, 0%)";if(o.setAttribute("data-index-h",n),o.style.display="block",o.style.WebkitTransform=s,o.style.MozTransform=s,o.style.msTransform=s,o.style.OTransform=s,o.style.transform=s,o.classList.contains("stack"))for(var a=o.querySelectorAll("section"),i=0,c=a.length;c>i;i++){var l=n===pt?ht:y(o),d=a[i],u="translate(0%, "+105*(i-l)+"%)";d.setAttribute("data-index-h",n),d.setAttribute("data-index-v",i),d.style.display="block",d.style.WebkitTransform=u,d.style.MozTransform=u,d.style.msTransform=u,d.style.OTransform=u,d.style.transform=u,d.addEventListener("click",at,!0)}else o.addEventListener("click",at,!0)}h(),e||v("overviewshown",{indexh:pt,indexv:ht,currentSlide:ct})},10)}}function w(){if(ft.overview){clearTimeout(At),clearTimeout(kt),Lt.wrapper.classList.remove("overview"),Lt.wrapper.classList.add("exit-overview"),kt=setTimeout(function(){Lt.wrapper.classList.remove("exit-overview")},10);for(var e=l(document.querySelectorAll(lt)),t=0,n=e.length;n>t;t++){var r=e[t];r.style.display="",r.style.WebkitTransform="",r.style.MozTransform="",r.style.msTransform="",r.style.OTransform="",r.style.transform="",r.removeEventListener("click",at,!0)}T(pt,ht),R(),v("overviewhidden",{indexh:pt,indexv:ht,currentSlide:ct})}}function b(e){"boolean"==typeof e?e?L():w():E()?w():L()}function E(){return Lt.wrapper.classList.contains("overview")}function S(){var e=document.body,t=e.requestFullScreen||e.webkitRequestFullScreen||e.mozRequestFullScreen||e.msRequestFullScreen;t&&t.apply(e)}function q(){var e=Lt.wrapper.classList.contains("paused");W(),Lt.wrapper.classList.add("paused"),e===!1&&v("paused")}function A(){var e=Lt.wrapper.classList.contains("paused");R(),Lt.wrapper.classList.remove("paused"),e&&v("resumed")}function k(){x()?A():q()}function x(){return Lt.wrapper.classList.contains("paused")}function T(e,t,n){it=ct;var r=document.querySelectorAll(dt);void 0===t&&(t=y(r[e])),it&&it.parentNode&&it.parentNode.classList.contains("stack")&&g(it.parentNode,ht);var o=gt.concat();gt.length=0;var s=pt,a=ht;pt=M(dt,void 0===e?pt:e),ht=M(ut,void 0===t?ht:t),h();e:for(var i=0,c=gt.length;c>i;i++){for(var d=0;o.length>d;d++)if(o[d]===gt[i]){o.splice(d,1);continue e}document.documentElement.classList.add(gt[i]),v(gt[i])}for(;o.length;)document.documentElement.classList.remove(o.pop());E()&&L(),O(1500);var u=r[pt],f=u.querySelectorAll("section");if(ct=f[ht]||u,n!==void 0){var m=p(ct.querySelectorAll(".fragment"));l(m).forEach(function(e,t){n>t?e.classList.add("visible"):e.classList.remove("visible")})}pt!==s||ht!==a?v("slidechanged",{indexh:pt,indexv:ht,previousSlide:it,currentSlide:ct}):it=null,it&&(it.classList.remove("present"),document.querySelector(vt).classList.contains("present")&&setTimeout(function(){var e,t=l(document.querySelectorAll(dt+".stack"));for(e in t)t[e]&&g(t[e],0)},0)),N(),D()}function M(e,t){var n=l(document.querySelectorAll(e)),r=n.length;if(r){ft.loop&&(t%=r,0>t&&(t=r+t)),t=Math.max(Math.min(t,r-1),0);for(var o=0;r>o;o++){var s=n[o];if(E()===!1){var a=Math.abs((t-o)%(r-3))||0;s.style.display=a>3?"none":"block"}n[o].classList.remove("past"),n[o].classList.remove("present"),n[o].classList.remove("future"),t>o?n[o].classList.add("past"):o>t&&n[o].classList.add("future"),s.querySelector("section")&&n[o].classList.add("stack")}n[t].classList.add("present");var i=n[t].getAttribute("data-state");i&&(gt=gt.concat(i.split(" ")));var c=n[t].getAttribute("data-autoslide");mt=c?parseInt(c,10):ft.autoSlide}else t=0;return t}function D(){if(ft.progress&&Lt.progress){var e=l(document.querySelectorAll(dt)),t=document.querySelectorAll(lt+":not(.stack)").length,n=0;e:for(var r=0;e.length>r;r++){for(var o=e[r],s=l(o.querySelectorAll("section")),a=0;s.length>a;a++){if(s[a].classList.contains("present"))break e;n++}if(o.classList.contains("present"))break;o.classList.contains("stack")===!1&&n++}Lt.progressbar.style.width=n/(t-1)*window.innerWidth+"px"}}function N(){if(ft.controls&&Lt.controls){var e=C();Lt.controlsLeft.concat(Lt.controlsRight).concat(Lt.controlsUp).concat(Lt.controlsDown).concat(Lt.controlsPrev).concat(Lt.controlsNext).forEach(function(e){e.classList.remove("enabled")}),e.left&&Lt.controlsLeft.forEach(function(e){e.classList.add("enabled")}),e.right&&Lt.controlsRight.forEach(function(e){e.classList.add("enabled")}),e.up&&Lt.controlsUp.forEach(function(e){e.classList.add("enabled")}),e.down&&Lt.controlsDown.forEach(function(e){e.classList.add("enabled")}),(e.left||e.up)&&Lt.controlsPrev.forEach(function(e){e.classList.add("enabled")}),(e.right||e.down)&&Lt.controlsNext.forEach(function(e){e.classList.add("enabled")})}}function C(){var e=document.querySelectorAll(dt),t=document.querySelectorAll(ut);return{left:pt>0,right:e.length-1>pt,up:ht>0,down:t.length-1>ht}}function P(){var e=window.location.hash,t=e.slice(2).split("/"),n=e.replace(/#|\//gi,"");if(isNaN(parseInt(t[0],10))&&n.length){var r=document.querySelector("#"+n);if(r){var o=Reveal.getIndices(r);T(o.h,o.v)}else T(pt,ht)}else{var s=parseInt(t[0],10)||0,a=parseInt(t[1],10)||0;T(s,a)}}function O(e){if(ft.history)if(clearTimeout(qt),"number"==typeof e)qt=setTimeout(O,e);else{var t="/";ct&&"string"==typeof ct.getAttribute("id")?t="/"+ct.getAttribute("id"):((pt>0||ht>0)&&(t+=pt),ht>0&&(t+="/"+ht)),window.location.hash=t}}function z(e){var t=pt,n=ht;if(e){var r=!!e.parentNode.nodeName.match(/section/gi),o=r?e.parentNode:e,s=l(document.querySelectorAll(dt));t=Math.max(s.indexOf(o),0),r&&(n=Math.max(l(e.parentNode.querySelectorAll("section")).indexOf(e),0))}return{h:t,v:n}}function H(){if(document.querySelector(ut+".present")){var e=p(document.querySelectorAll(ut+".present .fragment:not(.visible)"));if(e.length)return e[0].classList.add("visible"),v("fragmentshown",{fragment:e[0]}),!0}else{var t=p(document.querySelectorAll(dt+".present .fragment:not(.visible)"));if(t.length)return t[0].classList.add("visible"),v("fragmentshown",{fragment:t[0]}),!0}return!1}function I(){if(document.querySelector(ut+".present")){var e=p(document.querySelectorAll(ut+".present .fragment.visible"));if(e.length)return e[e.length-1].classList.remove("visible"),v("fragmenthidden",{fragment:e[e.length-1]}),!0}else{var t=p(document.querySelectorAll(dt+".present .fragment.visible"));if(t.length)return t[t.length-1].classList.remove("visible"),v("fragmenthidden",{fragment:t[t.length-1]}),!0}return!1}function R(){clearTimeout(St),!mt||x()||E()||(St=setTimeout(K,mt))}function W(){clearTimeout(St)}function X(){(C().left&&E()||I()===!1)&&T(pt-1)}function Y(){(C().right&&E()||H()===!1)&&T(pt+1)}function F(){(C().up&&E()||I()===!1)&&T(pt,ht-1)}function U(){(C().down&&E()||H()===!1)&&T(pt,ht+1)}function j(){if(I()===!1)if(C().up)F();else{var e=document.querySelector(dt+".past:nth-child("+pt+")");e&&(ht=e.querySelectorAll("section").length+1||void 0,pt--,T())}}function K(){H()===!1&&(C().down?U():Y()),R()}function $(e){document.activeElement;var t=!(!document.activeElement||!document.activeElement.type&&!document.activeElement.href&&"inherit"===document.activeElement.contentEditable);if(!(t||e.shiftKey||e.altKey||e.ctrlKey||e.metaKey)){var n=!0;if(x()&&-1===[66,190,191].indexOf(e.keyCode))return!1;switch(e.keyCode){case 80:case 33:j();break;case 78:case 34:K();break;case 72:case 37:X();break;case 76:case 39:Y();break;case 75:case 38:F();break;case 74:case 40:U();break;case 36:T(0);break;case 35:T(Number.MAX_VALUE);break;case 32:E()?w():K();break;case 13:E()?w():n=!1;break;case 66:case 190:case 191:k();break;case 70:S();break;default:n=!1}n?e.preventDefault():27===e.keyCode&&wt&&(b(),e.preventDefault()),R()}}function Z(e){Tt.startX=e.touches[0].clientX,Tt.startY=e.touches[0].clientY,Tt.startCount=e.touches.length,2===e.touches.length&&ft.overview&&(Tt.startSpan=d({x:e.touches[1].clientX,y:e.touches[1].clientY},{x:Tt.startX,y:Tt.startY}))}function _(e){if(Tt.handled)navigator.userAgent.match(/android/gi)&&e.preventDefault();else{var t=e.touches[0].clientX,n=e.touches[0].clientY;if(2===e.touches.length&&2===Tt.startCount&&ft.overview){var r=d({x:e.touches[1].clientX,y:e.touches[1].clientY},{x:Tt.startX,y:Tt.startY});Math.abs(Tt.startSpan-r)>Tt.threshold&&(Tt.handled=!0,Tt.startSpan>r?L():w()),e.preventDefault()}else if(1===e.touches.length&&2!==Tt.startCount){var o=t-Tt.startX,s=n-Tt.startY;o>Tt.threshold&&Math.abs(o)>Math.abs(s)?(Tt.handled=!0,X()):-Tt.threshold>o&&Math.abs(o)>Math.abs(s)?(Tt.handled=!0,Y()):s>Tt.threshold?(Tt.handled=!0,F()):-Tt.threshold>s&&(Tt.handled=!0,U()),e.preventDefault()}}}function Q(){Tt.handled=!1}function V(e){clearTimeout(Et),Et=setTimeout(function(){var t=e.detail||-e.wheelDelta;t>0?K():j()},100)}function B(e){e.preventDefault();var t=l(document.querySelectorAll(dt)).length,n=Math.floor(e.clientX/Lt.wrapper.offsetWidth*t);T(n)}function G(e){e.preventDefault(),X()}function J(e){e.preventDefault(),Y()}function et(e){e.preventDefault(),F()}function tt(e){e.preventDefault(),U()}function nt(e){e.preventDefault(),j()}function rt(e){e.preventDefault(),K()}function ot(){P()}function st(){h()}function at(e){if(xt&&E()){e.preventDefault();for(var t=e.target;t&&!t.nodeName.match(/section/gi);)t=t.parentNode;if(t&&!t.classList.contains("disabled")&&(w(),t.nodeName.match(/section/gi))){var n=parseInt(t.getAttribute("data-index-h"),10),r=parseInt(t.getAttribute("data-index-v"),10);T(n,r)}}}var it,ct,lt=".reveal .slides section",dt=".reveal .slides>section",ut=".reveal .slides>section.present>section",vt=".reveal .slides>section:first-child",ft={width:960,height:700,margin:.1,minScale:.2,maxScale:1,controls:!0,progress:!0,history:!1,keyboard:!0,overview:!0,center:!0,touch:!0,loop:!1,rtl:!1,autoSlide:0,mouseWheel:!1,rollingLinks:!0,theme:null,transition:"default",dependencies:[]},mt=ft.autoSlide,pt=0,ht=0,gt=[],yt=1,Lt={},wt="WebkitPerspective"in document.body.style||"MozPerspective"in document.body.style||"msPerspective"in document.body.style||"OPerspective"in document.body.style||"perspective"in document.body.style,bt="WebkitTransform"in document.body.style||"MozTransform"in document.body.style||"msTransform"in document.body.style||"OTransform"in document.body.style||"transform"in document.body.style,Et=0,St=0,qt=0,At=0,kt=0,xt=!1,Tt={startX:0,startY:0,startSpan:0,startCount:0,handled:!1,threshold:80};return{initialize:e,configure:s,slide:T,left:X,right:Y,up:F,down:U,prev:j,next:K,prevFragment:I,nextFragment:H,navigateTo:T,navigateLeft:X,navigateRight:Y,navigateUp:F,navigateDown:U,navigatePrev:j,navigateNext:K,layout:h,toggleOverview:b,togglePause:k,isOverview:E,isPaused:x,addEventListeners:a,removeEventListeners:i,getIndices:z,getSlide:function(e,t){var n=document.querySelectorAll(dt)[e],r=n&&n.querySelectorAll("section");return t!==void 0?r?r[t]:void 0:n},getPreviousSlide:function(){return it},getCurrentSlide:function(){return ct},getScale:function(){return yt},getQueryHash:function(){var e={};return location.search.replace(/[A-Z0-9]+?=(\w*)/gi,function(t){e[t.split("=").shift()]=t.split("=").pop()}),e},isFirstSlide:function(){return null==document.querySelector(lt+".past")?!0:!1},isLastSlide:function(){return ct&&ct.classList.contains(".stack")?null==ct.querySelector(lt+".future")?!0:!1:null==document.querySelector(lt+".future")?!0:!1},addEventListener:function(e,t,n){"addEventListener"in window&&(Lt.wrapper||document.querySelector(".reveal")).addEventListener(e,t,n)},removeEventListener:function(e,t,n){"addEventListener"in window&&(Lt.wrapper||document.querySelector(".reveal")).removeEventListener(e,t,n)}}}(); \ No newline at end of file +var Reveal=function(){"use strict";function e(e){return bt||Lt?(window.addEventListener("load",h,!1),c(ft,e),window.globals=ft.globals,n(),r(),void 0):(document.body.setAttribute("class","no-transforms"),void 0)}function t(){if(wt.theme=document.querySelector("#theme"),wt.wrapper=document.querySelector(".reveal"),wt.slides=document.querySelector(".reveal .slides"),!wt.wrapper.querySelector(".progress")&&ft.progress){var e=document.createElement("div");e.classList.add("progress"),e.innerHTML="",wt.wrapper.appendChild(e)}if(!wt.wrapper.querySelector(".controls")&&ft.controls){var t=document.createElement("aside");t.classList.add("controls"),t.innerHTML='',wt.wrapper.appendChild(t)}if(!wt.wrapper.querySelector(".state-background")){var n=document.createElement("div");n.classList.add("state-background"),wt.wrapper.appendChild(n)}if(!wt.wrapper.querySelector(".pause-overlay")){var r=document.createElement("div");r.classList.add("pause-overlay"),wt.wrapper.appendChild(r)}wt.progress=document.querySelector(".reveal .progress"),wt.progressbar=document.querySelector(".reveal .progress span"),ft.controls&&(wt.controls=document.querySelector(".reveal .controls"),wt.controlsLeft=l(document.querySelectorAll(".navigate-left")),wt.controlsRight=l(document.querySelectorAll(".navigate-right")),wt.controlsUp=l(document.querySelectorAll(".navigate-up")),wt.controlsDown=l(document.querySelectorAll(".navigate-down")),wt.controlsPrev=l(document.querySelectorAll(".navigate-prev")),wt.controlsNext=l(document.querySelectorAll(".navigate-next")))}function n(){/iphone|ipod|android/gi.test(navigator.userAgent)&&!/crios/gi.test(navigator.userAgent)&&(window.addEventListener("load",u,!1),window.addEventListener("orientationchange",u,!1))}function r(){function e(){n.length&&head.js.apply(null,n),o()}for(var t=[],n=[],r=0,s=ft.dependencies.length;s>r;r++){var a=ft.dependencies[r];(!a.condition||a.condition())&&(a.async?n.push(a.src):t.push(a.src),"function"==typeof a.callback&&head.ready(a.src.match(/([\w\d_\-]*)\.?js$|[^\\\/]*$/i)[0],a.callback))}t.length?(head.ready(e),head.js.apply(null,t)):e()}function o(){t(),a(),s(),P(),R(),setTimeout(function(){v("ready",{indexh:pt,indexv:ht,currentSlide:ct})},1)}function s(e){if(wt.wrapper.classList.remove(ft.transition),"object"==typeof e&&c(ft,e),Lt===!1&&(ft.transition="linear"),wt.wrapper.classList.add(ft.transition),wt.controls&&(wt.controls.style.display=ft.controls&&wt.controls?"block":"none"),wt.progress&&(wt.progress.style.display=ft.progress&&wt.progress?"block":"none"),ft.rtl?wt.wrapper.classList.add("rtl"):wt.wrapper.classList.remove("rtl"),ft.center?wt.wrapper.classList.add("center"):wt.wrapper.classList.remove("center"),ft.mouseWheel?(document.addEventListener("DOMMouseScroll",V,!1),document.addEventListener("mousewheel",V,!1)):(document.removeEventListener("DOMMouseScroll",V,!1),document.removeEventListener("mousewheel",V,!1)),ft.rollingLinks?f():m(),ft.theme&&wt.theme){var t=wt.theme.getAttribute("href"),n=/[^\/]*?(?=\.css)/,r=t.match(n)[0];ft.theme!==r&&(t=t.replace(n,ft.theme),wt.theme.setAttribute("href",t))}h()}function a(){if(xt=!0,window.addEventListener("hashchange",ot,!1),window.addEventListener("resize",st,!1),ft.touch&&(document.addEventListener("touchstart",Z,!1),document.addEventListener("touchmove",_,!1),document.addEventListener("touchend",Q,!1)),ft.keyboard&&document.addEventListener("keydown",$,!1),ft.progress&&wt.progress&&wt.progress.addEventListener("click",B,!1),ft.controls&&wt.controls){var e="ontouchstart"in window&&null!=window.ontouchstart?"touchstart":"click";wt.controlsLeft.forEach(function(t){t.addEventListener(e,G,!1)}),wt.controlsRight.forEach(function(t){t.addEventListener(e,J,!1)}),wt.controlsUp.forEach(function(t){t.addEventListener(e,et,!1)}),wt.controlsDown.forEach(function(t){t.addEventListener(e,tt,!1)}),wt.controlsPrev.forEach(function(t){t.addEventListener(e,nt,!1)}),wt.controlsNext.forEach(function(t){t.addEventListener(e,rt,!1)})}}function i(){if(xt=!1,document.removeEventListener("keydown",$,!1),window.removeEventListener("hashchange",ot,!1),window.removeEventListener("resize",st,!1),ft.touch&&(document.removeEventListener("touchstart",Z,!1),document.removeEventListener("touchmove",_,!1),document.removeEventListener("touchend",Q,!1)),ft.progress&&wt.progress&&wt.progress.removeEventListener("click",B,!1),ft.controls&&wt.controls){var e="ontouchstart"in window&&null!=window.ontouchstart?"touchstart":"click";wt.controlsLeft.forEach(function(t){t.removeEventListener(e,G,!1)}),wt.controlsRight.forEach(function(t){t.removeEventListener(e,J,!1)}),wt.controlsUp.forEach(function(t){t.removeEventListener(e,et,!1)}),wt.controlsDown.forEach(function(t){t.removeEventListener(e,tt,!1)}),wt.controlsPrev.forEach(function(t){t.removeEventListener(e,nt,!1)}),wt.controlsNext.forEach(function(t){t.removeEventListener(e,rt,!1)})}}function c(e,t){for(var n in t)e[n]=t[n]}function l(e){return Array.prototype.slice.call(e)}function d(e,t){var n=e.x-t.x,r=e.y-t.y;return Math.sqrt(n*n+r*r)}function u(){0===window.orientation?(document.documentElement.style.overflow="scroll",document.body.style.height="120%"):(document.documentElement.style.overflow="",document.body.style.height="100%"),setTimeout(function(){window.scrollTo(0,1)},10)}function v(e,t){var n=document.createEvent("HTMLEvents",1,2);n.initEvent(e,!0,!0),c(n,t),wt.wrapper.dispatchEvent(n)}function f(){if(Lt&&!("msPerspective"in document.body.style))for(var e=document.querySelectorAll(lt+" a:not(.image)"),t=0,n=e.length;n>t;t++){var r=e[t];if(!(!r.textContent||r.querySelector("*")||r.className&&r.classList.contains(r,"roll"))){var o=document.createElement("span");o.setAttribute("data-title",r.text),o.innerHTML=r.innerHTML,r.classList.add("roll"),r.innerHTML="",r.appendChild(o)}}}function m(){for(var e=document.querySelectorAll(lt+" a.roll"),t=0,n=e.length;n>t;t++){var r=e[t],o=r.querySelector("span");o&&(r.classList.remove("roll"),r.innerHTML=o.innerHTML)}}function p(e){var t=l(e);return t.forEach(function(e,t){e.hasAttribute("data-fragment-index")||e.setAttribute("data-fragment-index",t)}),t.sort(function(e,t){return e.getAttribute("data-fragment-index")-t.getAttribute("data-fragment-index")}),t}function h(){if(wt.wrapper){var e=wt.wrapper.offsetWidth,t=wt.wrapper.offsetHeight;e-=t*ft.margin,t-=t*ft.margin;var n=ft.width,r=ft.height;if("string"==typeof n&&/%$/.test(n)&&(n=parseInt(n,10)/100*e),"string"==typeof r&&/%$/.test(r)&&(r=parseInt(r,10)/100*t),wt.slides.style.width=n+"px",wt.slides.style.height=r+"px",yt=Math.min(e/n,t/r),yt=Math.max(yt,ft.minScale),yt=Math.min(yt,ft.maxScale),void 0===wt.slides.style.zoom||navigator.userAgent.match(/(iphone|ipod|ipad|android)/gi)){var o="translate(-50%, -50%) scale("+yt+") translate(50%, 50%)";wt.slides.style.WebkitTransform=o,wt.slides.style.MozTransform=o,wt.slides.style.msTransform=o,wt.slides.style.OTransform=o,wt.slides.style.transform=o}else wt.slides.style.zoom=yt;for(var s=l(document.querySelectorAll(lt)),a=0,i=s.length;i>a;a++){var c=s[a];"none"!==c.style.display&&(c.style.top=ft.center?c.classList.contains("stack")?0:Math.max(-(c.offsetHeight/2)-20,-r/2)+"px":"")}}}function g(e,t){e&&e.setAttribute("data-previous-indexv",t||0)}function y(e){return e&&e.classList.contains("stack")?parseInt(e.getAttribute("data-previous-indexv")||0,10):0}function w(){if(ft.overview){W();var e=wt.wrapper.classList.contains("overview");wt.wrapper.classList.add("overview"),wt.wrapper.classList.remove("exit-overview"),clearTimeout(At),clearTimeout(kt),At=setTimeout(function(){for(var t=document.querySelectorAll(dt),n=0,r=t.length;r>n;n++){var o=t[n],s="translateZ(-2500px) translate("+105*(n-pt)+"%, 0%)";if(o.setAttribute("data-index-h",n),o.style.display="block",o.style.WebkitTransform=s,o.style.MozTransform=s,o.style.msTransform=s,o.style.OTransform=s,o.style.transform=s,o.classList.contains("stack"))for(var a=o.querySelectorAll("section"),i=0,c=a.length;c>i;i++){var l=n===pt?ht:y(o),d=a[i],u="translate(0%, "+105*(i-l)+"%)";d.setAttribute("data-index-h",n),d.setAttribute("data-index-v",i),d.style.display="block",d.style.WebkitTransform=u,d.style.MozTransform=u,d.style.msTransform=u,d.style.OTransform=u,d.style.transform=u,d.addEventListener("click",at,!0)}else o.addEventListener("click",at,!0)}h(),e||v("overviewshown",{indexh:pt,indexv:ht,currentSlide:ct})},10)}}function L(){if(ft.overview){clearTimeout(At),clearTimeout(kt),wt.wrapper.classList.remove("overview"),wt.wrapper.classList.add("exit-overview"),kt=setTimeout(function(){wt.wrapper.classList.remove("exit-overview")},10);for(var e=l(document.querySelectorAll(lt)),t=0,n=e.length;n>t;t++){var r=e[t];r.style.display="",r.style.WebkitTransform="",r.style.MozTransform="",r.style.msTransform="",r.style.OTransform="",r.style.transform="",r.removeEventListener("click",at,!0)}T(pt,ht),R(),v("overviewhidden",{indexh:pt,indexv:ht,currentSlide:ct})}}function b(e){"boolean"==typeof e?e?w():L():E()?L():w()}function E(){return wt.wrapper.classList.contains("overview")}function S(){var e=document.body,t=e.requestFullScreen||e.webkitRequestFullScreen||e.mozRequestFullScreen||e.msRequestFullScreen;t&&t.apply(e)}function q(){var e=wt.wrapper.classList.contains("paused");W(),wt.wrapper.classList.add("paused"),e===!1&&v("paused")}function A(){var e=wt.wrapper.classList.contains("paused");R(),wt.wrapper.classList.remove("paused"),e&&v("resumed")}function k(){x()?A():q()}function x(){return wt.wrapper.classList.contains("paused")}function T(e,t,n,r){it=ct;var o=document.querySelectorAll(dt);void 0===t&&(t=y(o[e])),it&&it.parentNode&&it.parentNode.classList.contains("stack")&&g(it.parentNode,ht);var s=gt.concat();gt.length=0;var a=pt,i=ht;pt=M(dt,void 0===e?pt:e),ht=M(ut,void 0===t?ht:t),h();e:for(var c=0,d=gt.length;d>c;c++){for(var u=0;s.length>u;u++)if(s[u]===gt[c]){s.splice(u,1);continue e}document.documentElement.classList.add(gt[c]),v(gt[c])}for(;s.length;)document.documentElement.classList.remove(s.pop());E()&&w(),O(1500);var f=o[pt],m=f.querySelectorAll("section");if(ct=m[ht]||f,n!==void 0){var L=p(ct.querySelectorAll(".fragment"));l(L).forEach(function(e,t){n>t?e.classList.add("visible"):e.classList.remove("visible")})}pt!==a||ht!==i?v("slidechanged",{indexh:pt,indexv:ht,previousSlide:it,currentSlide:ct,origin:r}):it=null,it&&(it.classList.remove("present"),document.querySelector(vt).classList.contains("present")&&setTimeout(function(){var e,t=l(document.querySelectorAll(dt+".stack"));for(e in t)t[e]&&g(t[e],0)},0)),N(),D()}function M(e,t){var n=l(document.querySelectorAll(e)),r=n.length;if(r){ft.loop&&(t%=r,0>t&&(t=r+t)),t=Math.max(Math.min(t,r-1),0);for(var o=0;r>o;o++){var s=n[o];if(E()===!1){var a=Math.abs((t-o)%(r-3))||0;s.style.display=a>3?"none":"block"}n[o].classList.remove("past"),n[o].classList.remove("present"),n[o].classList.remove("future"),t>o?n[o].classList.add("past"):o>t&&n[o].classList.add("future"),s.querySelector("section")&&n[o].classList.add("stack")}n[t].classList.add("present");var i=n[t].getAttribute("data-state");i&&(gt=gt.concat(i.split(" ")));var c=n[t].getAttribute("data-autoslide");mt=c?parseInt(c,10):ft.autoSlide}else t=0;return t}function D(){if(ft.progress&&wt.progress){var e=l(document.querySelectorAll(dt)),t=document.querySelectorAll(lt+":not(.stack)").length,n=0;e:for(var r=0;e.length>r;r++){for(var o=e[r],s=l(o.querySelectorAll("section")),a=0;s.length>a;a++){if(s[a].classList.contains("present"))break e;n++}if(o.classList.contains("present"))break;o.classList.contains("stack")===!1&&n++}wt.progressbar.style.width=n/(t-1)*window.innerWidth+"px"}}function N(){if(ft.controls&&wt.controls){var e=C();wt.controlsLeft.concat(wt.controlsRight).concat(wt.controlsUp).concat(wt.controlsDown).concat(wt.controlsPrev).concat(wt.controlsNext).forEach(function(e){e.classList.remove("enabled")}),e.left&&wt.controlsLeft.forEach(function(e){e.classList.add("enabled")}),e.right&&wt.controlsRight.forEach(function(e){e.classList.add("enabled")}),e.up&&wt.controlsUp.forEach(function(e){e.classList.add("enabled")}),e.down&&wt.controlsDown.forEach(function(e){e.classList.add("enabled")}),(e.left||e.up)&&wt.controlsPrev.forEach(function(e){e.classList.add("enabled")}),(e.right||e.down)&&wt.controlsNext.forEach(function(e){e.classList.add("enabled")})}}function C(){var e=document.querySelectorAll(dt),t=document.querySelectorAll(ut);return{left:pt>0,right:e.length-1>pt,up:ht>0,down:t.length-1>ht}}function P(){var e=window.location.hash,t=e.slice(2).split("/"),n=e.replace(/#|\//gi,"");if(isNaN(parseInt(t[0],10))&&n.length){var r=document.querySelector("#"+n);if(r){var o=Reveal.getIndices(r);T(o.h,o.v)}else T(pt,ht)}else{var s=parseInt(t[0],10)||0,a=parseInt(t[1],10)||0;T(s,a)}}function O(e){if(ft.history)if(clearTimeout(qt),"number"==typeof e)qt=setTimeout(O,e);else{var t="/";ct&&"string"==typeof ct.getAttribute("id")?t="/"+ct.getAttribute("id"):((pt>0||ht>0)&&(t+=pt),ht>0&&(t+="/"+ht)),window.location.hash=t}}function z(e){var t=pt,n=ht;if(e){var r=!!e.parentNode.nodeName.match(/section/gi),o=r?e.parentNode:e,s=l(document.querySelectorAll(dt));t=Math.max(s.indexOf(o),0),r&&(n=Math.max(l(e.parentNode.querySelectorAll("section")).indexOf(e),0))}return{h:t,v:n}}function H(){if(document.querySelector(ut+".present")){var e=p(document.querySelectorAll(ut+".present .fragment:not(.visible)"));if(e.length)return e[0].classList.add("visible"),v("fragmentshown",{fragment:e[0]}),!0}else{var t=p(document.querySelectorAll(dt+".present .fragment:not(.visible)"));if(t.length)return t[0].classList.add("visible"),v("fragmentshown",{fragment:t[0]}),!0}return!1}function I(){if(document.querySelector(ut+".present")){var e=p(document.querySelectorAll(ut+".present .fragment.visible"));if(e.length)return e[e.length-1].classList.remove("visible"),v("fragmenthidden",{fragment:e[e.length-1]}),!0}else{var t=p(document.querySelectorAll(dt+".present .fragment.visible"));if(t.length)return t[t.length-1].classList.remove("visible"),v("fragmenthidden",{fragment:t[t.length-1]}),!0}return!1}function R(){clearTimeout(St),!mt||x()||E()||(St=setTimeout(K,mt))}function W(){clearTimeout(St)}function X(){(C().left&&E()||I()===!1)&&T(pt-1)}function Y(){(C().right&&E()||H()===!1)&&T(pt+1)}function F(){(C().up&&E()||I()===!1)&&T(pt,ht-1)}function U(){(C().down&&E()||H()===!1)&&T(pt,ht+1)}function j(){if(I()===!1)if(C().up)F();else{var e=document.querySelector(dt+".past:nth-child("+pt+")");e&&(ht=e.querySelectorAll("section").length+1||void 0,pt--,T())}}function K(){H()===!1&&(C().down?U():Y()),R()}function $(e){document.activeElement;var t=!(!document.activeElement||!document.activeElement.type&&!document.activeElement.href&&"inherit"===document.activeElement.contentEditable);if(!(t||e.shiftKey||e.altKey||e.ctrlKey||e.metaKey)){var n=!0;if(x()&&-1===[66,190,191].indexOf(e.keyCode))return!1;switch(e.keyCode){case 80:case 33:j();break;case 78:case 34:K();break;case 72:case 37:X();break;case 76:case 39:Y();break;case 75:case 38:F();break;case 74:case 40:U();break;case 36:T(0);break;case 35:T(Number.MAX_VALUE);break;case 32:E()?L():K();break;case 13:E()?L():n=!1;break;case 66:case 190:case 191:k();break;case 70:S();break;default:n=!1}n?e.preventDefault():27===e.keyCode&&Lt&&(b(),e.preventDefault()),R()}}function Z(e){Tt.startX=e.touches[0].clientX,Tt.startY=e.touches[0].clientY,Tt.startCount=e.touches.length,2===e.touches.length&&ft.overview&&(Tt.startSpan=d({x:e.touches[1].clientX,y:e.touches[1].clientY},{x:Tt.startX,y:Tt.startY}))}function _(e){if(Tt.handled)navigator.userAgent.match(/android/gi)&&e.preventDefault();else{var t=e.touches[0].clientX,n=e.touches[0].clientY;if(2===e.touches.length&&2===Tt.startCount&&ft.overview){var r=d({x:e.touches[1].clientX,y:e.touches[1].clientY},{x:Tt.startX,y:Tt.startY});Math.abs(Tt.startSpan-r)>Tt.threshold&&(Tt.handled=!0,Tt.startSpan>r?w():L()),e.preventDefault()}else if(1===e.touches.length&&2!==Tt.startCount){var o=t-Tt.startX,s=n-Tt.startY;o>Tt.threshold&&Math.abs(o)>Math.abs(s)?(Tt.handled=!0,X()):-Tt.threshold>o&&Math.abs(o)>Math.abs(s)?(Tt.handled=!0,Y()):s>Tt.threshold?(Tt.handled=!0,F()):-Tt.threshold>s&&(Tt.handled=!0,U()),e.preventDefault()}}}function Q(){Tt.handled=!1}function V(e){clearTimeout(Et),Et=setTimeout(function(){var t=e.detail||-e.wheelDelta;t>0?K():j()},100)}function B(e){e.preventDefault();var t=l(document.querySelectorAll(dt)).length,n=Math.floor(e.clientX/wt.wrapper.offsetWidth*t);T(n)}function G(e){e.preventDefault(),X()}function J(e){e.preventDefault(),Y()}function et(e){e.preventDefault(),F()}function tt(e){e.preventDefault(),U()}function nt(e){e.preventDefault(),j()}function rt(e){e.preventDefault(),K()}function ot(){P()}function st(){h()}function at(e){if(xt&&E()){e.preventDefault();for(var t=e.target;t&&!t.nodeName.match(/section/gi);)t=t.parentNode;if(t&&!t.classList.contains("disabled")&&(L(),t.nodeName.match(/section/gi))){var n=parseInt(t.getAttribute("data-index-h"),10),r=parseInt(t.getAttribute("data-index-v"),10);T(n,r)}}}var it,ct,lt=".reveal .slides section",dt=".reveal .slides>section",ut=".reveal .slides>section.present>section",vt=".reveal .slides>section:first-child",ft={width:960,height:700,margin:.1,minScale:.2,maxScale:1,controls:!0,progress:!0,history:!1,keyboard:!0,overview:!0,center:!0,touch:!0,loop:!1,rtl:!1,autoSlide:0,mouseWheel:!1,rollingLinks:!0,theme:null,transition:"default",dependencies:[]},mt=ft.autoSlide,pt=0,ht=0,gt=[],yt=1,wt={},Lt="WebkitPerspective"in document.body.style||"MozPerspective"in document.body.style||"msPerspective"in document.body.style||"OPerspective"in document.body.style||"perspective"in document.body.style,bt="WebkitTransform"in document.body.style||"MozTransform"in document.body.style||"msTransform"in document.body.style||"OTransform"in document.body.style||"transform"in document.body.style,Et=0,St=0,qt=0,At=0,kt=0,xt=!1,Tt={startX:0,startY:0,startSpan:0,startCount:0,handled:!1,threshold:80};return{initialize:e,configure:s,slide:T,left:X,right:Y,up:F,down:U,prev:j,next:K,prevFragment:I,nextFragment:H,navigateTo:T,navigateLeft:X,navigateRight:Y,navigateUp:F,navigateDown:U,navigatePrev:j,navigateNext:K,layout:h,toggleOverview:b,togglePause:k,isOverview:E,isPaused:x,addEventListeners:a,removeEventListeners:i,getIndices:z,getSlide:function(e,t){var n=document.querySelectorAll(dt)[e],r=n&&n.querySelectorAll("section");return t!==void 0?r?r[t]:void 0:n},getPreviousSlide:function(){return it},getCurrentSlide:function(){return ct},getScale:function(){return yt},getQueryHash:function(){var e={};return location.search.replace(/[A-Z0-9]+?=(\w*)/gi,function(t){e[t.split("=").shift()]=t.split("=").pop()}),e},isFirstSlide:function(){return null==document.querySelector(lt+".past")?!0:!1},isLastSlide:function(){return ct&&ct.classList.contains(".stack")?null==ct.querySelector(lt+".future")?!0:!1:null==document.querySelector(lt+".future")?!0:!1},addEventListener:function(e,t,n){"addEventListener"in window&&(wt.wrapper||document.querySelector(".reveal")).addEventListener(e,t,n)},removeEventListener:function(e,t,n){"addEventListener"in window&&(wt.wrapper||document.querySelector(".reveal")).removeEventListener(e,t,n)}}}(); \ No newline at end of file diff --git a/package.json b/package.json index 830b8771..f8ab38a1 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,11 @@ "version": "2.3.0", "description": "The HTML Presentation Framework", "homepage": "http://lab.hakim.se/reveal-js", + "subdomain": "revealjs", + "scripts": { + "test": "grunt jshint", + "start": "" + }, "author": { "name": "Hakim El Hattab", "email": "hakim.elhattab@gmail.com", @@ -15,14 +20,11 @@ "engines": { "node": "~0.8.0" }, - "scripts": { - "test": "grunt jshint" - }, "dependencies": { "underscore": "~1.3.3", "express": "~2.5.9", - "socket.io": "~0.9.6", - "mustache": "~0.4.0" + "mustache": "~0.4.0", + "socket.io": "~0.9.13" }, "devDependencies": { "grunt-contrib-jshint": "~0.2.0", diff --git a/plugin/multiplex/client.js b/plugin/multiplex/client.js index 6fc0d4db..cb7b27ad 100644 --- a/plugin/multiplex/client.js +++ b/plugin/multiplex/client.js @@ -1,4 +1,5 @@ (function() { + var multiplex = window.globals.multiplex; var socketId = multiplex.id; var socket = io.connect(multiplex.url); @@ -7,6 +8,6 @@ if (data.socketId !== socketId) { return; } if( window.location.host === 'localhost:1947' ) return; - Reveal.navigateTo(data.indexh, data.indexv, 'remote'); + Reveal.slide(data.indexh, data.indexv, null, 'remote'); }); }()); diff --git a/plugin/multiplex/index.js b/plugin/multiplex/index.js index 4665639e..aa8a55a7 100644 --- a/plugin/multiplex/index.js +++ b/plugin/multiplex/index.js @@ -15,7 +15,6 @@ var opts = { io.sockets.on('connection', function(socket) { socket.on('slidechanged', function(slideData) { - console.log(slideData); if (createHash(slideData.secret) === slideData.socketId) { slideData.secret = null; socket.broadcast.emit(slideData.socketId, slideData); @@ -32,12 +31,6 @@ app.configure(function() { app.get("/", function(req, res) { fs.createReadStream(opts.baseDir + '/index.html').pipe(res); }); -app.get("/fixed.html", function(req, res) { - fs.createReadStream(opts.baseDir + '/fixed.html').pipe(res); -}); -app.get("/fixedmaster.html", function(req, res) { - fs.createReadStream(opts.baseDir + '/fixedmaster.html').pipe(res); -}); app.get("/token", function(req,res) { var ts = new Date().getTime(); diff --git a/plugin/multiplex/master.js b/plugin/multiplex/master.js index 3704fa46..a8962444 100644 --- a/plugin/multiplex/master.js +++ b/plugin/multiplex/master.js @@ -1,6 +1,7 @@ (function() { // don't emit events from inside the previews themselves if ( window.location.search.match( /receiver/gi ) ) { return; } + var multiplex = window.globals.multiplex; var socket = io.connect(multiplex.url); @@ -27,6 +28,6 @@ socketId : multiplex.id }; - if( event.origin !== 'remote') socket.emit('slidechanged', slideData); + if( typeof event.origin === 'undefined' && event.origin !== 'remote') socket.emit('slidechanged', slideData); } ); }()); From 4963f15ab31406cf1ee53dc4d116eb8f630f2b1a Mon Sep 17 00:00:00 2001 From: David Banham Date: Sat, 9 Mar 2013 10:16:44 +1100 Subject: [PATCH 9/9] Prevent users from accidentally using common credentials --- index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 18c80a05..5d69f8a1 100644 --- a/index.html +++ b/index.html @@ -360,8 +360,9 @@ function linkify( selector ) { transition: Reveal.getQueryHash().transition || 'default', // default/cube/page/concave/zoom/linear/fade/none globals: { //multiplex: { - // id: '206589480dc41733' - // , secret: '13627006143682682664' + //// Generate a unique id and secret at http://revealjs.jit.su/token + // id: '' + // , secret: '' // , url: 'revealjs.jit.su:80' //} },