Bring multiplex up to date
This commit is contained in:
parent
61c229a4f9
commit
580a72c444
9 changed files with 31 additions and 925 deletions
453
fixed.html
453
fixed.html
|
@ -1,453 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>There I Fixed It</title>
|
||||
|
||||
<meta name="description" content="An amalgamation of dumb ideas that actually turn out to be kind of great.">
|
||||
<meta name="author" content="David Banham and Sam Gentle">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="css/reset.css">
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<link rel="stylesheet" href="css/print.css" type="text/css" media="print">
|
||||
|
||||
<link rel="stylesheet" href="lib/css/zenburn.css">
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="lib/js/html5shiv.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="reveal">
|
||||
|
||||
<!-- Used to fade in a background when a specific slide state is reached -->
|
||||
<div class="state-background"></div>
|
||||
|
||||
<!-- Any section element inside of this container is displayed as a slide -->
|
||||
<div class="slides">
|
||||
<section>
|
||||
<h1>There I Fixed It</h1>
|
||||
<h3 class="inverted">Dumb hacks that end up being great</h3>
|
||||
<script>
|
||||
// Delicously hacky. Look away.
|
||||
if( navigator.userAgent.match( /(iPhone|iPad|iPod|Android)/i ) ) document.write( '<p style="color: rgba(0,0,0,0.3); text-shadow: none;">('+'Tap to navigate'+')</p>' );
|
||||
</script>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Heads Up</h2>
|
||||
<p>
|
||||
This presentation uses a souped-up version of reveal.js
|
||||
</p>
|
||||
<p>
|
||||
Go here on your laptop, smartphone or tablet:
|
||||
</p>
|
||||
<p><a href="http://revealjs.jit.su/fixed.html">http://revealjs.jit.su/fixed.html</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>Who the hell are you?</h2>
|
||||
<a href="http://www.pinion.gg" class="image">
|
||||
<img src="http://www.pinion.gg/images/pinion_green_horizontal.png">
|
||||
</a>
|
||||
</section>
|
||||
<section>
|
||||
<h2>What the hell is this?</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2012/2/24/2d633fb0-9205-46f2-9bc1-f508124308aa.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/8/129047925338284784.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Unql -->
|
||||
<section>
|
||||
<section>
|
||||
<h2>In the beginning.</h2>
|
||||
<p>
|
||||
There was SQL.
|
||||
</p>
|
||||
<p>
|
||||
And it was okay.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>And then...</h2>
|
||||
<p>There was noSQL!</p>
|
||||
<p>And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy.
|
||||
</section>
|
||||
<section>
|
||||
<h2>But then you want to actually use it</h2>
|
||||
</section>
|
||||
<section>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
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()
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<img src="http://c1eatdrinkbettercom.wpengine.netdna-cdn.com/files/2012/05/nope.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>unql-node</h2>
|
||||
<p>
|
||||
<a href="https://github.com/sgentle/unql-node">
|
||||
https://github.com/sgentle/unql-node
|
||||
</a>
|
||||
</p>
|
||||
<p>It's like SQL for NoSQL</p>
|
||||
<img src="http://geekspodcast.com/geekpress/wp-content/uploads/2009/07/yo_dawg-230x300.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Deletin' stuff</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Why don't we take all the data...</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
> 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
|
||||
</code></pre>
|
||||
<h2>And put it over here!</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Want to see my awesome LALR recursive descent parser?</h2>
|
||||
<img src="http://ic.pics.livejournal.com/ontinia/10827199/5144/original.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Nope!</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
|
||||
query = "update #{db} set _deleted = true"
|
||||
query += " where #{expr}" if expr
|
||||
processExpr query, cb
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>There I fixed it.</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/4/129043939908502110.jpg"</img>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>noDB</h2>
|
||||
<p>So you want to add some persistence to your simple web app.</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>Okay so just require that each user have a couch installation.</p>
|
||||
<p>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.</p>
|
||||
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/72/ER_Diagram_MMORPG.png/539px-ER_Diagram_MMORPG.png">
|
||||
<p>Maybe it would be easier to build SQLite?</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Nope!</h2>
|
||||
<img src="https://dl.dropbox.com/u/176051/nopenopenope.jpeg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>noDB</h2>
|
||||
<p>SQL < noSQL < noDB</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Super simple</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="javascript">
|
||||
var users = JSON.parse(fs.readFileSync('data/users.json'))
|
||||
|
||||
users.push({name: "newguy"});
|
||||
fs.writeFileSync('data/users.json', JSON.stringify(users));
|
||||
res.send('success');
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Session storage too!</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="javascript">
|
||||
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);
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>It's basically Redis</h2>
|
||||
<small>It's not really</small>
|
||||
</section>
|
||||
<section>
|
||||
<h2>But it is:</h2>
|
||||
<ul>
|
||||
<li>Deployable</li>
|
||||
<li>Dependency free</li>
|
||||
<li>Easily backed up</li>
|
||||
<li>Debuggable</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Databases: Fixed</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/20/129058269966385911.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>I would like to make some information available on the internet.</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So find a shared hosting provider or something.</h2>
|
||||
<p>But they're kind of crappy</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So I'll just run my own</h2>
|
||||
<p>On nginx or express or something!</p>
|
||||
<p>But load balancing and updates and bugs and oh no.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Oh I know!</h2>
|
||||
<img src="http://s2.wp.com/wp-content/themes/h4/i/logo-v-rgb.png?m=1308937729g">
|
||||
</section>
|
||||
<section>
|
||||
<img src="https://dl.dropbox.com/u/176051/spidernope.jpeg">
|
||||
</section>
|
||||
<section>
|
||||
<blockquote>
|
||||
Augh. I wish I could just shove all this right on Akamai
|
||||
</blockquote>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>Why not?</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Step 0: Generate static site</h2>
|
||||
<p>Use whatever you want. We really like <a href="http://jade-lang.com/">Jade.</a></p>
|
||||
</section>
|
||||
<section>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="jade">
|
||||
!!! 5
|
||||
include includes/head.jade
|
||||
body
|
||||
include includes/header.jade
|
||||
// BEGIN Content
|
||||
.inner-bg
|
||||
#content-wrapper
|
||||
Welcome to zombocom!
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>make</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
JADE = $(shell find pages/*.jade)
|
||||
HTML = $(JADE:.jade=.html)
|
||||
|
||||
all: $(HTML)
|
||||
|
||||
%.html: %.jade
|
||||
./jade/bin/jade < $< --path $< > $@
|
||||
|
||||
clean:
|
||||
rm -f $(HTML)
|
||||
|
||||
.PHONY: clean
|
||||
</code></pre>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Rackspace == Akamai</h2>
|
||||
<p>It's cheap. 18c per GB</p>
|
||||
<p>You don't have to deal directly with Akamai. Keep your soul!</p>
|
||||
<p><a href="http://www.rackspace.com/cloud/public/files/">http://www.rackspace.com/cloud/public/files/</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Getting it there</h2>
|
||||
<p>There's a node library for that.</p>
|
||||
<p><a href="https://github.com/nodejitsu/node-cloudfiles">https://github.com/nodejitsu/node-cloudfiles</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>There's also some tooling for that.</p>
|
||||
<p><a href="https://github.com/PinionTech/cloud-loader">https://github.com/PinionTech/cloud-loader</a></p>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
coffee cloud-loader.coffee -x localDir cloudContainer
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Deep magic</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
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
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Relax</h2>
|
||||
<p>Never ever care about whether your website is up.</p>
|
||||
<p>Go do something useful instead.</p>
|
||||
<br />
|
||||
<p>Yeah, it's harder to do pretty URLs.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So fixed</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/19/129057249545630776.jpg">
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<section>
|
||||
<h2>It's not always the right thing to just fix it</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>But sometimes it is</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/22/129060139339845620.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h1>ALL FIXED</h1>
|
||||
<h3 class="inverted">BY David Banham and Sam Gentle</h3>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/22/129059992995261245.jpg">
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- The navigational controls UI -->
|
||||
<aside class="controls">
|
||||
<a class="left" href="#">◄</a>
|
||||
<a class="right" href="#">►</a>
|
||||
<a class="up" href="#">▲</a>
|
||||
<a class="down" href="#">▼</a>
|
||||
</aside>
|
||||
|
||||
<!-- Presentation progress bar -->
|
||||
<div class="progress"><span></span></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="lib/js/head.min.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var multiplex = {
|
||||
id: 'e754f2af1a284921'
|
||||
, secret: null
|
||||
, url: 'revealjs.jit.su'
|
||||
};
|
||||
|
||||
var notes = false;
|
||||
|
||||
head.ready( function() {
|
||||
|
||||
// Fires when a slide with data-state=customevent is activated
|
||||
Reveal.addEventListener( 'customevent', function() {
|
||||
console.log( '"customevent" has fired' );
|
||||
} );
|
||||
|
||||
// Fires each time a new slide is activated
|
||||
Reveal.addEventListener( 'slidechanged', function( event ) {
|
||||
// event.previousSlide, event.currentSlide, event.indexh, event.indexv
|
||||
} );
|
||||
|
||||
// Full list of configuration options available here:
|
||||
// https://github.com/hakimel/reveal.js#configuration
|
||||
Reveal.initialize({
|
||||
controls: true,
|
||||
progress: true,
|
||||
history: true,
|
||||
|
||||
theme: Reveal.getQueryHash().theme || 'default', // default/neon/beige
|
||||
transition: Reveal.getQueryHash().transition || 'default' // default/cube/page/concave/linear(2d)
|
||||
});
|
||||
|
||||
// Load highlight.js for syntax highlighting of code samples
|
||||
head.js( 'lib/js/highlight.js', function() {
|
||||
hljs.initHighlightingOnLoad();
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
// Scripts that should be loaded before initializing
|
||||
var scripts = [];
|
||||
|
||||
// If the browser doesn't support classList, load a polyfill
|
||||
if( !document.body.classList ) {
|
||||
head.js( 'lib/js/classList.js' );
|
||||
}
|
||||
|
||||
// Load markdown parser if there are slides defined using markdown
|
||||
if( document.querySelector( '[data-markdown]' ) ) {
|
||||
scripts.push( 'lib/js/showdown.js' );
|
||||
scripts.push( 'lib/js/data-markdown.js' );
|
||||
}
|
||||
|
||||
scripts.push( 'js/reveal.js' );
|
||||
|
||||
// If we're runnning the notes server we need to include some additional JS
|
||||
// TODO Is there a better way to determine if we're running the notes server?
|
||||
if( window.location.host === 'localhost:1947' || notes === true) {
|
||||
scripts.push( 'socket.io/socket.io.js' );
|
||||
scripts.push( 'plugin/speakernotes/client.js' );
|
||||
}
|
||||
|
||||
if( multiplex.id !== null ) {
|
||||
scripts.push( 'socket.io/socket.io.js' );
|
||||
scripts.push( 'plugin/multiplex/client.js' );
|
||||
|
||||
if( multiplex.secret !== null ) {
|
||||
scripts.push( 'plugin/multiplex/master.js' );
|
||||
}
|
||||
}
|
||||
|
||||
// Load the scripts and, when completed, initialize reveal.js
|
||||
head.js.apply( null, scripts );
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
453
fixedmaster.html
453
fixedmaster.html
|
@ -1,453 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>There I Fixed It</title>
|
||||
|
||||
<meta name="description" content="An amalgamation of dumb ideas that actually turn out to be kind of great.">
|
||||
<meta name="author" content="David Banham and Sam Gentle">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
|
||||
<link href='http://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic' rel='stylesheet' type='text/css'>
|
||||
|
||||
<link rel="stylesheet" href="css/reset.css">
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<link rel="stylesheet" href="css/print.css" type="text/css" media="print">
|
||||
|
||||
<link rel="stylesheet" href="lib/css/zenburn.css">
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="lib/js/html5shiv.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="reveal">
|
||||
|
||||
<!-- Used to fade in a background when a specific slide state is reached -->
|
||||
<div class="state-background"></div>
|
||||
|
||||
<!-- Any section element inside of this container is displayed as a slide -->
|
||||
<div class="slides">
|
||||
<section>
|
||||
<h1>There I Fixed It</h1>
|
||||
<h3 class="inverted">Dumb hacks that end up being great</h3>
|
||||
<script>
|
||||
// Delicously hacky. Look away.
|
||||
if( navigator.userAgent.match( /(iPhone|iPad|iPod|Android)/i ) ) document.write( '<p style="color: rgba(0,0,0,0.3); text-shadow: none;">('+'Tap to navigate'+')</p>' );
|
||||
</script>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Heads Up</h2>
|
||||
<p>
|
||||
This presentation uses a souped-up version of reveal.js
|
||||
</p>
|
||||
<p>
|
||||
Go here on your laptop, smartphone or tablet:
|
||||
</p>
|
||||
<p><a href="http://revealjs.jit.su/fixed.html">http://revealjs.jit.su/fixed.html</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>Who the hell are you?</h2>
|
||||
<a href="http://www.pinion.gg" class="image">
|
||||
<img src="http://www.pinion.gg/images/pinion_green_horizontal.png">
|
||||
</a>
|
||||
</section>
|
||||
<section>
|
||||
<h2>What the hell is this?</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2012/2/24/2d633fb0-9205-46f2-9bc1-f508124308aa.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/8/129047925338284784.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<!-- Unql -->
|
||||
<section>
|
||||
<section>
|
||||
<h2>In the beginning.</h2>
|
||||
<p>
|
||||
There was SQL.
|
||||
</p>
|
||||
<p>
|
||||
And it was okay.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>And then...</h2>
|
||||
<p>There was noSQL!</p>
|
||||
<p>And it scaled and it was all javascripty and all the hipsters loved it and everyone was happy.
|
||||
</section>
|
||||
<section>
|
||||
<h2>But then you want to actually use it</h2>
|
||||
</section>
|
||||
<section>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
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()
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<img src="http://c1eatdrinkbettercom.wpengine.netdna-cdn.com/files/2012/05/nope.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>unql-node</h2>
|
||||
<p>
|
||||
<a href="https://github.com/sgentle/unql-node">
|
||||
https://github.com/sgentle/unql-node
|
||||
</a>
|
||||
</p>
|
||||
<p>It's like SQL for NoSQL</p>
|
||||
<img src="http://geekspodcast.com/geekpress/wp-content/uploads/2009/07/yo_dawg-230x300.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Deletin' stuff</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
> delete from checkins where username.match(/\d{4}$/) && timestamp > (new Date()).getTime()-1000*60*60*24*7
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Why don't we take all the data...</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
> 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
|
||||
</code></pre>
|
||||
<h2>And put it over here!</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Want to see my awesome LALR recursive descent parser?</h2>
|
||||
<img src="http://ic.pics.livejournal.com/ontinia/10827199/5144/original.jpg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>Nope!</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
handle /delete from (\S+)(?: where (.*))?/, (db, expr, cb) ->
|
||||
query = "update #{db} set _deleted = true"
|
||||
query += " where #{expr}" if expr
|
||||
processExpr query, cb
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>There I fixed it.</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/4/129043939908502110.jpg"</img>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>noDB</h2>
|
||||
<p>So you want to add some persistence to your simple web app.</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>Okay so just require that each user have a couch installation.</p>
|
||||
<p>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.</p>
|
||||
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/72/ER_Diagram_MMORPG.png/539px-ER_Diagram_MMORPG.png">
|
||||
<p>Maybe it would be easier to build SQLite?</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Nope!</h2>
|
||||
<img src="https://dl.dropbox.com/u/176051/nopenopenope.jpeg">
|
||||
</section>
|
||||
<section>
|
||||
<h2>noDB</h2>
|
||||
<p>SQL < noSQL < noDB</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Super simple</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="javascript">
|
||||
var users = JSON.parse(fs.readFileSync('data/users.json'))
|
||||
|
||||
users.push({name: "newguy"});
|
||||
fs.writeFileSync('data/users.json', JSON.stringify(users));
|
||||
res.send('success');
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Session storage too!</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="javascript">
|
||||
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);
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>It's basically Redis</h2>
|
||||
<small>It's not really</small>
|
||||
</section>
|
||||
<section>
|
||||
<h2>But it is:</h2>
|
||||
<ul>
|
||||
<li>Deployable</li>
|
||||
<li>Dependency free</li>
|
||||
<li>Easily backed up</li>
|
||||
<li>Debuggable</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Databases: Fixed</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/20/129058269966385911.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section>
|
||||
<h2>I would like to make some information available on the internet.</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So find a shared hosting provider or something.</h2>
|
||||
<p>But they're kind of crappy</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So I'll just run my own</h2>
|
||||
<p>On nginx or express or something!</p>
|
||||
<p>But load balancing and updates and bugs and oh no.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Oh I know!</h2>
|
||||
<img src="http://s2.wp.com/wp-content/themes/h4/i/logo-v-rgb.png?m=1308937729g">
|
||||
</section>
|
||||
<section>
|
||||
<img src="https://dl.dropbox.com/u/176051/spidernope.jpeg">
|
||||
</section>
|
||||
<section>
|
||||
<blockquote>
|
||||
Augh. I wish I could just shove all this right on Akamai
|
||||
</blockquote>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>...</p>
|
||||
</section>
|
||||
<section>
|
||||
<p>Why not?</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Step 0: Generate static site</h2>
|
||||
<p>Use whatever you want. We really like <a href="http://jade-lang.com/">Jade.</a></p>
|
||||
</section>
|
||||
<section>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;" class="jade">
|
||||
!!! 5
|
||||
include includes/head.jade
|
||||
body
|
||||
include includes/header.jade
|
||||
// BEGIN Content
|
||||
.inner-bg
|
||||
#content-wrapper
|
||||
Welcome to zombocom!
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2>make</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
JADE = $(shell find pages/*.jade)
|
||||
HTML = $(JADE:.jade=.html)
|
||||
|
||||
all: $(HTML)
|
||||
|
||||
%.html: %.jade
|
||||
./jade/bin/jade < $< --path $< > $@
|
||||
|
||||
clean:
|
||||
rm -f $(HTML)
|
||||
|
||||
.PHONY: clean
|
||||
</code></pre>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Rackspace == Akamai</h2>
|
||||
<p>It's cheap. 18c per GB</p>
|
||||
<p>You don't have to deal directly with Akamai. Keep your soul!</p>
|
||||
<p><a href="http://www.rackspace.com/cloud/public/files/">http://www.rackspace.com/cloud/public/files/</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Getting it there</h2>
|
||||
<p>There's a node library for that.</p>
|
||||
<p><a href="https://github.com/nodejitsu/node-cloudfiles">https://github.com/nodejitsu/node-cloudfiles</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<p>There's also some tooling for that.</p>
|
||||
<p><a href="https://github.com/PinionTech/cloud-loader">https://github.com/PinionTech/cloud-loader</a></p>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
coffee cloud-loader.coffee -x localDir cloudContainer
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Deep magic</h2>
|
||||
<pre><code contenteditable style="font-size: 18px; margin-top: 20px;">
|
||||
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
|
||||
</code></pre>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Relax</h2>
|
||||
<p>Never ever care about whether your website is up.</p>
|
||||
<p>Go do something useful instead.</p>
|
||||
<br />
|
||||
<p>Yeah, it's harder to do pretty URLs.</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>So fixed</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/19/129057249545630776.jpg">
|
||||
</section>
|
||||
</section>
|
||||
<section>
|
||||
<section>
|
||||
<h2>It's not always the right thing to just fix it</h2>
|
||||
</section>
|
||||
<section>
|
||||
<h2>But sometimes it is</h2>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/22/129060139339845620.jpg">
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h1>ALL FIXED</h1>
|
||||
<h3 class="inverted">BY David Banham and Sam Gentle</h3>
|
||||
<img src="http://i.chzbgr.com/completestore/2009/12/22/129059992995261245.jpg">
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- The navigational controls UI -->
|
||||
<aside class="controls">
|
||||
<a class="left" href="#">◄</a>
|
||||
<a class="right" href="#">►</a>
|
||||
<a class="up" href="#">▲</a>
|
||||
<a class="down" href="#">▼</a>
|
||||
</aside>
|
||||
|
||||
<!-- Presentation progress bar -->
|
||||
<div class="progress"><span></span></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="lib/js/head.min.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
var multiplex = {
|
||||
id: 'e754f2af1a284921'
|
||||
, secret: '13450197174132860353'
|
||||
, url: 'revealjs.jit.su'
|
||||
};
|
||||
|
||||
var notes = false;
|
||||
|
||||
head.ready( function() {
|
||||
|
||||
// Fires when a slide with data-state=customevent is activated
|
||||
Reveal.addEventListener( 'customevent', function() {
|
||||
console.log( '"customevent" has fired' );
|
||||
} );
|
||||
|
||||
// Fires each time a new slide is activated
|
||||
Reveal.addEventListener( 'slidechanged', function( event ) {
|
||||
// event.previousSlide, event.currentSlide, event.indexh, event.indexv
|
||||
} );
|
||||
|
||||
// Full list of configuration options available here:
|
||||
// https://github.com/hakimel/reveal.js#configuration
|
||||
Reveal.initialize({
|
||||
controls: true,
|
||||
progress: true,
|
||||
history: true,
|
||||
|
||||
theme: Reveal.getQueryHash().theme || 'default', // default/neon/beige
|
||||
transition: Reveal.getQueryHash().transition || 'default' // default/cube/page/concave/linear(2d)
|
||||
});
|
||||
|
||||
// Load highlight.js for syntax highlighting of code samples
|
||||
head.js( 'lib/js/highlight.js', function() {
|
||||
hljs.initHighlightingOnLoad();
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
// Scripts that should be loaded before initializing
|
||||
var scripts = [];
|
||||
|
||||
// If the browser doesn't support classList, load a polyfill
|
||||
if( !document.body.classList ) {
|
||||
head.js( 'lib/js/classList.js' );
|
||||
}
|
||||
|
||||
// Load markdown parser if there are slides defined using markdown
|
||||
if( document.querySelector( '[data-markdown]' ) ) {
|
||||
scripts.push( 'lib/js/showdown.js' );
|
||||
scripts.push( 'lib/js/data-markdown.js' );
|
||||
}
|
||||
|
||||
scripts.push( 'js/reveal.js' );
|
||||
|
||||
// If we're runnning the notes server we need to include some additional JS
|
||||
// TODO Is there a better way to determine if we're running the notes server?
|
||||
if( window.location.host === 'localhost:1947' || notes === true) {
|
||||
scripts.push( 'socket.io/socket.io.js' );
|
||||
scripts.push( 'plugin/speakernotes/client.js' );
|
||||
}
|
||||
|
||||
if( multiplex.id !== null ) {
|
||||
scripts.push( 'socket.io/socket.io.js' );
|
||||
scripts.push( 'plugin/multiplex/client.js' );
|
||||
|
||||
if( multiplex.secret !== null ) {
|
||||
scripts.push( 'plugin/multiplex/master.js' );
|
||||
}
|
||||
}
|
||||
|
||||
// Load the scripts and, when completed, initialize reveal.js
|
||||
head.js.apply( null, scripts );
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
12
index.html
12
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; } }
|
||||
]
|
||||
});
|
||||
|
||||
|
|
|
@ -161,6 +161,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 {
|
||||
|
|
4
js/reveal.min.js
vendored
4
js/reveal.min.js
vendored
File diff suppressed because one or more lines are too long
12
package.json
12
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",
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
}());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
} );
|
||||
}());
|
||||
|
|
Loading…
Reference in a new issue