node powered mobile

Post on 17-May-2015

4.841 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Node Powered MobileBy Tim Caswell

Saturday, June 5, 2010

Node Powered MobileBy Tim Caswell

Saturday, June 5, 2010

Simple but Different

Saturday, June 5, 2010

What is needed

Saturday, June 5, 2010

What is needed• Simple Interface

• Light Code

• Networked Data

• Real-Time Data

• Free Deployment

• Open Workflow

Saturday, June 5, 2010

What is needed• Simple Interface

• Light Code

• Networked Data

• Real-Time Data

• Free Deployment

• Open Workflow

• HTML, SVG, CSS

• JavaScript

• HTTP Services

• PubSub

• Browser Apps

• It’s just text!

Saturday, June 5, 2010

ConnectWe’ll use a new node

framework that “connects” the mobile browser to data

on the server.

Saturday, June 5, 2010

It’s like Japanese LegosSaturday, June 5, 2010

Connect.createServer([ {filter: "log"}, {filter: "body-decoder"}, {filter: "conditional-get"}, {filter: "cache"}, {filter: "gzip"}, {provider: "cache-manifest", root: root}, {provider: "static", root: root}]);

Pre-Built Blocks

Saturday, June 5, 2010

And easy too!Saturday, June 5, 2010

method-override.jsvar key;// Initialize any state (on server startup)exports.setup = function (env) { key = this.key || "_method";};// Modify the request stream (on request)exports.handle = function(err, req, res, next){ if (key in req.body) { req.method = req.body[key].toUpperCase(); } next();};

Saturday, June 5, 2010

response-time.jsexports.handle = function(err, req, res, next){ var start = new Date, writeHead = res.writeHead;

res.writeHead = function(code, headers){ res.writeHead = writeHead; headers['X-Response-Time'] = (new Date - start) + "ms"; res.writeHead(code, headers); };

next();};

Saturday, June 5, 2010

Well, actually, it’s not always easy.

Saturday, June 5, 2010

static.js

Saturday, June 5, 2010

static.jsvar fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js // Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js // Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

} next(err); return; }

// Serve the file directly using buffers fs.readFile(filename, function (err, data) { if (err) { next(err); return; } res.writeHead(200, { "Content-Type": Mime.type(filename), "Content-Length": data.length, "Last-Modified": stat.mtime.toUTCString(), // Cache in browser for 1 year "Cache-Control": "public max-age=" + 31536000 }); res.end(data); }); }); }

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js // Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

} next(err); return; }

// Serve the file directly using buffers fs.readFile(filename, function (err, data) { if (err) { next(err); return; } res.writeHead(200, { "Content-Type": Mime.type(filename), "Content-Length": data.length, "Last-Modified": stat.mtime.toUTCString(), // Cache in browser for 1 year "Cache-Control": "public max-age=" + 31536000 }); res.end(data); }); }); }

};

// Mini mime module for static file servingvar Mime = {

type: function getMime(path) { var index = path.lastIndexOf("."); if (index < 0) { return DEFAULT_MIME; } var type = Mime.TYPES[path.substring(index).toLowerCase()] || DEFAULT_MIME; return (/(text|javascript)/).test(type) ? type + "; charset=utf-8" : type; },

TYPES : { ".3gp" : "video/3gpp", ".a" : "application/octet-stream", ".ai" : "application/postscript", ".aif" : "audio/x-aiff", ".aiff" : "audio/x-aiff", ".asc" : "application/pgp-signature", ".asf" : "video/x-ms-asf", ".asm" : "text/x-asm", ".asx" : "video/x-ms-asf", ".atom" : "application/atom+xml", ".au" : "audio/basic", ".avi" : "video/x-msvideo", ".bat" : "application/x-msdownload", ".bin" : "application/octet-stream",

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js ".flv" : "video/x-flv", ".for" : "text/x-fortran", ".gem" : "application/octet-stream", ".gemspec" : "text/x-script.ruby", ".gif" : "image/gif", ".gz" : "application/x-gzip", ".h" : "text/x-c", ".hh" : "text/x-c", ".htm" : "text/html", ".html" : "text/html", ".ico" : "image/vnd.microsoft.icon", ".ics" : "text/calendar", ".ifb" : "text/calendar", ".iso" : "application/octet-stream", ".jar" : "application/java-archive", ".java" : "text/x-java-source", ".jnlp" : "application/x-java-jnlp-file", ".jpeg" : "image/jpeg", ".jpg" : "image/jpeg", ".js" : "application/javascript", ".json" : "application/json", ".log" : "text/plain", ".m3u" : "audio/x-mpegurl", ".m4v" : "video/mp4", ".man" : "text/troff", ".mathml" : "application/mathml+xml", ".mbox" : "application/mbox", ".mdoc" : "text/troff", ".me" : "text/troff", ".mid" : "audio/midi", ".midi" : "audio/midi", ".mime" : "message/rfc822", ".mml" : "application/mathml+xml", ".mng" : "video/x-mng", ".mov" : "video/quicktime", ".mp3" : "audio/mpeg", ".mp4" : "video/mp4", ".mp4v" : "video/mp4", ".mpeg" : "video/mpeg", ".mpg" : "video/mpeg", ".ms" : "text/troff", ".msi" : "application/x-msdownload", ".odp" : "application/vnd.oasis.opendocument.presentation", ".ods" : "application/vnd.oasis.opendocument.spreadsheet", ".odt" : "application/vnd.oasis.opendocument.text", ".ogg" : "application/ogg", ".p" : "text/x-pascal", ".pas" : "text/x-pascal", ".pbm" : "image/x-portable-bitmap", ".pdf" : "application/pdf", ".pem" : "application/x-x509-ca-cert", ".pgm" : "image/x-portable-graymap", ".pgp" : "application/pgp-encrypted", ".pkg" : "application/octet-stream", ".pl" : "text/x-script.perl", ".pm" : "text/x-script.perl-module", ".png" : "image/png", ".pnm" : "image/x-portable-anymap", ".ppm" : "image/x-portable-pixmap", ".pps" : "application/vnd.ms-powerpoint", ".ppt" : "application/vnd.ms-powerpoint", ".ps" : "application/postscript", ".psd" : "image/vnd.adobe.photoshop", ".py" : "text/x-script.python", ".qt" : "video/quicktime", ".ra" : "audio/x-pn-realaudio", ".rake" : "text/x-script.ruby", ".ram" : "audio/x-pn-realaudio", ".rar" : "application/x-rar-compressed", ".rb" : "text/x-script.ruby", ".rdf" : "application/rdf+xml", ".roff" : "text/troff", ".rpm" : "application/x-redhat-package-manager", ".rss" : "application/rss+xml", ".rtf" : "application/rtf", ".ru" : "text/x-script.ruby", ".s" : "text/x-asm", ".sgm" : "text/sgml", ".sgml" : "text/sgml", ".sh" : "application/x-sh", ".sig" : "application/pgp-signature", ".snd" : "audio/basic", ".so" : "application/octet-stream", ".svg" : "image/svg+xml", ".svgz" : "image/svg+xml", ".swf" : "application/x-shockwave-flash", ".t" : "text/troff", ".tar" : "application/x-tar", ".tbz" : "application/x-bzip-compressed-tar", ".tci" : "application/x-topcloud", ".tcl" : "application/x-tcl", ".tex" : "application/x-tex", ".texi" : "application/x-texinfo", ".texinfo" : "application/x-texinfo", ".text" : "text/plain", ".tif" : "image/tiff", ".tiff" : "image/tiff", ".torrent" : "application/x-bittorrent", ".tr" : "text/troff", ".ttf" : "application/x-font-ttf", ".txt" : "text/plain", ".vcf" : "text/x-vcard", ".vcs" : "text/x-vcalendar", ".vrml" : "model/vrml", ".war" : "application/java-archive", ".wav" : "audio/x-wav", ".wma" : "audio/x-ms-wma", ".wmv" : "video/x-ms-wmv", ".wmx" : "video/x-ms-wmx", ".wrl" : "model/vrml", ".wsdl" : "application/wsdl+xml", ".xbm" : "image/x-xbitmap", ".xhtml" : "application/xhtml+xml", ".xls" : "application/vnd.ms-excel", ".xml" : "application/xml", ".xpm" : "image/x-xpixmap", ".xsl" : "application/xml", ".xslt" : "application/xslt+xml", ".yaml" : "text/yaml", ".yml" : "text/yaml", ".zip" : "application/zip" }};

// Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

} next(err); return; }

// Serve the file directly using buffers fs.readFile(filename, function (err, data) { if (err) { next(err); return; } res.writeHead(200, { "Content-Type": Mime.type(filename), "Content-Length": data.length, "Last-Modified": stat.mtime.toUTCString(), // Cache in browser for 1 year "Cache-Control": "public max-age=" + 31536000 }); res.end(data); }); }); }

};

// Mini mime module for static file servingvar Mime = {

type: function getMime(path) { var index = path.lastIndexOf("."); if (index < 0) { return DEFAULT_MIME; } var type = Mime.TYPES[path.substring(index).toLowerCase()] || DEFAULT_MIME; return (/(text|javascript)/).test(type) ? type + "; charset=utf-8" : type; },

TYPES : { ".3gp" : "video/3gpp", ".a" : "application/octet-stream", ".ai" : "application/postscript", ".aif" : "audio/x-aiff", ".aiff" : "audio/x-aiff", ".asc" : "application/pgp-signature", ".asf" : "video/x-ms-asf", ".asm" : "text/x-asm", ".asx" : "video/x-ms-asf", ".atom" : "application/atom+xml", ".au" : "audio/basic", ".avi" : "video/x-msvideo", ".bat" : "application/x-msdownload", ".bin" : "application/octet-stream",

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js ".flv" : "video/x-flv", ".for" : "text/x-fortran", ".gem" : "application/octet-stream", ".gemspec" : "text/x-script.ruby", ".gif" : "image/gif", ".gz" : "application/x-gzip", ".h" : "text/x-c", ".hh" : "text/x-c", ".htm" : "text/html", ".html" : "text/html", ".ico" : "image/vnd.microsoft.icon", ".ics" : "text/calendar", ".ifb" : "text/calendar", ".iso" : "application/octet-stream", ".jar" : "application/java-archive", ".java" : "text/x-java-source", ".jnlp" : "application/x-java-jnlp-file", ".jpeg" : "image/jpeg", ".jpg" : "image/jpeg", ".js" : "application/javascript", ".json" : "application/json", ".log" : "text/plain", ".m3u" : "audio/x-mpegurl", ".m4v" : "video/mp4", ".man" : "text/troff", ".mathml" : "application/mathml+xml", ".mbox" : "application/mbox", ".mdoc" : "text/troff", ".me" : "text/troff", ".mid" : "audio/midi", ".midi" : "audio/midi", ".mime" : "message/rfc822", ".mml" : "application/mathml+xml", ".mng" : "video/x-mng", ".mov" : "video/quicktime", ".mp3" : "audio/mpeg", ".mp4" : "video/mp4", ".mp4v" : "video/mp4", ".mpeg" : "video/mpeg", ".mpg" : "video/mpeg", ".ms" : "text/troff", ".msi" : "application/x-msdownload", ".odp" : "application/vnd.oasis.opendocument.presentation", ".ods" : "application/vnd.oasis.opendocument.spreadsheet", ".odt" : "application/vnd.oasis.opendocument.text", ".ogg" : "application/ogg", ".p" : "text/x-pascal", ".pas" : "text/x-pascal", ".pbm" : "image/x-portable-bitmap", ".pdf" : "application/pdf", ".pem" : "application/x-x509-ca-cert", ".pgm" : "image/x-portable-graymap", ".pgp" : "application/pgp-encrypted", ".pkg" : "application/octet-stream", ".pl" : "text/x-script.perl", ".pm" : "text/x-script.perl-module", ".png" : "image/png", ".pnm" : "image/x-portable-anymap", ".ppm" : "image/x-portable-pixmap", ".pps" : "application/vnd.ms-powerpoint", ".ppt" : "application/vnd.ms-powerpoint", ".ps" : "application/postscript", ".psd" : "image/vnd.adobe.photoshop", ".py" : "text/x-script.python", ".qt" : "video/quicktime", ".ra" : "audio/x-pn-realaudio", ".rake" : "text/x-script.ruby", ".ram" : "audio/x-pn-realaudio", ".rar" : "application/x-rar-compressed", ".rb" : "text/x-script.ruby", ".rdf" : "application/rdf+xml", ".roff" : "text/troff", ".rpm" : "application/x-redhat-package-manager", ".rss" : "application/rss+xml", ".rtf" : "application/rtf", ".ru" : "text/x-script.ruby", ".s" : "text/x-asm", ".sgm" : "text/sgml", ".sgml" : "text/sgml", ".sh" : "application/x-sh", ".sig" : "application/pgp-signature", ".snd" : "audio/basic", ".so" : "application/octet-stream", ".svg" : "image/svg+xml", ".svgz" : "image/svg+xml", ".swf" : "application/x-shockwave-flash", ".t" : "text/troff", ".tar" : "application/x-tar", ".tbz" : "application/x-bzip-compressed-tar", ".tci" : "application/x-topcloud", ".tcl" : "application/x-tcl", ".tex" : "application/x-tex", ".texi" : "application/x-texinfo", ".texinfo" : "application/x-texinfo", ".text" : "text/plain", ".tif" : "image/tiff", ".tiff" : "image/tiff", ".torrent" : "application/x-bittorrent", ".tr" : "text/troff", ".ttf" : "application/x-font-ttf", ".txt" : "text/plain", ".vcf" : "text/x-vcard", ".vcs" : "text/x-vcalendar", ".vrml" : "model/vrml", ".war" : "application/java-archive", ".wav" : "audio/x-wav", ".wma" : "audio/x-ms-wma", ".wmv" : "video/x-ms-wmv", ".wmx" : "video/x-ms-wmx", ".wrl" : "model/vrml", ".wsdl" : "application/wsdl+xml", ".xbm" : "image/x-xbitmap", ".xhtml" : "application/xhtml+xml", ".xls" : "application/vnd.ms-excel", ".xml" : "application/xml", ".xpm" : "image/x-xpixmap", ".xsl" : "application/xml", ".xslt" : "application/xslt+xml", ".yaml" : "text/yaml", ".yml" : "text/yaml", ".zip" : "application/zip" }};

// Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

} next(err); return; }

// Serve the file directly using buffers fs.readFile(filename, function (err, data) { if (err) { next(err); return; } res.writeHead(200, { "Content-Type": Mime.type(filename), "Content-Length": data.length, "Last-Modified": stat.mtime.toUTCString(), // Cache in browser for 1 year "Cache-Control": "public max-age=" + 31536000 }); res.end(data); }); }); }

".cc" : "text/x-c", ".chm" : "application/vnd.ms-htmlhelp", ".class" : "application/octet-stream", ".com" : "application/x-msdownload", ".conf" : "text/plain", ".cpp" : "text/x-c", ".crt" : "application/x-x509-ca-cert", ".css" : "text/css", ".csv" : "text/csv", ".cxx" : "text/x-c", ".deb" : "application/x-debian-package", ".der" : "application/x-x509-ca-cert", ".diff" : "text/x-diff", ".djv" : "image/vnd.djvu", ".djvu" : "image/vnd.djvu", ".dll" : "application/x-msdownload", ".dmg" : "application/octet-stream", ".doc" : "application/msword", ".dot" : "application/msword", ".dtd" : "application/xml-dtd", ".dvi" : "application/x-dvi", ".ear" : "application/java-archive", ".eml" : "message/rfc822", ".eps" : "application/postscript", ".exe" : "application/x-msdownload", ".f" : "text/x-fortran", ".f77" : "text/x-fortran", ".f90" : "text/x-fortran",

};

// Mini mime module for static file servingvar Mime = {

type: function getMime(path) { var index = path.lastIndexOf("."); if (index < 0) { return DEFAULT_MIME; } var type = Mime.TYPES[path.substring(index).toLowerCase()] || DEFAULT_MIME; return (/(text|javascript)/).test(type) ? type + "; charset=utf-8" : type; },

TYPES : { ".3gp" : "video/3gpp", ".a" : "application/octet-stream", ".ai" : "application/postscript", ".aif" : "audio/x-aiff", ".aiff" : "audio/x-aiff", ".asc" : "application/pgp-signature", ".asf" : "video/x-ms-asf", ".asm" : "text/x-asm", ".asx" : "video/x-ms-asf", ".atom" : "application/atom+xml", ".au" : "audio/basic", ".avi" : "video/x-msvideo", ".bat" : "application/x-msdownload", ".bin" : "application/octet-stream",

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

static.js ".flv" : "video/x-flv", ".for" : "text/x-fortran", ".gem" : "application/octet-stream", ".gemspec" : "text/x-script.ruby", ".gif" : "image/gif", ".gz" : "application/x-gzip", ".h" : "text/x-c", ".hh" : "text/x-c", ".htm" : "text/html", ".html" : "text/html", ".ico" : "image/vnd.microsoft.icon", ".ics" : "text/calendar", ".ifb" : "text/calendar", ".iso" : "application/octet-stream", ".jar" : "application/java-archive", ".java" : "text/x-java-source", ".jnlp" : "application/x-java-jnlp-file", ".jpeg" : "image/jpeg", ".jpg" : "image/jpeg", ".js" : "application/javascript", ".json" : "application/json", ".log" : "text/plain", ".m3u" : "audio/x-mpegurl", ".m4v" : "video/mp4", ".man" : "text/troff", ".mathml" : "application/mathml+xml", ".mbox" : "application/mbox", ".mdoc" : "text/troff", ".me" : "text/troff", ".mid" : "audio/midi", ".midi" : "audio/midi", ".mime" : "message/rfc822", ".mml" : "application/mathml+xml", ".mng" : "video/x-mng", ".mov" : "video/quicktime", ".mp3" : "audio/mpeg", ".mp4" : "video/mp4", ".mp4v" : "video/mp4", ".mpeg" : "video/mpeg", ".mpg" : "video/mpeg", ".ms" : "text/troff", ".msi" : "application/x-msdownload", ".odp" : "application/vnd.oasis.opendocument.presentation", ".ods" : "application/vnd.oasis.opendocument.spreadsheet", ".odt" : "application/vnd.oasis.opendocument.text", ".ogg" : "application/ogg", ".p" : "text/x-pascal", ".pas" : "text/x-pascal", ".pbm" : "image/x-portable-bitmap", ".pdf" : "application/pdf", ".pem" : "application/x-x509-ca-cert", ".pgm" : "image/x-portable-graymap", ".pgp" : "application/pgp-encrypted", ".pkg" : "application/octet-stream", ".pl" : "text/x-script.perl", ".pm" : "text/x-script.perl-module", ".png" : "image/png", ".pnm" : "image/x-portable-anymap", ".ppm" : "image/x-portable-pixmap", ".pps" : "application/vnd.ms-powerpoint", ".ppt" : "application/vnd.ms-powerpoint", ".ps" : "application/postscript", ".psd" : "image/vnd.adobe.photoshop", ".py" : "text/x-script.python", ".qt" : "video/quicktime", ".ra" : "audio/x-pn-realaudio", ".rake" : "text/x-script.ruby", ".ram" : "audio/x-pn-realaudio", ".rar" : "application/x-rar-compressed", ".rb" : "text/x-script.ruby", ".rdf" : "application/rdf+xml", ".roff" : "text/troff", ".rpm" : "application/x-redhat-package-manager", ".rss" : "application/rss+xml", ".rtf" : "application/rtf", ".ru" : "text/x-script.ruby", ".s" : "text/x-asm", ".sgm" : "text/sgml", ".sgml" : "text/sgml", ".sh" : "application/x-sh", ".sig" : "application/pgp-signature", ".snd" : "audio/basic", ".so" : "application/octet-stream", ".svg" : "image/svg+xml", ".svgz" : "image/svg+xml", ".swf" : "application/x-shockwave-flash", ".t" : "text/troff", ".tar" : "application/x-tar", ".tbz" : "application/x-bzip-compressed-tar", ".tci" : "application/x-topcloud", ".tcl" : "application/x-tcl", ".tex" : "application/x-tex", ".texi" : "application/x-texinfo", ".texinfo" : "application/x-texinfo", ".text" : "text/plain", ".tif" : "image/tiff", ".tiff" : "image/tiff", ".torrent" : "application/x-bittorrent", ".tr" : "text/troff", ".ttf" : "application/x-font-ttf", ".txt" : "text/plain", ".vcf" : "text/x-vcard", ".vcs" : "text/x-vcalendar", ".vrml" : "model/vrml", ".war" : "application/java-archive", ".wav" : "audio/x-wav", ".wma" : "audio/x-ms-wma", ".wmv" : "video/x-ms-wmv", ".wmx" : "video/x-ms-wmx", ".wrl" : "model/vrml", ".wsdl" : "application/wsdl+xml", ".xbm" : "image/x-xbitmap", ".xhtml" : "application/xhtml+xml", ".xls" : "application/vnd.ms-excel", ".xml" : "application/xml", ".xpm" : "image/x-xpixmap", ".xsl" : "application/xml", ".xslt" : "application/xslt+xml", ".yaml" : "text/yaml", ".yml" : "text/yaml", ".zip" : "application/zip" }};

// Buffer any events that fire while waiting on the stat. var events = []; function onData() { events.push(["data"].concat(Array.prototype.slice.call(arguments))); } function onEnd() { events.push(["end"].concat(Array.prototype.slice.call(arguments))); } req.addListener("data", onData); req.addListener("end", onEnd);

fs.stat(filename, function (err, stat) {

// Stop buffering events req.removeListener("data", onData); req.removeListener("end", onEnd);

// Fall through for missing files, thow error for other problems if (err) { if (err.errno === process.ENOENT) { next(); // Refire the buffered events events.forEach(function (args) { req.emit.apply(req, args); }); return;

} next(err); return; }

// Serve the file directly using buffers fs.readFile(filename, function (err, data) { if (err) { next(err); return; } res.writeHead(200, { "Content-Type": Mime.type(filename), "Content-Length": data.length, "Last-Modified": stat.mtime.toUTCString(), // Cache in browser for 1 year "Cache-Control": "public max-age=" + 31536000 }); res.end(data); }); }); }

".bmp" : "image/bmp", ".bz2" : "application/x-bzip2", ".c" : "text/x-c", ".cab" : "application/vnd.ms-cab-compressed",

".cc" : "text/x-c", ".chm" : "application/vnd.ms-htmlhelp", ".class" : "application/octet-stream", ".com" : "application/x-msdownload", ".conf" : "text/plain", ".cpp" : "text/x-c", ".crt" : "application/x-x509-ca-cert", ".css" : "text/css", ".csv" : "text/csv", ".cxx" : "text/x-c", ".deb" : "application/x-debian-package", ".der" : "application/x-x509-ca-cert", ".diff" : "text/x-diff", ".djv" : "image/vnd.djvu", ".djvu" : "image/vnd.djvu", ".dll" : "application/x-msdownload", ".dmg" : "application/octet-stream", ".doc" : "application/msword", ".dot" : "application/msword", ".dtd" : "application/xml-dtd", ".dvi" : "application/x-dvi", ".ear" : "application/java-archive", ".eml" : "message/rfc822", ".eps" : "application/postscript", ".exe" : "application/x-msdownload", ".f" : "text/x-fortran", ".f77" : "text/x-fortran", ".f90" : "text/x-fortran",

};

// Mini mime module for static file servingvar Mime = {

type: function getMime(path) { var index = path.lastIndexOf("."); if (index < 0) { return DEFAULT_MIME; } var type = Mime.TYPES[path.substring(index).toLowerCase()] || DEFAULT_MIME; return (/(text|javascript)/).test(type) ? type + "; charset=utf-8" : type; },

TYPES : { ".3gp" : "video/3gpp", ".a" : "application/octet-stream", ".ai" : "application/postscript", ".aif" : "audio/x-aiff", ".aiff" : "audio/x-aiff", ".asc" : "application/pgp-signature", ".asf" : "video/x-ms-asf", ".asm" : "text/x-asm", ".asx" : "video/x-ms-asf", ".atom" : "application/atom+xml", ".au" : "audio/basic", ".avi" : "video/x-msvideo", ".bat" : "application/x-msdownload", ".bin" : "application/octet-stream",

var fs = require('fs'), Url = require('url'), Path = require('path');

var lifetime = 1000 * 60 * 60; // 1 hour browser cache lifetime

var DEFAULT_MIME = 'application/octet-stream';

module.exports = {

setup: function (env) { this.root = this.root || process.cwd(); },

handle: function (err, req, res, next) { // Skip on error if (err) { next(); return; } var url = Url.parse(req.url);

var pathname = url.pathname.replace(/\.\.+/g, '.'), filename = Path.join(this.root, pathname);

if (filename[filename.length - 1] === "/") { filename += "index.html"; }

Saturday, June 5, 2010

• Authentication

• Authorization

• Body Decoder

• Cache

• Conditional Get

• Debug

• Error Handler

• Gzip

• Log

• Method Override

• Response Time

• Session

Built-in Filter Modules

Saturday, June 5, 2010

• Static

• Rest

• Router

• PubSub

• Cache Manifest

• Direct

• JSON-RPC

• More...

Built-in Data Providers

Saturday, June 5, 2010

Raphaël JSRaphaël is a small JavaScript library that should simplify your work with vector graphics on the web.

Saturday, June 5, 2010

Multi-Touch Vectors

http://vimeo.com/11610421

Saturday, June 5, 2010

multitouch-demo.jswindow.onload = function () { var R = Raphael(0, 0, "100%", "100%"), r = R.circle(100, 100, 50), g = R.circle(210, 100, 50), b = R.circle(320, 100, 50), p = R.circle(430, 100, 50); var start = function () { this.ox = this.attr("cx"); this.oy = this.attr("cy"); this.animate({r: 70, opacity: .25}, 500, ">"); }, move = function (dx, dy) { this.attr({cx: this.ox + dx, cy: this.oy + dy}); }, up = function () { this.animate({r: 50, opacity: .5}, 500, ">"); }; R.set(r, g, b, p).drag(move, start, up);};

Saturday, June 5, 2010

Creating Shapesvar R = Raphael(0, 0, "100%", "100%"), r = R.circle(100, 100, 50) .attr({fill: "hsb(0, 1, 1)"}), g = R.circle(210, 100, 50) .attr({fill: "hsb(.3, 1, 1)"}), b = R.circle(320, 100, 50) .attr({fill: "hsb(.6, 1, 1)"}), p = R.circle(430, 100, 50) .attr({fill: "hsb(.8, 1, 1)"});

Saturday, June 5, 2010

Attaching Eventsfunction start() { this.ox = this.attr("cx"); this.oy = this.attr("cy"); this.animate({r: 70, opacity: .25}, 500, ">");}function move(dx, dy) { this.attr({cx: this.ox + dx, cy: this.oy + dy});}function up() { this.animate({r: 50, opacity: .5}, 500, ">");}R.set(r, g, b, p).drag(move, start, up);

Saturday, June 5, 2010

Let’s combine them!

Saturday, June 5, 2010

• Serving static assets (HTML, CSS, JS)

• Live Interaction (Pub Sub)

• Performance Tweaks (Cache, Gzip)

• Offline Mode (Cache Manifest)

• HTTP Request Logging

Saturday, June 5, 2010

app.js (stack)require.paths.unshift("./lib");var Connect = require('connect');var root = __dirname + "/public";

module.exports = Connect.createServer([ {filter: "log"}, {filter: "body-decoder"}, {provider: "pubsub", route: "/stream", logic: Backend}, {filter: "conditional-get"}, {filter: "cache"}, {filter: "gzip"}, {provider: "cache-manifest", root: root}, {provider: "static", root: root}]);

Saturday, June 5, 2010

app.js (Backend)var Backend = { subscribe: function (subscriber) { if (subscribers.indexOf(subscriber) < 0) { subscribers.push(subscriber); } }, unsubscribe: function (subscriber) { var pos = subscribers.indexOf(subscriber); if (pos >= 0) { subscribers.slice(pos); } }, publish: function (message, callback) { subscribers.forEach(function (subscriber) { subscriber.send(message); }); callback(); }};

Saturday, June 5, 2010

index.html<!DOCTYPE html><html lang="en" manifest="cache.manifest"><head> <meta charset="utf-8" /> <meta name="apple-mobile-web-app-capable" content="yes"> <title>Node + Raphaël</title> <link rel="stylesheet" href="style.css" type="text/css" /> <script src="raphael.js"></script> <script src="client.js"></script></head><body> <div id="holder"></div> </body></html>

Saturday, June 5, 2010

Demo Time!

Saturday, June 5, 2010

AnyQuestions

?

Saturday, June 5, 2010

top related