text: // client.express.js JavaScript Routing, version: 0.2.3
  // (c) 2011 Mark Nijhof
  //
  //  Released under MIT license.
  //
  ClientExpress={};ClientExpress.createServer=function(){return new ClientExpress.Server};ClientExpress.supported=function(){return typeof window.history.pushState=="function"};
  ClientExpress.Server=function(){var b=0,a=function(){this.version="0.2.3";this.id=[(new Date).valueOf(),b++].join("-");this.settings={};this.templateEngines={};this.router=new ClientExpress.Router;this.eventListener=new ClientExpress.EventListener;this.log=new ClientExpress.Logger;this.session={};this.content_target_element=document.childNodes[1];this.setup_functions=[]};a.prototype.logger=function(){var c=this;return function(){c.log.enable()}};a.prototype.content_target_area=function(c){var a=
  this;return function(){var b=document.getElementById?document.getElementById(c):document.all?document.all[c]:document.layers?document.layers[c]:null;a.content_target_element=b||document.childNodes[1];a.content_target_element==document.childNodes[1]&&a.log.warning('The element "',c,'" could not be located as a content target!')}};a.prototype.configure=function(c,a){typeof c=="function"?this.setup_functions.push(c):this.setup_functions.push(function(){server.enabled(c)&&a.call()})};a.prototype.use=
  function(c,a){var b=this;if(typeof c=="function")c.call();else{c[c.length-1]==="/"&&(c=c.substring(0,c.length-1));var g=function(c,a){if(a=="/")return c;if(a.substr(0,1)!="/")return c+"/"+a;return c+a},h=a.router.routes;ClientExpress.utils.forEach(h.get,function(a){e(b,a.method,g(c,a.path),a.action,c)});ClientExpress.utils.forEach(h.post,function(a){e(b,a.method,g(c,a.path),a.action,c)});ClientExpress.utils.forEach(h.put,function(a){e(b,a.method,g(c,a.path),a.action,c)});ClientExpress.utils.forEach(h.del,
  function(a){e(b,a.method,g(c,a.path),a.action,c)})}};a.prototype.set=function(c,a){if(a===void 0)if(this.settings.hasOwnProperty(c))return this.settings[c];else{if(this.parent)return this.parent.set(c)}else return this.settings[c]=a,this};a.prototype.enable=function(c){this.settings.hasOwnProperty(c);this.settings[c]=!0};a.prototype.disable=function(c){this.settings.hasOwnProperty(c);this.settings[c]=!1};a.prototype.enabled=function(c){return this.settings.hasOwnProperty(c)&&this.settings[c]};a.prototype.disabled=
  function(c){return this.settings.hasOwnProperty(c)&&!this.settings[c]};a.prototype.register=function(c,a){if(a===void 0)if(this.templateEngines.hasOwnProperty(c))return this.templateEngines[c];else{if(this.parent)return this.parent.set(c)}else return this.templateEngines[c]=a,this};a.prototype.get=function(c,a){return e(this,"get",c,a,"")};a.prototype.post=function(c,a){return e(this,"post",c,a,"")};a.prototype.put=function(c,a){return e(this,"put",c,a,"")};a.prototype.del=function(c,a){return e(this,
  "del",c,a,"")};var e=function(c,a,b,e,h){c.log.information(" + ",a.toUpperCase().lpad("    "),b);c.router.registerRoute(a,b,e,h);return c};a.prototype.processRequest=function(c){var a=this.router.match(c.method,c.path);if(a.resolved()){this.log.information(200,c.method.toUpperCase().lpad("    "),c.path);c.attachRoute(a);var b=new ClientExpress.Response(c,this);!c.isHistoryRequest&&!c.isRedirect&&this.pushState(c);a.action(c,b);b.process()}else this.log.information(404,c.method.toUpperCase().lpad("    "),
  c.path),c.delegateToServer()};a.prototype.pushState=function(a){history.pushState(a,a.title,a.location())};a.prototype.replaceState=function(a){history.replaceState(a,a.title,a.location())};a.prototype.listen=function(){if(ClientExpress.supported()){var a=this;ClientExpress.onDomReady(function(){ClientExpress.utils.forEach(a.setup_functions,function(a){a.call()});a.eventListener.registerEventHandlers(a);var b=new ClientExpress.Request({method:"get",fullPath:window.location.pathname,title:document.title,
  session:a.session,delegateToServer:function(){window.location.pathname=window.location.pathname}});a.replaceState(b);a.log.information("Listening");b=a.router.routes;ClientExpress.utils.forEach(b.get,function(b){a.log.information("Route loaded:",b.method.toUpperCase().lpad("    "),b.path)});ClientExpress.utils.forEach(b.post,function(b){a.log.information("Route loaded:",b.method.toUpperCase().lpad("    "),b.path)});ClientExpress.utils.forEach(b.put,function(b){a.log.information("Route loaded:",b.method.toUpperCase().lpad("    "),
  b.path)});ClientExpress.utils.forEach(b.del,function(b){a.log.information("Route loaded:",b.method.toUpperCase().lpad("    "),b.path)})})}else a.log.information("Not supported on this browser")};return a}();
  ClientExpress.Route=function(){function b(a,c,b){if(a instanceof RegExp)return a;a=a.concat("/?").replace(/\/\(/g,"(?:/").replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,function(a,b,e,d,j,i){c.push({name:d,optional:!!i});b=b||"";return""+(i?"":b)+"(?:"+(i?b:"")+(e||"")+(j||"([^/]+?)")+")"+(i||"")}).replace(/([\/.])/g,"\\$1").replace(/\*/g,"(.+)");return RegExp("^"+a+"$",b?"":"i")}var a=function(a,c,d,f,g){this.resolved=function(){return!0};this.method=a;this.path=c;this.action=d;this.base_path=f;
  this.params=[];this.regexp=b(c,this.keys=[],g.sensitive)};a.prototype.match=function(a){return this.regexp.exec(a)};return a}();
  ClientExpress.Router=function(){var b=function(){this.routes={get:[],post:[],put:[],del:[]}};b.prototype.match=function(a,b){for(var c=this.routes[a].length,d=0;d<c;++d){var f=this.routes[a][d];if(captures=f.match(b)){keys=f.keys;f.params=[];c=1;for(d=captures.length;c<d;++c){var g=keys[c-1],h="string"==typeof captures[c]?decodeURIComponent(captures[c]):captures[c];g?f.params[g.name]=h:f.params.push(h)}return f}}return{resolved:function(){return!1}}};b.prototype.registerRoute=function(a,b,c,d){this.routes[a].push(new ClientExpress.Route(a,
  b,c,d,{sensitive:!1}))};return b}();
  ClientExpress.EventListener=function(){var b=function(){};b.prototype.registerEventHandlers=function(b){a(b);e(b);c(b)};var a=function(a){document.onclick=function(c){c=c||window.event;var b=c.target||c.srcElement;if(b.tagName.toLowerCase()=="a")return c=new ClientExpress.Request({method:"get",fullPath:b.href,title:b.title||"",session:a.session,delegateToServer:function(){b.href.indexOf("://")!=-1?window.location=b.href:window.location.pathname=b.href}}),a.processRequest(c),!1}},e=function(a){document.onsubmit=
  function(c){c=c||window.event;var b=c.target||c.srcElement;if(b.tagName.toLowerCase()=="form")return c=new ClientExpress.Request({method:b.method,fullPath:[b.action,ClientExpress.utils.serializeArray(b)].join("?"),title:b.title,session:a.session,delegateToServer:function(){b.submit()}}),a.processRequest(c),!1}},c=function(a){window.onpopstate=function(c){if(c.state)c=c.state,c.__proto__=ClientExpress.Request.prototype,c.HistoryRequest(),a.processRequest(c)}};return b}();
  ClientExpress.Request=function(){var b=function(a){var b=this;this.isHistoryRequest=!1;this.session=a.session;this.body={};this.title=a.title;this.isRedirect=a.isRedirect||!1;(this.queryString=a.fullPath.split("?")[1])&&ClientExpress.utils.forEach(this.queryString.split("&"),function(a){var d=a.split("=")[0];a=a.split("=")[1];var f;if(f=/^(\w+)\[(\w+)\]/.exec(d)){var g=f[1];d=f[2];f=b.body[g]||{};f[d]=a;b.body[g]=f}else b.body[d]=a});this.method=(this.body._method||a.method).toLowerCase();this.path=
  a.fullPath.replace(/\?.+$/,"").replace(window.location.protocol+"//"+window.location.host,"");this.delegateToServer=a.delegateToServer||function(){}};b.prototype.attachRoute=function(a){this.params=a.params;this.base_path=a.base_path};b.prototype.location=function(){return this.method==="get"?this.path:""};b.prototype.HistoryRequest=function(){this.isHistoryRequest=!0};return b}();
  ClientExpress.Response=function(){var b=function(a,b){this.request=a;this.server=b;this.output=this.redirect_path=""};b.prototype.send=function(a){this.output=a};b.prototype.render=function(a,b){var c=this.server.settings["view engine"]||"";a=(this.server.settings.views||"")+a;a.lastIndexOf(".")!=-1&&a.lastIndexOf(".")<=4&&(c=a.substr(a.lastIndexOf(".")-1,a.length),a=a.substr(0,a.lastIndexOf(".")-1));c=c||this.server.settings["view engine"]||"";c!=""&&(c="."+c,a+=c);this.send(this.server.templateEngines[c].compile(a,
  b))};b.prototype.redirect=function(a){this.redirect_path=(a.substr(0,1)=="/"?this.request.base_path:"")+a};b.prototype.process=function(){var a=this;if(a.redirect_path!=""){a.server.log.information(302,"GET ",a.redirect_path);var b=new ClientExpress.Request({method:"get",fullPath:a.redirect_path,title:"",isRedirect:!0,session:a.server.session,delegateToServer:function(){window.location.pathname=a.redirect_path}});a.server.processRequest(b)}else a.server.content_target_element.innerHTML=a.output};
  return b}();
  ClientExpress.Logger=function(){var b=function(){this.log_enabled=!1};b.prototype.enable=function(){this.log_enabled=!0};b.prototype.error=function(){this.log_enabled&&window.console&&console.error(ClientExpress.utils.toArray(arguments).join(" "))};b.prototype.information=function(){this.log_enabled&&window.console&&console.log(ClientExpress.utils.toArray(arguments).join(" "))};b.prototype.warning=function(){this.log_enabled&&window.console&&console.warn(ClientExpress.utils.toArray(arguments).join(" "))};return b}();
  String.prototype.rpad=function(b){return b.substr(0,b.length-this.length)+this};String.prototype.lpad=function(b){return this+b.substr(0,b.length-this.length)};
  ClientExpress.utils=function(){return{every:Array.prototype.every?function(b,a,e){return b.every(a,e)}:function(b,a,e){if(b===void 0||b===null)throw new TypeError;b=Object(b);var c=b.length>>>0;if(typeof a!=="function")throw new TypeError;for(var d=0;d<c;d++)if(d in b&&!a.call(e,b[d],d,b))return!1;return!0},forEach:Array.prototype.forEach?function(b,a,e){return b.forEach(a,e)}:function(b,a,e){if(b===void 0||b===null)throw new TypeError;b=Object(b);var c=b.length>>>0;if(typeof a!=="function")throw new TypeError;
  for(var d=0;d<c;d++)d in b&&a.call(e,b[d],d,b)},filter:Array.prototype.filter?function(b,a,e){return b.filter(a,e)}:function(b,a,e){if(b===void 0||b===null)throw new TypeError;b=Object(b);var c=b.length>>>0;if(typeof a!=="function")throw new TypeError;for(var d=[],f=0;f<c;f++)if(f in b){var g=b[f];a.call(e,g,f,b)&&d.push(g)}return d},map:Array.prototype.map?function(b,a,e){return b.map(a,e)}:function(b,a,e){if(b===void 0||b===null)throw new TypeError;b=Object(b);var c=b.length>>>0;if(typeof a!=="function")throw new TypeError;
  for(var d=Array(c),f=0;f<c;f++)f in b&&(d[f]=a.call(e,b[f],f,b));return d},toArray:function(b,a){return Array.prototype.slice.call(b,a||0)},serializeArray:function(b){var a="";b=b.getElementsByTagName("*");for(var e=0;e<b.length;e++){var c=b[e];if(!c.disabled&&c.name&&c.name.length>0)switch(c.tagName.toLowerCase()){case "input":switch(c.type){case "checkbox":case "radio":c.checked&&(a.length>0&&(a+="&"),a+=c.name+"="+encodeURIComponent(c.value));break;case "hidden":case "password":case "text":a.length>
  0&&(a+="&"),a+=c.name+"="+encodeURIComponent(c.value)}break;case "select":case "textarea":a.length>0&&(a+="&"),a+=c.name+"="+encodeURIComponent(c.value)}}return a}}}();
  