2012-08-15 10:55:22 +02:00
<!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 >
2012-08-15 11:01:14 +02:00
< p > < a href = "http://revealjs.jit.su/fixed.html" > http://revealjs.jit.su/fixed.html< / a > < / p >
2012-08-15 10:55:22 +02:00
< / 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 >