Update requirejs to 2.0.6
Update requirejs to 2.0.6

--- a/js/ext/require.js
+++ b/js/ext/require.js
@@ -1,32 +1,36 @@
 /*
- RequireJS 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
+ RequireJS 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  Available via the MIT or new BSD license.
  see: http://github.com/jrburke/requirejs for details
 */
 var requirejs,require,define;
-(function(){function J(a){return M.call(a)==="[object Function]"}function E(a){return M.call(a)==="[object Array]"}function Z(a,c,h){for(var k in c)if(!(k in K)&&(!(k in a)||h))a[k]=c[k];return d}function N(a,c,d){a=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+a);if(d)a.originalError=d;return a}function $(a,c,d){var k,j,q;for(k=0;q=c[k];k++){q=typeof q==="string"?{name:q}:q;j=q.location;if(d&&(!j||j.indexOf("/")!==0&&j.indexOf(":")===-1))j=d+"/"+(j||q.name);a[q.name]={name:q.name,location:j||
-q.name,main:(q.main||"main").replace(ea,"").replace(aa,"")}}}function V(a,c){a.holdReady?a.holdReady(c):c?a.readyWait+=1:a.ready(!0)}function fa(a){function c(b,l){var f,a;if(b&&b.charAt(0)===".")if(l){p.pkgs[l]?l=[l]:(l=l.split("/"),l=l.slice(0,l.length-1));f=b=l.concat(b.split("/"));var c;for(a=0;c=f[a];a++)if(c===".")f.splice(a,1),a-=1;else if(c==="..")if(a===1&&(f[2]===".."||f[0]===".."))break;else a>0&&(f.splice(a-1,2),a-=2);a=p.pkgs[f=b[0]];b=b.join("/");a&&b===f+"/"+a.main&&(b=f)}else b.indexOf("./")===
-0&&(b=b.substring(2));return b}function h(b,l){var f=b?b.indexOf("!"):-1,a=null,d=l?l.name:null,i=b,e,h;f!==-1&&(a=b.substring(0,f),b=b.substring(f+1,b.length));a&&(a=c(a,d));b&&(a?e=(f=m[a])&&f.normalize?f.normalize(b,function(b){return c(b,d)}):c(b,d):(e=c(b,d),h=E[e],h||(h=g.nameToUrl(e,null,l),E[e]=h)));return{prefix:a,name:e,parentMap:l,url:h,originalName:i,fullName:a?a+"!"+(e||""):e}}function k(){var b=!0,l=p.priorityWait,f,a;if(l){for(a=0;f=l[a];a++)if(!s[f]){b=!1;break}b&&delete p.priorityWait}return b}
-function j(b,l,f){return function(){var a=ga.call(arguments,0),c;if(f&&J(c=a[a.length-1]))c.__requireJsBuild=!0;a.push(l);return b.apply(null,a)}}function q(b,l){var a=j(g.require,b,l);Z(a,{nameToUrl:j(g.nameToUrl,b),toUrl:j(g.toUrl,b),defined:j(g.requireDefined,b),specified:j(g.requireSpecified,b),isBrowser:d.isBrowser});return a}function o(b){var l,a,c,C=b.callback,i=b.map,e=i.fullName,ba=b.deps;c=b.listeners;if(C&&J(C)){if(p.catchError.define)try{a=d.execCb(e,b.callback,ba,m[e])}catch(k){l=k}else a=
-d.execCb(e,b.callback,ba,m[e]);if(e)(C=b.cjsModule)&&C.exports!==void 0&&C.exports!==m[e]?a=m[e]=b.cjsModule.exports:a===void 0&&b.usingExports?a=m[e]:(m[e]=a,F[e]&&(Q[e]=!0))}else e&&(a=m[e]=C,F[e]&&(Q[e]=!0));if(D[b.id])delete D[b.id],b.isDone=!0,g.waitCount-=1,g.waitCount===0&&(I=[]);delete R[e];if(d.onResourceLoad&&!b.placeholder)d.onResourceLoad(g,i,b.depArray);if(l)return a=(e?h(e).url:"")||l.fileName||l.sourceURL,c=l.moduleTree,l=N("defineerror",'Error evaluating module "'+e+'" at location "'+
-a+'":\n'+l+"\nfileName:"+a+"\nlineNumber: "+(l.lineNumber||l.line),l),l.moduleName=e,l.moduleTree=c,d.onError(l);for(l=0;C=c[l];l++)C(a)}function r(b,a){return function(f){b.depDone[a]||(b.depDone[a]=!0,b.deps[a]=f,b.depCount-=1,b.depCount||o(b))}}function u(b,a){var f=a.map,c=f.fullName,h=f.name,i=L[b]||(L[b]=m[b]),e;if(!a.loading)a.loading=!0,e=function(b){a.callback=function(){return b};o(a);s[a.id]=!0;w()},e.fromText=function(b,a){var l=O;s[b]=!1;g.scriptCount+=1;g.fake[b]=!0;l&&(O=!1);d.exec(a);
-l&&(O=!0);g.completeLoad(b)},c in m?e(m[c]):i.load(h,q(f.parentMap,!0),e,p)}function v(b){D[b.id]||(D[b.id]=b,I.push(b),g.waitCount+=1)}function B(b){this.listeners.push(b)}function t(b,a){var f=b.fullName,c=b.prefix,d=c?L[c]||(L[c]=m[c]):null,i,e;f&&(i=R[f]);if(!i&&(e=!0,i={id:(c&&!d?M++ +"__p@:":"")+(f||"__r@"+M++),map:b,depCount:0,depDone:[],depCallbacks:[],deps:[],listeners:[],add:B},y[i.id]=!0,f&&(!c||L[c])))R[f]=i;c&&!d?(f=t(h(c),!0),f.add(function(){var a=h(b.originalName,b.parentMap),a=t(a,
-!0);i.placeholder=!0;a.add(function(b){i.callback=function(){return b};o(i)})})):e&&a&&(s[i.id]=!1,g.paused.push(i),v(i));return i}function x(b,a,f,c){var b=h(b,c),d=b.name,i=b.fullName,e=t(b),k=e.id,j=e.deps,n;if(i){if(i in m||s[k]===!0||i==="jquery"&&p.jQuery&&p.jQuery!==f().fn.jquery)return;y[k]=!0;s[k]=!0;i==="jquery"&&f&&S(f())}e.depArray=a;e.callback=f;for(f=0;f<a.length;f++)if(k=a[f])k=h(k,d?b:c),n=k.fullName,a[f]=n,n==="require"?j[f]=q(b):n==="exports"?(j[f]=m[i]={},e.usingExports=!0):n===
-"module"?e.cjsModule=j[f]={id:d,uri:d?g.nameToUrl(d,null,c):void 0,exports:m[i]}:n in m&&!(n in D)&&(!(i in F)||i in F&&Q[n])?j[f]=m[n]:(i in F&&(F[n]=!0,delete m[n],T[k.url]=!1),e.depCount+=1,e.depCallbacks[f]=r(e,f),t(k,!0).add(e.depCallbacks[f]));e.depCount?v(e):o(e)}function n(b){x.apply(null,b)}function z(b,a){if(!b.isDone){var c=b.map.fullName,d=b.depArray,g,i,e,k;if(c){if(a[c])return m[c];a[c]=!0}if(d)for(g=0;g<d.length;g++)if(i=d[g])if((e=h(i).prefix)&&(k=D[e])&&z(k,a),(e=D[i])&&!e.isDone&&
-s[i])i=z(e,a),b.depCallbacks[g](i);return c?m[c]:void 0}}function A(){var b=p.waitSeconds*1E3,a=b&&g.startTime+b<(new Date).getTime(),b="",c=!1,h=!1,j;if(!(g.pausedCount>0)){if(p.priorityWait)if(k())w();else return;for(j in s)if(!(j in K)&&(c=!0,!s[j]))if(a)b+=j+" ";else{h=!0;break}if(c||g.waitCount){if(a&&b)return j=N("timeout","Load timeout for modules: "+b),j.requireType="timeout",j.requireModules=b,d.onError(j);if(h||g.scriptCount){if((G||ca)&&!W)W=setTimeout(function(){W=0;A()},50)}else{if(g.waitCount){for(H=
-0;b=I[H];H++)z(b,{});g.paused.length&&w();X<5&&(X+=1,A())}X=0;d.checkReadyState()}}}}var g,w,p={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},catchError:{}},P=[],y={require:!0,exports:!0,module:!0},E={},m={},s={},D={},I=[],T={},M=0,R={},L={},F={},Q={},Y=0;S=function(b){if(!g.jQuery&&(b=b||(typeof jQuery!=="undefined"?jQuery:null))&&!(p.jQuery&&b.fn.jquery!==p.jQuery)&&("holdReady"in b||"readyWait"in b))if(g.jQuery=b,n(["jquery",[],function(){return jQuery}]),g.scriptCount)V(b,!0),g.jQueryIncremented=
-!0};w=function(){var b,a,c,h,j,i;Y+=1;if(g.scriptCount<=0)g.scriptCount=0;for(;P.length;)if(b=P.shift(),b[0]===null)return d.onError(N("mismatch","Mismatched anonymous define() module: "+b[b.length-1]));else n(b);if(!p.priorityWait||k())for(;g.paused.length;){j=g.paused;g.pausedCount+=j.length;g.paused=[];for(h=0;b=j[h];h++)a=b.map,c=a.url,i=a.fullName,a.prefix?u(a.prefix,b):!T[c]&&!s[i]&&(d.load(g,i,c),c.indexOf("empty:")!==0&&(T[c]=!0));g.startTime=(new Date).getTime();g.pausedCount-=j.length}Y===
-1&&A();Y-=1};g={contextName:a,config:p,defQueue:P,waiting:D,waitCount:0,specified:y,loaded:s,urlMap:E,urlFetched:T,scriptCount:0,defined:m,paused:[],pausedCount:0,plugins:L,needFullExec:F,fake:{},fullExec:Q,managerCallbacks:R,makeModuleMap:h,normalize:c,configure:function(b){var a,c,d;b.baseUrl&&b.baseUrl.charAt(b.baseUrl.length-1)!=="/"&&(b.baseUrl+="/");a=p.paths;d=p.pkgs;Z(p,b,!0);if(b.paths){for(c in b.paths)c in K||(a[c]=b.paths[c]);p.paths=a}if((a=b.packagePaths)||b.packages){if(a)for(c in a)c in
-K||$(d,a[c],c);b.packages&&$(d,b.packages);p.pkgs=d}if(b.priority)c=g.requireWait,g.requireWait=!1,g.takeGlobalQueue(),w(),g.require(b.priority),w(),g.requireWait=c,p.priorityWait=b.priority;if(b.deps||b.callback)g.require(b.deps||[],b.callback)},requireDefined:function(b,a){return h(b,a).fullName in m},requireSpecified:function(b,a){return h(b,a).fullName in y},require:function(b,c,f){if(typeof b==="string"){if(J(c))return d.onError(N("requireargs","Invalid require call"));if(d.get)return d.get(g,
-b,c);c=h(b,c);b=c.fullName;return!(b in m)?d.onError(N("notloaded","Module name '"+c.fullName+"' has not been loaded yet for context: "+a)):m[b]}(b&&b.length||c)&&x(null,b,c,f);if(!g.requireWait)for(;!g.scriptCount&&g.paused.length;)g.takeGlobalQueue(),w();return g.require},takeGlobalQueue:function(){U.length&&(ha.apply(g.defQueue,[g.defQueue.length-1,0].concat(U)),U=[])},completeLoad:function(b){var a;for(g.takeGlobalQueue();P.length;)if(a=P.shift(),a[0]===null){a[0]=b;break}else if(a[0]===b)break;
-else n(a),a=null;a?n(a):n([b,[],b==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null]);S();d.isAsync&&(g.scriptCount-=1);w();d.isAsync||(g.scriptCount-=1)},toUrl:function(a,c){var d=a.lastIndexOf("."),h=null;d!==-1&&(h=a.substring(d,a.length),a=a.substring(0,d));return g.nameToUrl(a,h,c)},nameToUrl:function(a,h,f){var j,k,i,e,m=g.config,a=c(a,f&&f.fullName);if(d.jsExtRegExp.test(a))h=a+(h?h:"");else{j=m.paths;k=m.pkgs;f=a.split("/");for(e=f.length;e>0;e--)if(i=f.slice(0,e).join("/"),
-j[i]){f.splice(0,e,j[i]);break}else if(i=k[i]){a=a===i.name?i.location+"/"+i.main:i.location;f.splice(0,e,a);break}h=f.join("/")+(h||".js");h=(h.charAt(0)==="/"||h.match(/^\w+:/)?"":m.baseUrl)+h}return m.urlArgs?h+((h.indexOf("?")===-1?"?":"&")+m.urlArgs):h}};g.jQueryCheck=S;g.resume=w;return g}function ia(){var a,c,d;if(n&&n.readyState==="interactive")return n;a=document.getElementsByTagName("script");for(c=a.length-1;c>-1&&(d=a[c]);c--)if(d.readyState==="interactive")return n=d;return null}var ja=
-/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ka=/require\(\s*["']([^'"\s]+)["']\s*\)/g,ea=/^\.\//,aa=/\.js$/,M=Object.prototype.toString,r=Array.prototype,ga=r.slice,ha=r.splice,G=!!(typeof window!=="undefined"&&navigator&&document),ca=!G&&typeof importScripts!=="undefined",la=G&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,da=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",K={},t={},U=[],n=null,X=0,O=!1,d,r={},I,v,x,y,u,z,A,H,B,S,W;if(typeof define==="undefined"){if(typeof requirejs!==
-"undefined")if(J(requirejs))return;else r=requirejs,requirejs=void 0;typeof require!=="undefined"&&!J(require)&&(r=require,require=void 0);d=requirejs=function(a,c,d){var k="_",j;!E(a)&&typeof a!=="string"&&(j=a,E(c)?(a=c,c=d):a=[]);if(j&&j.context)k=j.context;d=t[k]||(t[k]=fa(k));j&&d.configure(j);return d.require(a,c)};d.config=function(a){return d(a)};require||(require=d);d.toUrl=function(a){return t._.toUrl(a)};d.version="1.0.2";d.jsExtRegExp=/^\/|:|\?|\.js$/;v=d.s={contexts:t,skipAsync:{}};if(d.isAsync=
-d.isBrowser=G)if(x=v.head=document.getElementsByTagName("head")[0],y=document.getElementsByTagName("base")[0])x=v.head=y.parentNode;d.onError=function(a){throw a;};d.load=function(a,c,h){d.resourcesReady(!1);a.scriptCount+=1;d.attach(h,a,c);if(a.jQuery&&!a.jQueryIncremented)V(a.jQuery,!0),a.jQueryIncremented=!0};define=function(a,c,d){var k,j;typeof a!=="string"&&(d=c,c=a,a=null);E(c)||(d=c,c=[]);!c.length&&J(d)&&d.length&&(d.toString().replace(ja,"").replace(ka,function(a,d){c.push(d)}),c=(d.length===
-1?["require"]:["require","exports","module"]).concat(c));if(O&&(k=I||ia()))a||(a=k.getAttribute("data-requiremodule")),j=t[k.getAttribute("data-requirecontext")];(j?j.defQueue:U).push([a,c,d])};define.amd={multiversion:!0,plugins:!0,jQuery:!0};d.exec=function(a){return eval(a)};d.execCb=function(a,c,d,k){return c.apply(k,d)};d.addScriptToDom=function(a){I=a;y?x.insertBefore(a,y):x.appendChild(a);I=null};d.onScriptLoad=function(a){var c=a.currentTarget||a.srcElement,h;if(a.type==="load"||c&&la.test(c.readyState))n=
-null,a=c.getAttribute("data-requirecontext"),h=c.getAttribute("data-requiremodule"),t[a].completeLoad(h),c.detachEvent&&!da?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=function(a,c,h,k,j,n){var o;if(G)return k=k||d.onScriptLoad,o=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),o.type=j||"text/javascript",o.charset="utf-8",o.async=!v.skipAsync[a],c&&o.setAttribute("data-requirecontext",
-c.contextName),o.setAttribute("data-requiremodule",h),o.attachEvent&&!da?(O=!0,n?o.onreadystatechange=function(){if(o.readyState==="loaded")o.onreadystatechange=null,o.attachEvent("onreadystatechange",k),n(o)}:o.attachEvent("onreadystatechange",k)):o.addEventListener("load",k,!1),o.src=a,n||d.addScriptToDom(o),o;else ca&&(importScripts(a),c.completeLoad(h));return null};if(G){u=document.getElementsByTagName("script");for(H=u.length-1;H>-1&&(z=u[H]);H--){if(!x)x=z.parentNode;if(A=z.getAttribute("data-main")){if(!r.baseUrl)u=
-A.split("/"),z=u.pop(),u=u.length?u.join("/")+"/":"./",r.baseUrl=u,A=z.replace(aa,"");r.deps=r.deps?r.deps.concat(A):[A];break}}}d.checkReadyState=function(){var a=v.contexts,c;for(c in a)if(!(c in K)&&a[c].waitCount)return;d.resourcesReady(!0)};d.resourcesReady=function(a){var c,h;d.resourcesDone=a;if(d.resourcesDone)for(h in a=v.contexts,a)if(!(h in K)&&(c=a[h],c.jQueryIncremented))V(c.jQuery,!1),c.jQueryIncremented=!1};d.pageLoaded=function(){if(document.readyState!=="complete")document.readyState=
-"complete"};if(G&&document.addEventListener&&!document.readyState)document.readyState="loading",window.addEventListener("load",d.pageLoaded,!1);d(r);if(d.isAsync&&typeof setTimeout!=="undefined")B=v.contexts[r.context||"_"],B.requireWait=!0,setTimeout(function(){B.requireWait=!1;B.takeGlobalQueue();B.jQueryCheck();B.scriptCount||B.resume();d.checkReadyState()},0)}})();
+(function(Z){function x(b){return J.call(b)==="[object Function]"}function E(b){return J.call(b)==="[object Array]"}function o(b,e){if(b){var f;for(f=0;f<b.length;f+=1)if(b[f]&&e(b[f],f,b))break}}function M(b,e){if(b){var f;for(f=b.length-1;f>-1;f-=1)if(b[f]&&e(b[f],f,b))break}}function y(b,e){for(var f in b)if(b.hasOwnProperty(f)&&e(b[f],f))break}function N(b,e,f,h){e&&y(e,function(e,j){if(f||!F.call(b,j))h&&typeof e!=="string"?(b[j]||(b[j]={}),N(b[j],e,f,h)):b[j]=e});return b}function t(b,e){return function(){return e.apply(b,
+arguments)}}function $(b){if(!b)return b;var e=Z;o(b.split("."),function(b){e=e[b]});return e}function aa(b,e,f){return function(){var h=ga.call(arguments,0),c;if(f&&x(c=h[h.length-1]))c.__requireJsBuild=!0;h.push(e);return b.apply(null,h)}}function ba(b,e,f){o([["toUrl"],["undef"],["defined","requireDefined"],["specified","requireSpecified"]],function(h){var c=h[1]||h[0];b[h[0]]=e?aa(e[c],f):function(){var b=z[O];return b[c].apply(b,arguments)}})}function G(b,e,f,h){e=Error(e+"\nhttp://requirejs.org/docs/errors.html#"+
+b);e.requireType=b;e.requireModules=h;if(f)e.originalError=f;return e}function ha(){if(H&&H.readyState==="interactive")return H;M(document.getElementsByTagName("script"),function(b){if(b.readyState==="interactive")return H=b});return H}var j,p,u,B,s,C,H,I,ca,da,ia=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ja=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,ea=/\.js$/,ka=/^\.\//;p=Object.prototype;var J=p.toString,F=p.hasOwnProperty;p=Array.prototype;var ga=p.slice,la=p.splice,w=!!(typeof window!==
+"undefined"&&navigator&&document),fa=!w&&typeof importScripts!=="undefined",ma=w&&navigator.platform==="PLAYSTATION 3"?/^complete$/:/^(complete|loaded)$/,O="_",S=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",z={},r={},P=[],K=!1;if(typeof define==="undefined"){if(typeof requirejs!=="undefined"){if(x(requirejs))return;r=requirejs;requirejs=void 0}typeof require!=="undefined"&&!x(require)&&(r=require,require=void 0);j=requirejs=function(b,e,f,h){var c,o=O;!E(b)&&typeof b!=="string"&&
+(c=b,E(e)?(b=e,e=f,f=h):b=[]);if(c&&c.context)o=c.context;(h=z[o])||(h=z[o]=j.s.newContext(o));c&&h.configure(c);return h.require(b,e,f)};j.config=function(b){return j(b)};require||(require=j);j.version="2.0.6";j.jsExtRegExp=/^\/|:|\?|\.js$/;j.isBrowser=w;p=j.s={contexts:z,newContext:function(b){function e(a,d,k){var l,b,i,v,e,c,f,g=d&&d.split("/");l=g;var h=m.map,j=h&&h["*"];if(a&&a.charAt(0)===".")if(d){l=m.pkgs[d]?g=[d]:g.slice(0,g.length-1);d=a=l.concat(a.split("/"));for(l=0;d[l];l+=1)if(b=d[l],
+b===".")d.splice(l,1),l-=1;else if(b==="..")if(l===1&&(d[2]===".."||d[0]===".."))break;else l>0&&(d.splice(l-1,2),l-=2);l=m.pkgs[d=a[0]];a=a.join("/");l&&a===d+"/"+l.main&&(a=d)}else a.indexOf("./")===0&&(a=a.substring(2));if(k&&(g||j)&&h){d=a.split("/");for(l=d.length;l>0;l-=1){i=d.slice(0,l).join("/");if(g)for(b=g.length;b>0;b-=1)if(k=h[g.slice(0,b).join("/")])if(k=k[i]){v=k;e=l;break}if(v)break;!c&&j&&j[i]&&(c=j[i],f=l)}!v&&c&&(v=c,e=f);v&&(d.splice(0,e,v),a=d.join("/"))}return a}function f(a){w&&
+o(document.getElementsByTagName("script"),function(d){if(d.getAttribute("data-requiremodule")===a&&d.getAttribute("data-requirecontext")===g.contextName)return d.parentNode.removeChild(d),!0})}function h(a){var d=m.paths[a];if(d&&E(d)&&d.length>1)return f(a),d.shift(),g.undef(a),g.require([a]),!0}function c(a,d,k,l){var b,i,v=a?a.indexOf("!"):-1,c=null,f=d?d.name:null,h=a,j=!0,m="";a||(j=!1,a="_@r"+(M+=1));v!==-1&&(c=a.substring(0,v),a=a.substring(v+1,a.length));c&&(c=e(c,f,l),i=q[c]);a&&(c?m=i&&
+i.normalize?i.normalize(a,function(a){return e(a,f,l)}):e(a,f,l):(m=e(a,f,l),b=g.nameToUrl(m)));a=c&&!i&&!k?"_unnormalized"+(O+=1):"";return{prefix:c,name:m,parentMap:d,unnormalized:!!a,url:b,originalName:h,isDefine:j,id:(c?c+"!"+m:m)+a}}function p(a){var d=a.id,k=n[d];k||(k=n[d]=new g.Module(a));return k}function r(a,d,k){var b=a.id,c=n[b];if(F.call(q,b)&&(!c||c.defineEmitComplete))d==="defined"&&k(q[b]);else p(a).on(d,k)}function A(a,d){var k=a.requireModules,b=!1;if(d)d(a);else if(o(k,function(d){if(d=
+n[d])d.error=a,d.events.error&&(b=!0,d.emit("error",a))}),!b)j.onError(a)}function s(){P.length&&(la.apply(D,[D.length-1,0].concat(P)),P=[])}function u(a,d,k){a=a&&a.map;d=aa(k||g.require,a,d);ba(d,g,a);d.isBrowser=w;return d}function z(a){delete n[a];o(L,function(d,k){if(d.map.id===a)return L.splice(k,1),d.defined||(g.waitCount-=1),!0})}function B(a,d,k){var b=a.map.id,c=a.depMaps,i;if(a.inited){if(d[b])return a;d[b]=!0;o(c,function(a){var a=a.id,b=n[a];return!b||k[a]||!b.inited||!b.enabled?void 0:
+i=B(b,d,k)});k[b]=!0;return i}}function C(a,d,b){var l=a.map.id,c=a.depMaps;if(a.inited&&a.map.isDefine){if(d[l])return q[l];d[l]=a;o(c,function(i){var i=i.id,c=n[i];!Q[i]&&c&&(!c.inited||!c.enabled?b[l]=!0:(c=C(c,d,b),b[i]||a.defineDepById(i,c)))});a.check(!0);return q[l]}}function I(a){a.check()}function T(){var a,d,b,l,c=(b=m.waitSeconds*1E3)&&g.startTime+b<(new Date).getTime(),i=[],e=!1,j=!0;if(!U){U=!0;y(n,function(b){a=b.map;d=a.id;if(b.enabled&&!b.error)if(!b.inited&&c)h(d)?e=l=!0:(i.push(d),
+f(d));else if(!b.inited&&b.fetched&&a.isDefine&&(e=!0,!a.prefix))return j=!1});if(c&&i.length)return b=G("timeout","Load timeout for modules: "+i,null,i),b.contextName=g.contextName,A(b);j&&(o(L,function(a){if(!a.defined){var a=B(a,{},{}),d={};a&&(C(a,d,{}),y(d,I))}}),y(n,I));if((!c||l)&&e)if((w||fa)&&!V)V=setTimeout(function(){V=0;T()},50);U=!1}}function W(a){p(c(a[0],null,!0)).init(a[1],a[2])}function J(a){var a=a.currentTarget||a.srcElement,d=g.onScriptLoad;a.detachEvent&&!S?a.detachEvent("onreadystatechange",
+d):a.removeEventListener("load",d,!1);d=g.onScriptError;a.detachEvent&&!S||a.removeEventListener("error",d,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}var U,X,g,Q,V,m={waitSeconds:7,baseUrl:"./",paths:{},pkgs:{},shim:{}},n={},Y={},D=[],q={},R={},M=1,O=1,L=[];Q={require:function(a){return u(a)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports=q[a.map.id]={}},module:function(a){return a.module={id:a.map.id,uri:a.map.url,config:function(){return m.config&&m.config[a.map.id]||
+{}},exports:q[a.map.id]}}};X=function(a){this.events=Y[a.id]||{};this.map=a;this.shim=m.shim[a.id];this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};X.prototype={init:function(a,d,b,c){c=c||{};if(!this.inited){this.factory=d;if(b)this.on("error",b);else this.events.error&&(b=t(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.depMaps.rjsSkipMap=a.rjsSkipMap;this.errback=b;this.inited=!0;this.ignore=c.ignore;c.enabled||this.enabled?this.enable():
+this.check()}},defineDepById:function(a,d){var b;o(this.depMaps,function(d,c){if(d.id===a)return b=c,!0});return this.defineDep(b,d)},defineDep:function(a,d){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=d)},fetch:function(){if(!this.fetched){this.fetched=!0;g.startTime=(new Date).getTime();var a=this.map;if(this.shim)u(this,!0)(this.shim.deps||[],t(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},
+load:function(){var a=this.map.url;R[a]||(R[a]=!0,g.load(this.map.id,a))},check:function(a){if(this.enabled&&!this.enabling){var d,b,c=this.map.id;b=this.depExports;var e=this.exports,i=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(this.depCount<1&&!this.defined){if(x(i)){if(this.events.error)try{e=g.execCb(c,i,b,e)}catch(f){d=f}else e=g.execCb(c,i,b,e);if(this.map.isDefine)if((b=this.module)&&b.exports!==void 0&&b.exports!==this.exports)e=
+b.exports;else if(e===void 0&&this.usingExports)e=this.exports;if(d)return d.requireMap=this.map,d.requireModules=[this.map.id],d.requireType="define",A(this.error=d)}else e=i;this.exports=e;if(this.map.isDefine&&!this.ignore&&(q[c]=e,j.onResourceLoad))j.onResourceLoad(g,this.map,this.depMaps);delete n[c];this.defined=!0;g.waitCount-=1;g.waitCount===0&&(L=[])}this.defining=!1;if(!a&&this.defined&&!this.defineEmitted)this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0}}else this.fetch()}},
+callPlugin:function(){var a=this.map,d=a.id,b=c(a.prefix,null,!1,!0);r(b,"defined",t(this,function(b){var k;k=this.map.name;var i=this.map.parentMap?this.map.parentMap.name:null;if(this.map.unnormalized){if(b.normalize&&(k=b.normalize(k,function(a){return e(a,i,!0)})||""),b=c(a.prefix+"!"+k,this.map.parentMap,!1,!0),r(b,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),b=n[b.id]){if(this.events.error)b.on("error",t(this,function(a){this.emit("error",a)}));
+b.enable()}}else k=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),k.error=t(this,function(a){this.inited=!0;this.error=a;a.requireModules=[d];y(n,function(a){a.map.id.indexOf(d+"_unnormalized")===0&&z(a.map.id)});A(a)}),k.fromText=function(a,b){var d=K;d&&(K=!1);p(c(a));j.exec(b);d&&(K=!0);g.completeLoad(a)},b.load(a.name,u(a.parentMap,!0,function(a,b,d){a.rjsSkipMap=!0;return g.require(a,b,d)}),k,m)}));g.enable(b,this);this.pluginMaps[b.id]=b},enable:function(){this.enabled=
+!0;if(!this.waitPushed)L.push(this),g.waitCount+=1,this.waitPushed=!0;this.enabling=!0;o(this.depMaps,t(this,function(a,b){var k,e;if(typeof a==="string"){a=c(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.depMaps.rjsSkipMap);this.depMaps[b]=a;if(k=Q[a.id]){this.depExports[b]=k(this);return}this.depCount+=1;r(a,"defined",t(this,function(a){this.defineDep(b,a);this.check()}));this.errback&&r(a,"error",this.errback)}k=a.id;e=n[k];!Q[k]&&e&&!e.enabled&&g.enable(a,this)}));y(this.pluginMaps,
+t(this,function(a){var b=n[a.id];b&&!b.enabled&&g.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){o(this.events[a],function(a){a(b)});a==="error"&&delete this.events[a]}};return g={config:m,contextName:b,registry:n,defined:q,urlFetched:R,waitCount:0,defQueue:D,Module:X,makeModuleMap:c,configure:function(a){a.baseUrl&&a.baseUrl.charAt(a.baseUrl.length-1)!=="/"&&(a.baseUrl+="/");var b=m.pkgs,e=m.shim,f=m.paths,
+j=m.map;N(m,a,!0);m.paths=N(f,a.paths,!0);if(a.map)m.map=N(j||{},a.map,!0,!0);if(a.shim)y(a.shim,function(a,b){E(a)&&(a={deps:a});if(a.exports&&!a.exports.__buildReady)a.exports=g.makeShimExports(a.exports);e[b]=a}),m.shim=e;if(a.packages)o(a.packages,function(a){a=typeof a==="string"?{name:a}:a;b[a.name]={name:a.name,location:a.location||a.name,main:(a.main||"main").replace(ka,"").replace(ea,"")}}),m.pkgs=b;y(n,function(a,b){if(!a.inited&&!a.map.unnormalized)a.map=c(b)});if(a.deps||a.callback)g.require(a.deps||
+[],a.callback)},makeShimExports:function(a){var b;return typeof a==="string"?(b=function(){return $(a)},b.exports=a,b):function(){return a.apply(Z,arguments)}},requireDefined:function(a,b){var e=c(a,b,!1,!0).id;return F.call(q,e)},requireSpecified:function(a,b){a=c(a,b,!1,!0).id;return F.call(q,a)||F.call(n,a)},require:function(a,d,e,f){var h;if(typeof a==="string"){if(x(d))return A(G("requireargs","Invalid require call"),e);if(j.get)return j.get(g,a,d);a=c(a,d,!1,!0);a=a.id;return!F.call(q,a)?A(G("notloaded",
+'Module name "'+a+'" has not been loaded yet for context: '+b)):q[a]}e&&!x(e)&&(f=e,e=void 0);d&&!x(d)&&(f=d,d=void 0);for(s();D.length;)if(h=D.shift(),h[0]===null)return A(G("mismatch","Mismatched anonymous define() module: "+h[h.length-1]));else W(h);p(c(null,f)).init(a,d,e,{enabled:!0});T();return g.require},undef:function(a){s();var b=c(a,null,!0),e=n[a];delete q[a];delete R[b.url];delete Y[a];if(e){if(e.events.defined)Y[a]=e.events;z(a)}},enable:function(a){n[a.id]&&p(a).enable()},completeLoad:function(a){var b,
+c,e=m.shim[a]||{},f=e.exports&&e.exports.exports;for(s();D.length;){c=D.shift();if(c[0]===null){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);W(c)}c=n[a];if(!b&&!q[a]&&c&&!c.inited)if(m.enforceDefine&&(!f||!$(f)))if(h(a))return;else return A(G("nodefine","No define call for "+a,null,[a]));else W([a,e.deps||[],e.exports]);T()},toUrl:function(a,b){var c=a.lastIndexOf("."),f=null;c!==-1&&(f=a.substring(c,a.length),a=a.substring(0,c));return g.nameToUrl(e(a,b&&b.id,!0),f)},nameToUrl:function(a,b){var c,
+e,f,i,h,g;if(j.jsExtRegExp.test(a))i=a+(b||"");else{c=m.paths;e=m.pkgs;i=a.split("/");for(h=i.length;h>0;h-=1)if(g=i.slice(0,h).join("/"),f=e[g],g=c[g]){E(g)&&(g=g[0]);i.splice(0,h,g);break}else if(f){c=a===f.name?f.location+"/"+f.main:f.location;i.splice(0,h,c);break}i=i.join("/");i+=b||(/\?/.test(i)?"":".js");i=(i.charAt(0)==="/"||i.match(/^[\w\+\.\-]+:/)?"":m.baseUrl)+i}return m.urlArgs?i+((i.indexOf("?")===-1?"?":"&")+m.urlArgs):i},load:function(a,b){j.load(g,a,b)},execCb:function(a,b,c,e){return b.apply(e,
+c)},onScriptLoad:function(a){if(a.type==="load"||ma.test((a.currentTarget||a.srcElement).readyState))H=null,a=J(a),g.completeLoad(a.id)},onScriptError:function(a){var b=J(a);if(!h(b.id))return A(G("scripterror","Script error",a,[b.id]))}}}};j({});ba(j);if(w&&(u=p.head=document.getElementsByTagName("head")[0],B=document.getElementsByTagName("base")[0]))u=p.head=B.parentNode;j.onError=function(b){throw b;};j.load=function(b,e,f){var h=b&&b.config||{},c;if(w)return c=h.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml",
+"html:script"):document.createElement("script"),c.type=h.scriptType||"text/javascript",c.charset="utf-8",c.async=!0,c.setAttribute("data-requirecontext",b.contextName),c.setAttribute("data-requiremodule",e),c.attachEvent&&!(c.attachEvent.toString&&c.attachEvent.toString().indexOf("[native code")<0)&&!S?(K=!0,c.attachEvent("onreadystatechange",b.onScriptLoad)):(c.addEventListener("load",b.onScriptLoad,!1),c.addEventListener("error",b.onScriptError,!1)),c.src=f,I=c,B?u.insertBefore(c,B):u.appendChild(c),
+I=null,c;else fa&&(importScripts(f),b.completeLoad(e))};w&&M(document.getElementsByTagName("script"),function(b){if(!u)u=b.parentNode;if(s=b.getAttribute("data-main")){if(!r.baseUrl)C=s.split("/"),ca=C.pop(),da=C.length?C.join("/")+"/":"./",r.baseUrl=da,s=ca;s=s.replace(ea,"");r.deps=r.deps?r.deps.concat(s):[s];return!0}});define=function(b,e,f){var h,c;typeof b!=="string"&&(f=e,e=b,b=null);E(e)||(f=e,e=[]);!e.length&&x(f)&&f.length&&(f.toString().replace(ia,"").replace(ja,function(b,c){e.push(c)}),
+e=(f.length===1?["require"]:["require","exports","module"]).concat(e));if(K&&(h=I||ha()))b||(b=h.getAttribute("data-requiremodule")),c=z[h.getAttribute("data-requirecontext")];(c?c.defQueue:P).push([b,e,f])};define.amd={jQuery:!0};j.exec=function(b){return eval(b)};j(r)}})(this);
 

--- a/lib/requirejs/r.js
+++ b/lib/requirejs/r.js
@@ -1,5 +1,5 @@
 /**
- * @license r.js 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
+ * @license r.js 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
  */
@@ -11,18 +11,19 @@
  * the shell of the r.js file.
  */
 
-/*jslint strict: false, evil: true, nomen: false */
+/*jslint evil: true, nomen: true, sloppy: true */
 /*global readFile: true, process: false, Packages: false, print: false,
-console: false, java: false, module: false */
+console: false, java: false, module: false, requirejsVars */
 
 var requirejs, require, define;
 (function (console, args, readFileFunc) {
 
     var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire,
-        nodeDefine, exists, reqMain, loadedOptimizedLib,
-        version = '1.0.2',
+        nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode,
+        version = '2.0.6',
         jsSuffixRegExp = /\.js$/,
         commandOption = '',
+        useLibLoaded = {},
         //Used by jslib/rhino/args.js
         rhinoArgs = args,
         readFile = typeof readFileFunc !== 'undefined' ? readFileFunc : null;
@@ -69,6 +70,9 @@
         fs = require('fs');
         vm = require('vm');
         path = require('path');
+        //In Node 0.7+ existsSync is on fs.
+        existsForNode = fs.existsSync || path.existsSync;
+
         nodeRequire = require;
         nodeDefine = define;
         reqMain = require.main;
@@ -88,7 +92,7 @@
         };
 
         exists = function (fileName) {
-            return path.existsSync(fileName);
+            return existsForNode(fileName);
         };
 
 
@@ -101,53 +105,102 @@
     }
 
     /** vim: et:ts=4:sw=4:sts=4
- * @license RequireJS 1.0.2 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
+ * @license RequireJS 2.0.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
  */
-/*jslint strict: false, plusplus: false, sub: true */
-/*global window: false, navigator: false, document: false, importScripts: false,
-  jQuery: false, clearInterval: false, setInterval: false, self: false,
-  setTimeout: false, opera: false */
-
-
-(function () {
-    //Change this version number for each release.
-    var version = "1.0.2",
+//Not using strict: uneven strict support in browsers, #392, and causes
+//problems with requirejs.exec()/transpiler plugins that may not be strict.
+/*jslint regexp: true, nomen: true, sloppy: true */
+/*global window, navigator, document, importScripts, jQuery, setTimeout, opera */
+
+
+(function (global) {
+    var req, s, head, baseElement, dataMain, src,
+        interactiveScript, currentlyAddingScript, mainScript, subPath,
+        version = '2.0.6',
         commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
-        cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g,
+        cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
+        jsSuffixRegExp = /\.js$/,
         currDirRegExp = /^\.\//,
-        jsSuffixRegExp = /\.js$/,
-        ostring = Object.prototype.toString,
+        op = Object.prototype,
+        ostring = op.toString,
+        hasOwn = op.hasOwnProperty,
         ap = Array.prototype,
         aps = ap.slice,
         apsp = ap.splice,
-        isBrowser = !!(typeof window !== "undefined" && navigator && document),
-        isWebWorker = !isBrowser && typeof importScripts !== "undefined",
+        isBrowser = !!(typeof window !== 'undefined' && navigator && document),
+        isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
         //PS3 indicates loaded and complete, but need to wait for complete
-        //specifically. Sequence is "loading", "loaded", execution,
-        // then "complete". The UA check is unfortunate, but not sure how
+        //specifically. Sequence is 'loading', 'loaded', execution,
+        // then 'complete'. The UA check is unfortunate, but not sure how
         //to feature test w/o causing perf issues.
         readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
                       /^complete$/ : /^(complete|loaded)$/,
-        defContextName = "_",
+        defContextName = '_',
         //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
-        isOpera = typeof opera !== "undefined" && opera.toString() === "[object Opera]",
-        empty = {},
+        isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
         contexts = {},
+        cfg = {},
         globalDefQueue = [],
-        interactiveScript = null,
-        checkLoadedDepth = 0,
-        useInteractive = false,
-        req, cfg = {}, currentlyAddingScript, s, head, baseElement, scripts, script,
-        src, subPath, mainScript, dataMain, i, ctx, jQueryCheck, checkLoadedTimeoutId;
+        useInteractive = false;
 
     function isFunction(it) {
-        return ostring.call(it) === "[object Function]";
+        return ostring.call(it) === '[object Function]';
     }
 
     function isArray(it) {
-        return ostring.call(it) === "[object Array]";
+        return ostring.call(it) === '[object Array]';
+    }
+
+    /**
+     * Helper function for iterating over an array. If the func returns
+     * a true value, it will break out of the loop.
+     */
+    function each(ary, func) {
+        if (ary) {
+            var i;
+            for (i = 0; i < ary.length; i += 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function for iterating over an array backwards. If the func
+     * returns a true value, it will break out of the loop.
+     */
+    function eachReverse(ary, func) {
+        if (ary) {
+            var i;
+            for (i = ary.length - 1; i > -1; i -= 1) {
+                if (ary[i] && func(ary[i], i, ary)) {
+                    break;
+                }
+            }
+        }
+    }
+
+    function hasProp(obj, prop) {
+        return hasOwn.call(obj, prop);
+    }
+
+    /**
+     * Cycles over properties in an object and calls a function for each
+     * property value. If the function returns a truthy value, then the
+     * iteration is stopped.
+     */
+    function eachProp(obj, func) {
+        var prop;
+        for (prop in obj) {
+            if (obj.hasOwnProperty(prop)) {
+                if (func(obj[prop], prop)) {
+                    break;
+                }
+            }
+        }
     }
 
     /**
@@ -157,13 +210,82 @@
      * Object.prototype names, but the uses of mixin here seem unlikely to
      * trigger a problem related to that.
      */
-    function mixin(target, source, force) {
-        for (var prop in source) {
-            if (!(prop in empty) && (!(prop in target) || force)) {
-                target[prop] = source[prop];
-            }
-        }
-        return req;
+    function mixin(target, source, force, deepStringMixin) {
+        if (source) {
+            eachProp(source, function (value, prop) {
+                if (force || !hasProp(target, prop)) {
+                    if (deepStringMixin && typeof value !== 'string') {
+                        if (!target[prop]) {
+                            target[prop] = {};
+                        }
+                        mixin(target[prop], value, force, deepStringMixin);
+                    } else {
+                        target[prop] = value;
+                    }
+                }
+            });
+        }
+        return target;
+    }
+
+    //Similar to Function.prototype.bind, but the 'this' object is specified
+    //first, since it is easier to read/figure out what 'this' will be.
+    function bind(obj, fn) {
+        return function () {
+            return fn.apply(obj, arguments);
+        };
+    }
+
+    function scripts() {
+        return document.getElementsByTagName('script');
+    }
+
+    //Allow getting a global that expressed in
+    //dot notation, like 'a.b.c'.
+    function getGlobal(value) {
+        if (!value) {
+            return value;
+        }
+        var g = global;
+        each(value.split('.'), function (part) {
+            g = g[part];
+        });
+        return g;
+    }
+
+    function makeContextModuleFunc(func, relMap, enableBuildCallback) {
+        return function () {
+            //A version of a require function that passes a moduleName
+            //value for items that may need to
+            //look up paths relative to the moduleName
+            var args = aps.call(arguments, 0), lastArg;
+            if (enableBuildCallback &&
+                    isFunction((lastArg = args[args.length - 1]))) {
+                lastArg.__requireJsBuild = true;
+            }
+            args.push(relMap);
+            return func.apply(null, args);
+        };
+    }
+
+    function addRequireMethods(req, context, relMap) {
+        each([
+            ['toUrl'],
+            ['undef'],
+            ['defined', 'requireDefined'],
+            ['specified', 'requireSpecified']
+        ], function (item) {
+            var prop = item[1] || item[0];
+            req[item[0]] = context ? makeContextModuleFunc(context[prop], relMap) :
+                    //If no context, then use default context. Reference from
+                    //contexts instead of early binding to default context, so
+                    //that during builds, the latest instance of the default
+                    //context with its config gets used.
+                    function () {
+                        var ctx = contexts[defContextName];
+                        return ctx[prop].apply(ctx, arguments);
+                    };
+        });
     }
 
     /**
@@ -174,128 +296,60 @@
      *
      * @returns {Error}
      */
-    function makeError(id, msg, err) {
+    function makeError(id, msg, err, requireModules) {
         var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
+        e.requireType = id;
+        e.requireModules = requireModules;
         if (err) {
             e.originalError = err;
         }
         return e;
     }
 
-    /**
-     * Used to set up package paths from a packagePaths or packages config object.
-     * @param {Object} pkgs the object to store the new package config
-     * @param {Array} currentPackages an array of packages to configure
-     * @param {String} [dir] a prefix dir to use.
-     */
-    function configurePackageDir(pkgs, currentPackages, dir) {
-        var i, location, pkgObj;
-
-        for (i = 0; (pkgObj = currentPackages[i]); i++) {
-            pkgObj = typeof pkgObj === "string" ? { name: pkgObj } : pkgObj;
-            location = pkgObj.location;
-
-            //Add dir to the path, but avoid paths that start with a slash
-            //or have a colon (indicates a protocol)
-            if (dir && (!location || (location.indexOf("/") !== 0 && location.indexOf(":") === -1))) {
-                location = dir + "/" + (location || pkgObj.name);
-            }
-
-            //Create a brand new object on pkgs, since currentPackages can
-            //be passed in again, and config.pkgs is the internal transformed
-            //state for all package configs.
-            pkgs[pkgObj.name] = {
-                name: pkgObj.name,
-                location: location || pkgObj.name,
-                //Remove leading dot in main, so main paths are normalized,
-                //and remove any trailing .js, since different package
-                //envs have different conventions: some use a module name,
-                //some use a file name.
-                main: (pkgObj.main || "main")
-                      .replace(currDirRegExp, '')
-                      .replace(jsSuffixRegExp, '')
-            };
-        }
-    }
-
-    /**
-     * jQuery 1.4.3-1.5.x use a readyWait/ready() pairing to hold DOM
-     * ready callbacks, but jQuery 1.6 supports a holdReady() API instead.
-     * At some point remove the readyWait/ready() support and just stick
-     * with using holdReady.
-     */
-    function jQueryHoldReady($, shouldHold) {
-        if ($.holdReady) {
-            $.holdReady(shouldHold);
-        } else if (shouldHold) {
-            $.readyWait += 1;
-        } else {
-            $.ready(true);
-        }
-    }
-
-    if (typeof define !== "undefined") {
+    if (typeof define !== 'undefined') {
         //If a define is already in play via another AMD loader,
         //do not overwrite.
         return;
     }
 
-    if (typeof requirejs !== "undefined") {
+    if (typeof requirejs !== 'undefined') {
         if (isFunction(requirejs)) {
             //Do not overwrite and existing requirejs instance.
             return;
-        } else {
-            cfg = requirejs;
-            requirejs = undefined;
-        }
+        }
+        cfg = requirejs;
+        requirejs = undefined;
     }
 
     //Allow for a require config object
-    if (typeof require !== "undefined" && !isFunction(require)) {
+    if (typeof require !== 'undefined' && !isFunction(require)) {
         //assume it is a config object.
         cfg = require;
         require = undefined;
     }
 
-    /**
-     * Creates a new context for use in require and define calls.
-     * Handle most of the heavy lifting. Do not want to use an object
-     * with prototype here to avoid using "this" in require, in case it
-     * needs to be used in more super secure envs that do not want this.
-     * Also there should not be that many contexts in the page. Usually just
-     * one for the default context, but could be extra for multiversion cases
-     * or if a package needs a special context for a dependency that conflicts
-     * with the standard context.
-     */
     function newContext(contextName) {
-        var context, resume,
+        var inCheckLoaded, Module, context, handlers,
+            checkLoadedTimeoutId,
             config = {
                 waitSeconds: 7,
-                baseUrl: "./",
+                baseUrl: './',
                 paths: {},
                 pkgs: {},
-                catchError: {}
+                shim: {}
             },
+            registry = {},
+            undefEvents = {},
             defQueue = [],
-            specified = {
-                "require": true,
-                "exports": true,
-                "module": true
-            },
-            urlMap = {},
             defined = {},
-            loaded = {},
-            waiting = {},
-            waitAry = [],
             urlFetched = {},
-            managerCounter = 0,
-            managerCallbacks = {},
-            plugins = {},
-            //Used to indicate which modules in a build scenario
-            //need to be full executed.
-            needFullExec = {},
-            fullExec = {},
-            resumeDepth = 0;
+            requireCounter = 1,
+            unnormalizedCounter = 1,
+            //Used to track the order in which modules
+            //should be executed, by the order they
+            //load. Important for consistent cycle resolution
+            //behavior.
+            waitAry = [];
 
         /**
          * Trims the . and .. from an array of path segments.
@@ -308,11 +362,12 @@
          */
         function trimDots(ary) {
             var i, part;
-            for (i = 0; (part = ary[i]); i++) {
-                if (part === ".") {
+            for (i = 0; ary[i]; i += 1) {
+                part = ary[i];
+                if (part === '.') {
                     ary.splice(i, 1);
                     i -= 1;
-                } else if (part === "..") {
+                } else if (part === '..') {
                     if (i === 1 && (ary[2] === '..' || ary[0] === '..')) {
                         //End of the line. Keep at least one non-dot
                         //path segment at the front so it can be mapped
@@ -335,13 +390,20 @@
          * @param {String} name the relative name
          * @param {String} baseName a real name that the name arg is relative
          * to.
+         * @param {Boolean} applyMap apply the map config to the value. Should
+         * only be done if this normalization is for a dependency ID.
          * @returns {String} normalized name
          */
-        function normalize(name, baseName) {
-            var pkgName, pkgConfig;
+        function normalize(name, baseName, applyMap) {
+            var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment,
+                foundMap, foundI, foundStarMap, starI,
+                baseParts = baseName && baseName.split('/'),
+                normalizedBaseParts = baseParts,
+                map = config.map,
+                starMap = map && map['*'];
 
             //Adjust any relative paths.
-            if (name && name.charAt(0) === ".") {
+            if (name && name.charAt(0) === '.') {
                 //If have a base name, try to normalize against it,
                 //otherwise, assume it is a top-level require that will
                 //be relative to baseUrl in the end.
@@ -349,34 +411,110 @@
                     if (config.pkgs[baseName]) {
                         //If the baseName is a package name, then just treat it as one
                         //name to concat the name with.
-                        baseName = [baseName];
+                        normalizedBaseParts = baseParts = [baseName];
                     } else {
                         //Convert baseName to array, and lop off the last part,
-                        //so that . matches that "directory" and not name of the baseName's
-                        //module. For instance, baseName of "one/two/three", maps to
-                        //"one/two/three.js", but we want the directory, "one/two" for
+                        //so that . matches that 'directory' and not name of the baseName's
+                        //module. For instance, baseName of 'one/two/three', maps to
+                        //'one/two/three.js', but we want the directory, 'one/two' for
                         //this normalization.
-                        baseName = baseName.split("/");
-                        baseName = baseName.slice(0, baseName.length - 1);
+                        normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
                     }
 
-                    name = baseName.concat(name.split("/"));
+                    name = normalizedBaseParts.concat(name.split('/'));
                     trimDots(name);
 
                     //Some use of packages may use a . path to reference the
-                    //"main" module name, so normalize for that.
+                    //'main' module name, so normalize for that.
                     pkgConfig = config.pkgs[(pkgName = name[0])];
-                    name = name.join("/");
+                    name = name.join('/');
                     if (pkgConfig && name === pkgName + '/' + pkgConfig.main) {
                         name = pkgName;
                     }
-                } else if (name.indexOf("./") === 0) {
+                } else if (name.indexOf('./') === 0) {
                     // No baseName, so this is ID is resolved relative
                     // to baseUrl, pull off the leading dot.
                     name = name.substring(2);
                 }
             }
+
+            //Apply map config if available.
+            if (applyMap && (baseParts || starMap) && map) {
+                nameParts = name.split('/');
+
+                for (i = nameParts.length; i > 0; i -= 1) {
+                    nameSegment = nameParts.slice(0, i).join('/');
+
+                    if (baseParts) {
+                        //Find the longest baseName segment match in the config.
+                        //So, do joins on the biggest to smallest lengths of baseParts.
+                        for (j = baseParts.length; j > 0; j -= 1) {
+                            mapValue = map[baseParts.slice(0, j).join('/')];
+
+                            //baseName segment has config, find if it has one for
+                            //this name.
+                            if (mapValue) {
+                                mapValue = mapValue[nameSegment];
+                                if (mapValue) {
+                                    //Match, update name to the new value.
+                                    foundMap = mapValue;
+                                    foundI = i;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    if (foundMap) {
+                        break;
+                    }
+
+                    //Check for a star map match, but just hold on to it,
+                    //if there is a shorter segment match later in a matching
+                    //config, then favor over this star map.
+                    if (!foundStarMap && starMap && starMap[nameSegment]) {
+                        foundStarMap = starMap[nameSegment];
+                        starI = i;
+                    }
+                }
+
+                if (!foundMap && foundStarMap) {
+                    foundMap = foundStarMap;
+                    foundI = starI;
+                }
+
+                if (foundMap) {
+                    nameParts.splice(0, foundI, foundMap);
+                    name = nameParts.join('/');
+                }
+            }
+
             return name;
+        }
+
+        function removeScript(name) {
+            if (isBrowser) {
+                each(scripts(), function (scriptNode) {
+                    if (scriptNode.getAttribute('data-requiremodule') === name &&
+                            scriptNode.getAttribute('data-requirecontext') === context.contextName) {
+                        scriptNode.parentNode.removeChild(scriptNode);
+                        return true;
+                    }
+                });
+            }
+        }
+
+        function hasPathFallback(id) {
+            var pathConfig = config.paths[id];
+            if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
+                removeScript(id);
+                //Pop off the first array value, since it failed, and
+                //retry
+                pathConfig.shift();
+                context.undef(id);
+                context.require([id]);
+                return true;
+            }
         }
 
         /**
@@ -387,15 +525,28 @@
          * @param {String} name the module name
          * @param {String} [parentModuleMap] parent module map
          * for the module name, used to resolve relative names.
+         * @param {Boolean} isNormalized: is the ID already normalized.
+         * This is true if this call is done for a define() module ID.
+         * @param {Boolean} applyMap: apply the map config to the ID.
+         * Should only be true if this map is for a dependency.
          *
          * @returns {Object}
          */
-        function makeModuleMap(name, parentModuleMap) {
-            var index = name ? name.indexOf("!") : -1,
+        function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
+            var url, pluginModule, suffix,
+                index = name ? name.indexOf('!') : -1,
                 prefix = null,
                 parentName = parentModuleMap ? parentModuleMap.name : null,
                 originalName = name,
-                normalizedName, url, pluginModule;
+                isDefine = true,
+                normalizedName = '';
+
+            //If no name, then it means it is a require call, generate an
+            //internal name.
+            if (!name) {
+                isDefine = false;
+                name = '_@r' + (requireCounter += 1);
+            }
 
             if (index !== -1) {
                 prefix = name.substring(0, index);
@@ -403,80 +554,113 @@
             }
 
             if (prefix) {
-                prefix = normalize(prefix, parentName);
+                prefix = normalize(prefix, parentName, applyMap);
+                pluginModule = defined[prefix];
             }
 
             //Account for relative paths if there is a base name.
             if (name) {
                 if (prefix) {
-                    pluginModule = defined[prefix];
                     if (pluginModule && pluginModule.normalize) {
                         //Plugin is loaded, use its normalize method.
                         normalizedName = pluginModule.normalize(name, function (name) {
-                            return normalize(name, parentName);
+                            return normalize(name, parentName, applyMap);
                         });
                     } else {
-                        normalizedName = normalize(name, parentName);
+                        normalizedName = normalize(name, parentName, applyMap);
                     }
                 } else {
                     //A regular module.
-                    normalizedName = normalize(name, parentName);
-
-                    url = urlMap[normalizedName];
-                    if (!url) {
-                        //Calculate url for the module, if it has a name.
-                        url = context.nameToUrl(normalizedName, null, parentModuleMap);
-
-                        //Store the URL mapping for later.
-                        urlMap[normalizedName] = url;
-                    }
-                }
-            }
+                    normalizedName = normalize(name, parentName, applyMap);
+                    url = context.nameToUrl(normalizedName);
+                }
+            }
+
+            //If the id is a plugin id that cannot be determined if it needs
+            //normalization, stamp it with a unique ID so two matching relative
+            //ids that may conflict can be separate.
+            suffix = prefix && !pluginModule && !isNormalized ?
+                     '_unnormalized' + (unnormalizedCounter += 1) :
+                     '';
 
             return {
                 prefix: prefix,
                 name: normalizedName,
                 parentMap: parentModuleMap,
+                unnormalized: !!suffix,
                 url: url,
                 originalName: originalName,
-                fullName: prefix ? prefix + "!" + (normalizedName || '') : normalizedName
+                isDefine: isDefine,
+                id: (prefix ?
+                        prefix + '!' + normalizedName :
+                        normalizedName) + suffix
             };
         }
 
+        function getModule(depMap) {
+            var id = depMap.id,
+                mod = registry[id];
+
+            if (!mod) {
+                mod = registry[id] = new context.Module(depMap);
+            }
+
+            return mod;
+        }
+
+        function on(depMap, name, fn) {
+            var id = depMap.id,
+                mod = registry[id];
+
+            if (hasProp(defined, id) &&
+                    (!mod || mod.defineEmitComplete)) {
+                if (name === 'defined') {
+                    fn(defined[id]);
+                }
+            } else {
+                getModule(depMap).on(name, fn);
+            }
+        }
+
+        function onError(err, errback) {
+            var ids = err.requireModules,
+                notified = false;
+
+            if (errback) {
+                errback(err);
+            } else {
+                each(ids, function (id) {
+                    var mod = registry[id];
+                    if (mod) {
+                        //Set error on module, so it skips timeout checks.
+                        mod.error = err;
+                        if (mod.events.error) {
+                            notified = true;
+                            mod.emit('error', err);
+                        }
+                    }
+                });
+
+                if (!notified) {
+                    req.onError(err);
+                }
+            }
+        }
+
         /**
-         * Determine if priority loading is done. If so clear the priorityWait
+         * Internal method to transfer globalQueue items to this context's
+         * defQueue.
          */
-        function isPriorityDone() {
-            var priorityDone = true,
-                priorityWait = config.priorityWait,
-                priorityName, i;
-            if (priorityWait) {
-                for (i = 0; (priorityName = priorityWait[i]); i++) {
-                    if (!loaded[priorityName]) {
-                        priorityDone = false;
-                        break;
-                    }
-                }
-                if (priorityDone) {
-                    delete config.priorityWait;
-                }
-            }
-            return priorityDone;
-        }
-
-        function makeContextModuleFunc(func, relModuleMap, enableBuildCallback) {
-            return function () {
-                //A version of a require function that passes a moduleName
-                //value for items that may need to
-                //look up paths relative to the moduleName
-                var args = aps.call(arguments, 0), lastArg;
-                if (enableBuildCallback &&
-                    isFunction((lastArg = args[args.length - 1]))) {
-                    lastArg.__requireJsBuild = true;
-                }
-                args.push(relModuleMap);
-                return func.apply(null, args);
-            };
+        function takeGlobalQueue() {
+            //Push all the globalDefQueue items into the context's defQueue
+            if (globalDefQueue.length) {
+                //Array splice in the values since the context code has a
+                //local var ref to defQueue, so cannot just reassign the one
+                //on context.
+                apsp.apply(defQueue,
+                           [defQueue.length - 1, 0].concat(globalDefQueue));
+                globalDefQueue = [];
+            }
         }
 
         /**
@@ -485,581 +669,235 @@
          * per module because of the implication of path mappings that may
          * need to be relative to the module name.
          */
-        function makeRequire(relModuleMap, enableBuildCallback) {
-            var modRequire = makeContextModuleFunc(context.require, relModuleMap, enableBuildCallback);
-
-            mixin(modRequire, {
-                nameToUrl: makeContextModuleFunc(context.nameToUrl, relModuleMap),
-                toUrl: makeContextModuleFunc(context.toUrl, relModuleMap),
-                defined: makeContextModuleFunc(context.requireDefined, relModuleMap),
-                specified: makeContextModuleFunc(context.requireSpecified, relModuleMap),
-                isBrowser: req.isBrowser
+        function makeRequire(mod, enableBuildCallback, altRequire) {
+            var relMap = mod && mod.map,
+                modRequire = makeContextModuleFunc(altRequire || context.require,
+                                                   relMap,
+                                                   enableBuildCallback);
+
+            addRequireMethods(modRequire, context, relMap);
+            modRequire.isBrowser = isBrowser;
+
+            return modRequire;
+        }
+
+        handlers = {
+            'require': function (mod) {
+                return makeRequire(mod);
+            },
+            'exports': function (mod) {
+                mod.usingExports = true;
+                if (mod.map.isDefine) {
+                    return (mod.exports = defined[mod.map.id] = {});
+                }
+            },
+            'module': function (mod) {
+                return (mod.module = {
+                    id: mod.map.id,
+                    uri: mod.map.url,
+                    config: function () {
+                        return (config.config && config.config[mod.map.id]) || {};
+                    },
+                    exports: defined[mod.map.id]
+                });
+            }
+        };
+
+        function removeWaiting(id) {
+            //Clean up machinery used for waiting modules.
+            delete registry[id];
+
+            each(waitAry, function (mod, i) {
+                if (mod.map.id === id) {
+                    waitAry.splice(i, 1);
+                    if (!mod.defined) {
+                        context.waitCount -= 1;
+                    }
+                    return true;
+                }
             });
-            return modRequire;
-        }
-
-        /*
-         * Queues a dependency for checking after the loader is out of a
-         * "paused" state, for example while a script file is being loaded
-         * in the browser, where it may have many modules defined in it.
-         */
-        function queueDependency(manager) {
-            context.paused.push(manager);
-        }
-
-        function execManager(manager) {
-            var i, ret, err, errFile, errModuleTree,
-                cb = manager.callback,
-                map = manager.map,
-                fullName = map.fullName,
-                args = manager.deps,
-                listeners = manager.listeners,
-                cjsModule;
-
-            //Call the callback to define the module, if necessary.
-            if (cb && isFunction(cb)) {
-                if (config.catchError.define) {
-                    try {
-                        ret = req.execCb(fullName, manager.callback, args, defined[fullName]);
-                    } catch (e) {
-                        err = e;
+        }
+
+        function findCycle(mod, traced, processed) {
+            var id = mod.map.id,
+                depArray = mod.depMaps,
+                foundModule;
+
+            //Do not bother with unitialized modules or not yet enabled
+            //modules.
+            if (!mod.inited) {
+                return;
+            }
+
+            //Found the cycle.
+            if (traced[id]) {
+                return mod;
+            }
+
+            traced[id] = true;
+
+            //Trace through the dependencies.
+            each(depArray, function (depMap) {
+                var depId = depMap.id,
+                    depMod = registry[depId];
+
+                if (!depMod || processed[depId] ||
+                        !depMod.inited || !depMod.enabled) {
+                    return;
+                }
+
+                return (foundModule = findCycle(depMod, traced, processed));
+            });
+
+            processed[id] = true;
+
+            return foundModule;
+        }
+
+        function forceExec(mod, traced, uninited) {
+            var id = mod.map.id,
+                depArray = mod.depMaps;
+
+            if (!mod.inited || !mod.map.isDefine) {
+                return;
+            }
+
+            if (traced[id]) {
+                return defined[id];
+            }
+
+            traced[id] = mod;
+
+            each(depArray, function (depMap) {
+                var depId = depMap.id,
+                    depMod = registry[depId],
+                    value;
+
+                if (handlers[depId]) {
+                    return;
+                }
+
+                if (depMod) {
+                    if (!depMod.inited || !depMod.enabled) {
+                        //Dependency is not inited,
+                        //so this module cannot be
+                        //given a forced value yet.
+                        uninited[id] = true;
+                        return;
                     }
-                } else {
-                    ret = req.execCb(fullName, manager.callback, args, defined[fullName]);
-                }
-
-                if (fullName) {
-                    //If setting exports via "module" is in play,
-                    //favor that over return value and exports. After that,
-                    //favor a non-undefined return value over exports use.
-                    cjsModule = manager.cjsModule;
-                    if (cjsModule &&
-                        cjsModule.exports !== undefined &&
-                        //Make sure it is not already the exports value
-                        cjsModule.exports !== defined[fullName]) {
-                        ret = defined[fullName] = manager.cjsModule.exports;
-                    } else if (ret === undefined && manager.usingExports) {
-                        //exports already set the defined value.
-                        ret = defined[fullName];
-                    } else {
-                        //Use the return value from the function.
-                        defined[fullName] = ret;
-                        //If this module needed full execution in a build
-                        //environment, mark that now.
-                        if (needFullExec[fullName]) {
-                            fullExec[fullName] = true;
+
+                    //Get the value for the current dependency
+                    value = forceExec(depMod, traced, uninited);
+
+                    //Even with forcing it may not be done,
+                    //in particular if the module is waiting
+                    //on a plugin resource.
+                    if (!uninited[depId]) {
+                        mod.defineDepById(depId, value);
+                    }
+                }
+            });
+
+            mod.check(true);
+
+            return defined[id];
+        }
+
+        function modCheck(mod) {
+            mod.check();
+        }
+
+        function checkLoaded() {
+            var map, modId, err, usingPathFallback,
+                waitInterval = config.waitSeconds * 1000,
+                //It is possible to disable the wait interval by using waitSeconds of 0.
+                expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
+                noLoads = [],
+                stillLoading = false,
+                needCycleCheck = true;
+
+            //Do not bother if this call was a result of a cycle break.
+            if (inCheckLoaded) {
+                return;
+            }
+
+            inCheckLoaded = true;
+
+            //Figure out the state of all the modules.
+            eachProp(registry, function (mod) {
+                map = mod.map;
+                modId = map.id;
+
+                //Skip things that are not enabled or in error state.
+                if (!mod.enabled) {
+                    return;
+                }
+
+                if (!mod.error) {
+                    //If the module should be executed, and it has not
+                    //been inited and time is up, remember it.
+                    if (!mod.inited && expired) {
+                        if (hasPathFallback(modId)) {
+                            usingPathFallback = true;
+                            stillLoading = true;
+                        } else {
+                            noLoads.push(modId);
+                            removeScript(modId);
+                        }
+                    } else if (!mod.inited && mod.fetched && map.isDefine) {
+                        stillLoading = true;
+                        if (!map.prefix) {
+                            //No reason to keep looking for unfinished
+                            //loading. If the only stillLoading is a
+                            //plugin resource though, keep going,
+                            //because it may be that a plugin resource
+                            //is waiting on a non-plugin cycle.
+                            return (needCycleCheck = false);
                         }
                     }
                 }
-            } else if (fullName) {
-                //May just be an object definition for the module. Only
-                //worry about defining if have a module name.
-                ret = defined[fullName] = cb;
-
-                //If this module needed full execution in a build
-                //environment, mark that now.
-                if (needFullExec[fullName]) {
-                    fullExec[fullName] = true;
-                }
-            }
-
-            //Clean up waiting. Do this before error calls, and before
-            //calling back listeners, so that bookkeeping is correct
-            //in the event of an error and error is reported in correct order,
-            //since the listeners will likely have errors if the
-            //onError function does not throw.
-            if (waiting[manager.id]) {
-                delete waiting[manager.id];
-                manager.isDone = true;
-                context.waitCount -= 1;
-                if (context.waitCount === 0) {
-                    //Clear the wait array used for cycles.
-                    waitAry = [];
-                }
-            }
-
-            //Do not need to track manager callback now that it is defined.
-            delete managerCallbacks[fullName];
-
-            //Allow instrumentation like the optimizer to know the order
-            //of modules executed and their dependencies.
-            if (req.onResourceLoad && !manager.placeholder) {
-                req.onResourceLoad(context, map, manager.depArray);
-            }
-
-            if (err) {
-                errFile = (fullName ? makeModuleMap(fullName).url : '') ||
-                           err.fileName || err.sourceURL;
-                errModuleTree = err.moduleTree;
-                err = makeError('defineerror', 'Error evaluating ' +
-                                'module "' + fullName + '" at location "' +
-                                errFile + '":\n' +
-                                err + '\nfileName:' + errFile +
-                                '\nlineNumber: ' + (err.lineNumber || err.line), err);
-                err.moduleName = fullName;
-                err.moduleTree = errModuleTree;
-                return req.onError(err);
-            }
-
-            //Let listeners know of this manager's value.
-            for (i = 0; (cb = listeners[i]); i++) {
-                cb(ret);
-            }
-
-            return undefined;
-        }
-
-        /**
-         * Helper that creates a callack function that is called when a dependency
-         * is ready, and sets the i-th dependency for the manager as the
-         * value passed to the callback generated by this function.
-         */
-        function makeArgCallback(manager, i) {
-            return function (value) {
-                //Only do the work if it has not been done
-                //already for a dependency. Cycle breaking
-                //logic in forceExec could mean this function
-                //is called more than once for a given dependency.
-                if (!manager.depDone[i]) {
-                    manager.depDone[i] = true;
-                    manager.deps[i] = value;
-                    manager.depCount -= 1;
-                    if (!manager.depCount) {
-                        //All done, execute!
-                        execManager(manager);
-                    }
-                }
-            };
-        }
-
-        function callPlugin(pluginName, depManager) {
-            var map = depManager.map,
-                fullName = map.fullName,
-                name = map.name,
-                plugin = plugins[pluginName] ||
-                        (plugins[pluginName] = defined[pluginName]),
-                load;
-
-            //No need to continue if the manager is already
-            //in the process of loading.
-            if (depManager.loading) {
-                return;
-            }
-            depManager.loading = true;
-
-            load = function (ret) {
-                depManager.callback = function () {
-                    return ret;
-                };
-                execManager(depManager);
-
-                loaded[depManager.id] = true;
-
-                //The loading of this plugin
-                //might have placed other things
-                //in the paused queue. In particular,
-                //a loader plugin that depends on
-                //a different plugin loaded resource.
-                resume();
-            };
-
-            //Allow plugins to load other code without having to know the
-            //context or how to "complete" the load.
-            load.fromText = function (moduleName, text) {
-                /*jslint evil: true */
-                var hasInteractive = useInteractive;
-
-                //Indicate a the module is in process of loading.
-                loaded[moduleName] = false;
-                context.scriptCount += 1;
-
-                //Indicate this is not a "real" module, so do not track it
-                //for builds, it does not map to a real file.
-                context.fake[moduleName] = true;
-
-                //Turn off interactive script matching for IE for any define
-                //calls in the text, then turn it back on at the end.
-                if (hasInteractive) {
-                    useInteractive = false;
-                }
-
-                req.exec(text);
-
-                if (hasInteractive) {
-                    useInteractive = true;
-                }
-
-                //Support anonymous modules.
-                context.completeLoad(moduleName);
-            };
-
-            //No need to continue if the plugin value has already been
-            //defined by a build.
-            if (fullName in defined) {
-                load(defined[fullName]);
-            } else {
-                //Use parentName here since the plugin's name is not reliable,
-                //could be some weird string with no path that actually wants to
-                //reference the parentName's path.
-                plugin.load(name, makeRequire(map.parentMap, true), load, config);
-            }
-        }
-
-        /**
-         * Adds the manager to the waiting queue. Only fully
-         * resolved items should be in the waiting queue.
-         */
-        function addWait(manager) {
-            if (!waiting[manager.id]) {
-                waiting[manager.id] = manager;
-                waitAry.push(manager);
-                context.waitCount += 1;
-            }
-        }
-
-        /**
-         * Function added to every manager object. Created out here
-         * to avoid new function creation for each manager instance.
-         */
-        function managerAdd(cb) {
-            this.listeners.push(cb);
-        }
-
-        function getManager(map, shouldQueue) {
-            var fullName = map.fullName,
-                prefix = map.prefix,
-                plugin = prefix ? plugins[prefix] ||
-                                (plugins[prefix] = defined[prefix]) : null,
-                manager, created, pluginManager;
-
-            if (fullName) {
-                manager = managerCallbacks[fullName];
-            }
-
-            if (!manager) {
-                created = true;
-                manager = {
-                    //ID is just the full name, but if it is a plugin resource
-                    //for a plugin that has not been loaded,
-                    //then add an ID counter to it.
-                    id: (prefix && !plugin ?
-                        (managerCounter++) + '__p@:' : '') +
-                        (fullName || '__r@' + (managerCounter++)),
-                    map: map,
-                    depCount: 0,
-                    depDone: [],
-                    depCallbacks: [],
-                    deps: [],
-                    listeners: [],
-                    add: managerAdd
-                };
-
-                specified[manager.id] = true;
-
-                //Only track the manager/reuse it if this is a non-plugin
-                //resource. Also only track plugin resources once
-                //the plugin has been loaded, and so the fullName is the
-                //true normalized value.
-                if (fullName && (!prefix || plugins[prefix])) {
-                    managerCallbacks[fullName] = manager;
-                }
-            }
-
-            //If there is a plugin needed, but it is not loaded,
-            //first load the plugin, then continue on.
-            if (prefix && !plugin) {
-                pluginManager = getManager(makeModuleMap(prefix), true);
-                pluginManager.add(function (plugin) {
-                    //Create a new manager for the normalized
-                    //resource ID and have it call this manager when
-                    //done.
-                    var newMap = makeModuleMap(map.originalName, map.parentMap),
-                        normalizedManager = getManager(newMap, true);
-
-                    //Indicate this manager is a placeholder for the real,
-                    //normalized thing. Important for when trying to map
-                    //modules and dependencies, for instance, in a build.
-                    manager.placeholder = true;
-
-                    normalizedManager.add(function (resource) {
-                        manager.callback = function () {
-                            return resource;
-                        };
-                        execManager(manager);
-                    });
-                });
-            } else if (created && shouldQueue) {
-                //Indicate the resource is not loaded yet if it is to be
-                //queued.
-                loaded[manager.id] = false;
-                queueDependency(manager);
-                addWait(manager);
-            }
-
-            return manager;
-        }
-
-        function main(inName, depArray, callback, relModuleMap) {
-            var moduleMap = makeModuleMap(inName, relModuleMap),
-                name = moduleMap.name,
-                fullName = moduleMap.fullName,
-                manager = getManager(moduleMap),
-                id = manager.id,
-                deps = manager.deps,
-                i, depArg, depName, depPrefix, cjsMod;
-
-            if (fullName) {
-                //If module already defined for context, or already loaded,
-                //then leave. Also leave if jQuery is registering but it does
-                //not match the desired version number in the config.
-                if (fullName in defined || loaded[id] === true ||
-                    (fullName === "jquery" && config.jQuery &&
-                     config.jQuery !== callback().fn.jquery)) {
-                    return;
-                }
-
-                //Set specified/loaded here for modules that are also loaded
-                //as part of a layer, where onScriptLoad is not fired
-                //for those cases. Do this after the inline define and
-                //dependency tracing is done.
-                specified[id] = true;
-                loaded[id] = true;
-
-                //If module is jQuery set up delaying its dom ready listeners.
-                if (fullName === "jquery" && callback) {
-                    jQueryCheck(callback());
-                }
-            }
-
-            //Attach real depArray and callback to the manager. Do this
-            //only if the module has not been defined already, so do this after
-            //the fullName checks above. IE can call main() more than once
-            //for a module.
-            manager.depArray = depArray;
-            manager.callback = callback;
-
-            //Add the dependencies to the deps field, and register for callbacks
-            //on the dependencies.
-            for (i = 0; i < depArray.length; i++) {
-                depArg = depArray[i];
-                //There could be cases like in IE, where a trailing comma will
-                //introduce a null dependency, so only treat a real dependency
-                //value as a dependency.
-                if (depArg) {
-                    //Split the dependency name into plugin and name parts
-                    depArg = makeModuleMap(depArg, (name ? moduleMap : relModuleMap));
-                    depName = depArg.fullName;
-                    depPrefix = depArg.prefix;
-
-                    //Fix the name in depArray to be just the name, since
-                    //that is how it will be called back later.
-                    depArray[i] = depName;
-
-                    //Fast path CommonJS standard dependencies.
-                    if (depName === "require") {
-                        deps[i] = makeRequire(moduleMap);
-                    } else if (depName === "exports") {
-                        //CommonJS module spec 1.1
-                        deps[i] = defined[fullName] = {};
-                        manager.usingExports = true;
-                    } else if (depName === "module") {
-                        //CommonJS module spec 1.1
-                        manager.cjsModule = cjsMod = deps[i] = {
-                            id: name,
-                            uri: name ? context.nameToUrl(name, null, relModuleMap) : undefined,
-                            exports: defined[fullName]
-                        };
-                    } else if (depName in defined && !(depName in waiting) &&
-                               (!(fullName in needFullExec) ||
-                                (fullName in needFullExec && fullExec[depName]))) {
-                        //Module already defined, and not in a build situation
-                        //where the module is a something that needs full
-                        //execution and this dependency has not been fully
-                        //executed. See r.js's requirePatch.js for more info
-                        //on fullExec.
-                        deps[i] = defined[depName];
-                    } else {
-                        //Mark this dependency as needing full exec if
-                        //the current module needs full exec.
-                        if (fullName in needFullExec) {
-                            needFullExec[depName] = true;
-                            //Reset state so fully executed code will get
-                            //picked up correctly.
-                            delete defined[depName];
-                            urlFetched[depArg.url] = false;
-                        }
-
-                        //Either a resource that is not loaded yet, or a plugin
-                        //resource for either a plugin that has not
-                        //loaded yet.
-                        manager.depCount += 1;
-                        manager.depCallbacks[i] = makeArgCallback(manager, i);
-                        getManager(depArg, true).add(manager.depCallbacks[i]);
-                    }
-                }
-            }
-
-            //Do not bother tracking the manager if it is all done.
-            if (!manager.depCount) {
-                //All done, execute!
-                execManager(manager);
-            } else {
-                addWait(manager);
-            }
-        }
-
-        /**
-         * Convenience method to call main for a define call that was put on
-         * hold in the defQueue.
-         */
-        function callDefMain(args) {
-            main.apply(null, args);
-        }
-
-        /**
-         * jQuery 1.4.3+ supports ways to hold off calling
-         * calling jQuery ready callbacks until all scripts are loaded. Be sure
-         * to track it if the capability exists.. Also, since jQuery 1.4.3 does
-         * not register as a module, need to do some global inference checking.
-         * Even if it does register as a module, not guaranteed to be the precise
-         * name of the global. If a jQuery is tracked for this context, then go
-         * ahead and register it as a module too, if not already in process.
-         */
-        jQueryCheck = function (jqCandidate) {
-            if (!context.jQuery) {
-                var $ = jqCandidate || (typeof jQuery !== "undefined" ? jQuery : null);
-
-                if ($) {
-                    //If a specific version of jQuery is wanted, make sure to only
-                    //use this jQuery if it matches.
-                    if (config.jQuery && $.fn.jquery !== config.jQuery) {
+            });
+
+            if (expired && noLoads.length) {
+                //If wait time expired, throw error of unloaded modules.
+                err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
+                err.contextName = context.contextName;
+                return onError(err);
+            }
+
+            //Not expired, check for a cycle.
+            if (needCycleCheck) {
+
+                each(waitAry, function (mod) {
+                    if (mod.defined) {
                         return;
                     }
 
-                    if ("holdReady" in $ || "readyWait" in $) {
-                        context.jQuery = $;
-
-                        //Manually create a "jquery" module entry if not one already
-                        //or in process. Note this could trigger an attempt at
-                        //a second jQuery registration, but does no harm since
-                        //the first one wins, and it is the same value anyway.
-                        callDefMain(["jquery", [], function () {
-                            return jQuery;
-                        }]);
-
-                        //Ask jQuery to hold DOM ready callbacks.
-                        if (context.scriptCount) {
-                            jQueryHoldReady($, true);
-                            context.jQueryIncremented = true;
-                        }
+                    var cycleMod = findCycle(mod, {}, {}),
+                        traced = {};
+
+                    if (cycleMod) {
+                        forceExec(cycleMod, traced, {});
+
+                        //traced modules may have been
+                        //removed from the registry, but
+                        //their listeners still need to
+                        //be called.
+                        eachProp(traced, modCheck);
                     }
-                }
-            }
-        };
-
-        function forceExec(manager, traced) {
-            if (manager.isDone) {
-                return undefined;
-            }
-
-            var fullName = manager.map.fullName,
-                depArray = manager.depArray,
-                i, depName, depManager, prefix, prefixManager, value;
-
-            if (fullName) {
-                if (traced[fullName]) {
-                    return defined[fullName];
-                }
-
-                traced[fullName] = true;
-            }
-
-            //Trace through the dependencies.
-            if (depArray) {
-                for (i = 0; i < depArray.length; i++) {
-                    //Some array members may be null, like if a trailing comma
-                    //IE, so do the explicit [i] access and check if it has a value.
-                    depName = depArray[i];
-                    if (depName) {
-                        //First, make sure if it is a plugin resource that the
-                        //plugin is not blocked.
-                        prefix = makeModuleMap(depName).prefix;
-                        if (prefix && (prefixManager = waiting[prefix])) {
-                            forceExec(prefixManager, traced);
-                        }
-                        depManager = waiting[depName];
-                        if (depManager && !depManager.isDone && loaded[depName]) {
-                            value = forceExec(depManager, traced);
-                            manager.depCallbacks[i](value);
-                        }
-                    }
-                }
-            }
-
-            return fullName ? defined[fullName] : undefined;
-        }
-
-        /**
-         * Checks if all modules for a context are loaded, and if so, evaluates the
-         * new ones in right dependency order.
-         *
-         * @private
-         */
-        function checkLoaded() {
-            var waitInterval = config.waitSeconds * 1000,
-                //It is possible to disable the wait interval by using waitSeconds of 0.
-                expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
-                noLoads = "", hasLoadedProp = false, stillLoading = false, prop,
-                err, manager;
-
-            //If there are items still in the paused queue processing wait.
-            //This is particularly important in the sync case where each paused
-            //item is processed right away but there may be more waiting.
-            if (context.pausedCount > 0) {
-                return undefined;
-            }
-
-            //Determine if priority loading is done. If so clear the priority. If
-            //not, then do not check
-            if (config.priorityWait) {
-                if (isPriorityDone()) {
-                    //Call resume, since it could have
-                    //some waiting dependencies to trace.
-                    resume();
-                } else {
-                    return undefined;
-                }
-            }
-
-            //See if anything is still in flight.
-            for (prop in loaded) {
-                if (!(prop in empty)) {
-                    hasLoadedProp = true;
-                    if (!loaded[prop]) {
-                        if (expired) {
-                            noLoads += prop + " ";
-                        } else {
-                            stillLoading = true;
-                            break;
-                        }
-                    }
-                }
-            }
-
-            //Check for exit conditions.
-            if (!hasLoadedProp && !context.waitCount) {
-                //If the loaded object had no items, then the rest of
-                //the work below does not need to be done.
-                return undefined;
-            }
-            if (expired && noLoads) {
-                //If wait time expired, throw error of unloaded modules.
-                err = makeError("timeout", "Load timeout for modules: " + noLoads);
-                err.requireType = "timeout";
-                err.requireModules = noLoads;
-                return req.onError(err);
-            }
-            if (stillLoading || context.scriptCount) {
+                });
+
+                //Now that dependencies have
+                //been satisfied, trigger the
+                //completion check that then
+                //notifies listeners.
+                eachProp(registry, modCheck);
+            }
+
+            //If still waiting on loads, and the waiting load is something
+            //other than a plugin resource, or there are still outstanding
+            //scripts, then just try back later.
+            if ((!expired || usingPathFallback) && stillLoading) {
                 //Something is still waiting to load. Wait for it, but only
                 //if a timeout is not already in effect.
                 if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
@@ -1068,235 +906,578 @@
                         checkLoaded();
                     }, 50);
                 }
-                return undefined;
-            }
-
-            //If still have items in the waiting cue, but all modules have
-            //been loaded, then it means there are some circular dependencies
-            //that need to be broken.
-            //However, as a waiting thing is fired, then it can add items to
-            //the waiting cue, and those items should not be fired yet, so
-            //make sure to redo the checkLoaded call after breaking a single
-            //cycle, if nothing else loaded then this logic will pick it up
-            //again.
-            if (context.waitCount) {
-                //Cycle through the waitAry, and call items in sequence.
-                for (i = 0; (manager = waitAry[i]); i++) {
-                    forceExec(manager, {});
-                }
-
-                //If anything got placed in the paused queue, run it down.
-                if (context.paused.length) {
-                    resume();
-                }
-
-                //Only allow this recursion to a certain depth. Only
-                //triggered by errors in calling a module in which its
-                //modules waiting on it cannot finish loading, or some circular
-                //dependencies that then may add more dependencies.
-                //The value of 5 is a bit arbitrary. Hopefully just one extra
-                //pass, or two for the case of circular dependencies generating
-                //more work that gets resolved in the sync node case.
-                if (checkLoadedDepth < 5) {
-                    checkLoadedDepth += 1;
-                    checkLoaded();
-                }
-            }
-
-            checkLoadedDepth = 0;
-
-            //Check for DOM ready, and nothing is waiting across contexts.
-            req.checkReadyState();
-
-            return undefined;
-        }
-
-        /**
-         * Resumes tracing of dependencies and then checks if everything is loaded.
-         */
-        resume = function () {
-            var manager, map, url, i, p, args, fullName;
-
-            resumeDepth += 1;
-
-            if (context.scriptCount <= 0) {
-                //Synchronous envs will push the number below zero with the
-                //decrement above, be sure to set it back to zero for good measure.
-                //require() calls that also do not end up loading scripts could
-                //push the number negative too.
-                context.scriptCount = 0;
-            }
-
-            //Make sure any remaining defQueue items get properly processed.
-            while (defQueue.length) {
-                args = defQueue.shift();
-                if (args[0] === null) {
-                    return req.onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+            }
+
+            inCheckLoaded = false;
+        }
+
+        Module = function (map) {
+            this.events = undefEvents[map.id] || {};
+            this.map = map;
+            this.shim = config.shim[map.id];
+            this.depExports = [];
+            this.depMaps = [];
+            this.depMatched = [];
+            this.pluginMaps = {};
+            this.depCount = 0;
+
+            /* this.exports this.factory
+               this.depMaps = [],
+               this.enabled, this.fetched
+            */
+        };
+
+        Module.prototype = {
+            init: function (depMaps, factory, errback, options) {
+                options = options || {};
+
+                //Do not do more inits if already done. Can happen if there
+                //are multiple define calls for the same module. That is not
+                //a normal, common case, but it is also not unexpected.
+                if (this.inited) {
+                    return;
+                }
+
+                this.factory = factory;
+
+                if (errback) {
+                    //Register for errors on this module.
+                    this.on('error', errback);
+                } else if (this.events.error) {
+                    //If no errback already, but there are error listeners
+                    //on this module, set up an errback to pass to the deps.
+                    errback = bind(this, function (err) {
+                        this.emit('error', err);
+                    });
+                }
+
+                //Do a copy of the dependency array, so that
+                //source inputs are not modified. For example
+                //"shim" deps are passed in here directly, and
+                //doing a direct modification of the depMaps array
+                //would affect that config.
+                this.depMaps = depMaps && depMaps.slice(0);
+                this.depMaps.rjsSkipMap = depMaps.rjsSkipMap;
+
+                this.errback = errback;
+
+                //Indicate this module has be initialized
+                this.inited = true;
+
+                this.ignore = options.ignore;
+
+                //Could have option to init this module in enabled mode,
+                //or could have been previously marked as enabled. However,
+                //the dependencies are not known until init is called. So
+                //if enabled previously, now trigger dependencies as enabled.
+                if (options.enabled || this.enabled) {
+                    //Enable this module and dependencies.
+                    //Will call this.check()
+                    this.enable();
                 } else {
-                    callDefMain(args);
-                }
-            }
-
-            //Skip the resume of paused dependencies
-            //if current context is in priority wait.
-            if (!config.priorityWait || isPriorityDone()) {
-                while (context.paused.length) {
-                    p = context.paused;
-                    context.pausedCount += p.length;
-                    //Reset paused list
-                    context.paused = [];
-
-                    for (i = 0; (manager = p[i]); i++) {
-                        map = manager.map;
-                        url = map.url;
-                        fullName = map.fullName;
-
-                        //If the manager is for a plugin managed resource,
-                        //ask the plugin to load it now.
-                        if (map.prefix) {
-                            callPlugin(map.prefix, manager);
-                        } else {
-                            //Regular dependency.
-                            if (!urlFetched[url] && !loaded[fullName]) {
-                                req.load(context, fullName, url);
-
-                                //Mark the URL as fetched, but only if it is
-                                //not an empty: URL, used by the optimizer.
-                                //In that case we need to be sure to call
-                                //load() for each module that is mapped to
-                                //empty: so that dependencies are satisfied
-                                //correctly.
-                                if (url.indexOf('empty:') !== 0) {
-                                    urlFetched[url] = true;
+                    this.check();
+                }
+            },
+
+            defineDepById: function (id, depExports) {
+                var i;
+
+                //Find the index for this dependency.
+                each(this.depMaps, function (map, index) {
+                    if (map.id === id) {
+                        i = index;
+                        return true;
+                    }
+                });
+
+                return this.defineDep(i, depExports);
+            },
+
+            defineDep: function (i, depExports) {
+                //Because of cycles, defined callback for a given
+                //export can be called more than once.
+                if (!this.depMatched[i]) {
+                    this.depMatched[i] = true;
+                    this.depCount -= 1;
+                    this.depExports[i] = depExports;
+                }
+            },
+
+            fetch: function () {
+                if (this.fetched) {
+                    return;
+                }
+                this.fetched = true;
+
+                context.startTime = (new Date()).getTime();
+
+                var map = this.map;
+
+                //If the manager is for a plugin managed resource,
+                //ask the plugin to load it now.
+                if (this.shim) {
+                    makeRequire(this, true)(this.shim.deps || [], bind(this, function () {
+                        return map.prefix ? this.callPlugin() : this.load();
+                    }));
+                } else {
+                    //Regular dependency.
+                    return map.prefix ? this.callPlugin() : this.load();
+                }
+            },
+
+            load: function () {
+                var url = this.map.url;
+
+                //Regular dependency.
+                if (!urlFetched[url]) {
+                    urlFetched[url] = true;
+                    context.load(this.map.id, url);
+                }
+            },
+
+            /**
+             * Checks is the module is ready to define itself, and if so,
+             * define it. If the silent argument is true, then it will just
+             * define, but not notify listeners, and not ask for a context-wide
+             * check of all loaded modules. That is useful for cycle breaking.
+             */
+            check: function (silent) {
+                if (!this.enabled || this.enabling) {
+                    return;
+                }
+
+                var err, cjsModule,
+                    id = this.map.id,
+                    depExports = this.depExports,
+                    exports = this.exports,
+                    factory = this.factory;
+
+                if (!this.inited) {
+                    this.fetch();
+                } else if (this.error) {
+                    this.emit('error', this.error);
+                } else if (!this.defining) {
+                    //The factory could trigger another require call
+                    //that would result in checking this module to
+                    //define itself again. If already in the process
+                    //of doing that, skip this work.
+                    this.defining = true;
+
+                    if (this.depCount < 1 && !this.defined) {
+                        if (isFunction(factory)) {
+                            //If there is an error listener, favor passing
+                            //to that instead of throwing an error.
+                            if (this.events.error) {
+                                try {
+                                    exports = context.execCb(id, factory, depExports, exports);
+                                } catch (e) {
+                                    err = e;
+                                }
+                            } else {
+                                exports = context.execCb(id, factory, depExports, exports);
+                            }
+
+                            if (this.map.isDefine) {
+                                //If setting exports via 'module' is in play,
+                                //favor that over return value and exports. After that,
+                                //favor a non-undefined return value over exports use.
+                                cjsModule = this.module;
+                                if (cjsModule &&
+                                        cjsModule.exports !== undefined &&
+                                        //Make sure it is not already the exports value
+                                        cjsModule.exports !== this.exports) {
+                                    exports = cjsModule.exports;
+                                } else if (exports === undefined && this.usingExports) {
+                                    //exports already set the defined value.
+                                    exports = this.exports;
                                 }
                             }
+
+                            if (err) {
+                                err.requireMap = this.map;
+                                err.requireModules = [this.map.id];
+                                err.requireType = 'define';
+                                return onError((this.error = err));
+                            }
+
+                        } else {
+                            //Just a literal value
+                            exports = factory;
+                        }
+
+                        this.exports = exports;
+
+                        if (this.map.isDefine && !this.ignore) {
+                            defined[id] = exports;
+
+                            if (req.onResourceLoad) {
+                                req.onResourceLoad(context, this.map, this.depMaps);
+                            }
+                        }
+
+                        //Clean up
+                        delete registry[id];
+
+                        this.defined = true;
+                        context.waitCount -= 1;
+                        if (context.waitCount === 0) {
+                            //Clear the wait array used for cycles.
+                            waitAry = [];
                         }
                     }
 
-                    //Move the start time for timeout forward.
-                    context.startTime = (new Date()).getTime();
-                    context.pausedCount -= p.length;
-                }
-            }
-
-            //Only check if loaded when resume depth is 1. It is likely that
-            //it is only greater than 1 in sync environments where a factory
-            //function also then calls the callback-style require. In those
-            //cases, the checkLoaded should not occur until the resume
-            //depth is back at the top level.
-            if (resumeDepth === 1) {
-                checkLoaded();
-            }
-
-            resumeDepth -= 1;
-
-            return undefined;
-        };
-
-        //Define the context object. Many of these fields are on here
-        //just to make debugging easier.
-        context = {
+                    //Finished the define stage. Allow calling check again
+                    //to allow define notifications below in the case of a
+                    //cycle.
+                    this.defining = false;
+
+                    if (!silent) {
+                        if (this.defined && !this.defineEmitted) {
+                            this.defineEmitted = true;
+                            this.emit('defined', this.exports);
+                            this.defineEmitComplete = true;
+                        }
+                    }
+                }
+            },
+
+            callPlugin: function () {
+                var map = this.map,
+                    id = map.id,
+                    pluginMap = makeModuleMap(map.prefix, null, false, true);
+
+                on(pluginMap, 'defined', bind(this, function (plugin) {
+                    var load, normalizedMap, normalizedMod,
+                        name = this.map.name,
+                        parentName = this.map.parentMap ? this.map.parentMap.name : null;
+
+                    //If current map is not normalized, wait for that
+                    //normalized name to load instead of continuing.
+                    if (this.map.unnormalized) {
+                        //Normalize the ID if the plugin allows it.
+                        if (plugin.normalize) {
+                            name = plugin.normalize(name, function (name) {
+                                return normalize(name, parentName, true);
+                            }) || '';
+                        }
+
+                        normalizedMap = makeModuleMap(map.prefix + '!' + name,
+                                                      this.map.parentMap,
+                                                      false,
+                                                      true);
+                        on(normalizedMap,
+                            'defined', bind(this, function (value) {
+                                this.init([], function () { return value; }, null, {
+                                    enabled: true,
+                                    ignore: true
+                                });
+                            }));
+                        normalizedMod = registry[normalizedMap.id];
+                        if (normalizedMod) {
+                            if (this.events.error) {
+                                normalizedMod.on('error', bind(this, function (err) {
+                                    this.emit('error', err);
+                                }));
+                            }
+                            normalizedMod.enable();
+                        }
+
+                        return;
+                    }
+
+                    load = bind(this, function (value) {
+                        this.init([], function () { return value; }, null, {
+                            enabled: true
+                        });
+                    });
+
+                    load.error = bind(this, function (err) {
+                        this.inited = true;
+                        this.error = err;
+                        err.requireModules = [id];
+
+                        //Remove temp unnormalized modules for this module,
+                        //since they will never be resolved otherwise now.
+                        eachProp(registry, function (mod) {
+                            if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
+                                removeWaiting(mod.map.id);
+                            }
+                        });
+
+                        onError(err);
+                    });
+
+                    //Allow plugins to load other code without having to know the
+                    //context or how to 'complete' the load.
+                    load.fromText = function (moduleName, text) {
+                        /*jslint evil: true */
+                        var hasInteractive = useInteractive;
+
+                        //Turn off interactive script matching for IE for any define
+                        //calls in the text, then turn it back on at the end.
+                        if (hasInteractive) {
+                            useInteractive = false;
+                        }
+
+                        //Prime the system by creating a module instance for
+                        //it.
+                        getModule(makeModuleMap(moduleName));
+
+                        req.exec(text);
+
+                        if (hasInteractive) {
+                            useInteractive = true;
+                        }
+
+                        //Support anonymous modules.
+                        context.completeLoad(moduleName);
+                    };
+
+                    //Use parentName here since the plugin's name is not reliable,
+                    //could be some weird string with no path that actually wants to
+                    //reference the parentName's path.
+                    plugin.load(map.name, makeRequire(map.parentMap, true, function (deps, cb, er) {
+                        deps.rjsSkipMap = true;
+                        return context.require(deps, cb, er);
+                    }), load, config);
+                }));
+
+                context.enable(pluginMap, this);
+                this.pluginMaps[pluginMap.id] = pluginMap;
+            },
+
+            enable: function () {
+                this.enabled = true;
+
+                if (!this.waitPushed) {
+                    waitAry.push(this);
+                    context.waitCount += 1;
+                    this.waitPushed = true;
+                }
+
+                //Set flag mentioning that the module is enabling,
+                //so that immediate calls to the defined callbacks
+                //for dependencies do not trigger inadvertent load
+                //with the depCount still being zero.
+                this.enabling = true;
+
+                //Enable each dependency
+                each(this.depMaps, bind(this, function (depMap, i) {
+                    var id, mod, handler;
+
+                    if (typeof depMap === 'string') {
+                        //Dependency needs to be converted to a depMap
+                        //and wired up to this module.
+                        depMap = makeModuleMap(depMap,
+                                               (this.map.isDefine ? this.map : this.map.parentMap),
+                                               false,
+                                               !this.depMaps.rjsSkipMap);
+                        this.depMaps[i] = depMap;
+
+                        handler = handlers[depMap.id];
+
+                        if (handler) {
+                            this.depExports[i] = handler(this);
+                            return;
+                        }
+
+                        this.depCount += 1;
+
+                        on(depMap, 'defined', bind(this, function (depExports) {
+                            this.defineDep(i, depExports);
+                            this.check();
+                        }));
+
+                        if (this.errback) {
+                            on(depMap, 'error', this.errback);
+                        }
+                    }
+
+                    id = depMap.id;
+                    mod = registry[id];
+
+                    //Skip special modules like 'require', 'exports', 'module'
+                    //Also, don't call enable if it is already enabled,
+                    //important in circular dependency cases.
+                    if (!handlers[id] && mod && !mod.enabled) {
+                        context.enable(depMap, this);
+                    }
+                }));
+
+                //Enable each plugin that is used in
+                //a dependency
+                eachProp(this.pluginMaps, bind(this, function (pluginMap) {
+                    var mod = registry[pluginMap.id];
+                    if (mod && !mod.enabled) {
+                        context.enable(pluginMap, this);
+                    }
+                }));
+
+                this.enabling = false;
+
+                this.check();
+            },
+
+            on: function (name, cb) {
+                var cbs = this.events[name];
+                if (!cbs) {
+                    cbs = this.events[name] = [];
+                }
+                cbs.push(cb);
+            },
+
+            emit: function (name, evt) {
+                each(this.events[name], function (cb) {
+                    cb(evt);
+                });
+                if (name === 'error') {
+                    //Now that the error handler was triggered, remove
+                    //the listeners, since this broken Module instance
+                    //can stay around for a while in the registry/waitAry.
+                    delete this.events[name];
+                }
+            }
+        };
+
+        function callGetModule(args) {
+            getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
+        }
+
+        function removeListener(node, func, name, ieName) {
+            //Favor detachEvent because of IE9
+            //issue, see attachEvent/addEventListener comment elsewhere
+            //in this file.
+            if (node.detachEvent && !isOpera) {
+                //Probably IE. If not it will throw an error, which will be
+                //useful to know.
+                if (ieName) {
+                    node.detachEvent(ieName, func);
+                }
+            } else {
+                node.removeEventListener(name, func, false);
+            }
+        }
+
+        /**
+         * Given an event from a script node, get the requirejs info from it,
+         * and then removes the event listeners on the node.
+         * @param {Event} evt
+         * @returns {Object}
+         */
+        function getScriptData(evt) {
+            //Using currentTarget instead of target for Firefox 2.0's sake. Not
+            //all old browsers will be supported, but this one was easy enough
+            //to support and still makes sense.
+            var node = evt.currentTarget || evt.srcElement;
+
+            //Remove the listeners once here.
+            removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
+            removeListener(node, context.onScriptError, 'error');
+
+            return {
+                node: node,
+                id: node && node.getAttribute('data-requiremodule')
+            };
+        }
+
+        return (context = {
+            config: config,
             contextName: contextName,
-            config: config,
+            registry: registry,
+            defined: defined,
+            urlFetched: urlFetched,
+            waitCount: 0,
             defQueue: defQueue,
-            waiting: waiting,
-            waitCount: 0,
-            specified: specified,
-            loaded: loaded,
-            urlMap: urlMap,
-            urlFetched: urlFetched,
-            scriptCount: 0,
-            defined: defined,
-            paused: [],
-            pausedCount: 0,
-            plugins: plugins,
-            needFullExec: needFullExec,
-            fake: {},
-            fullExec: fullExec,
-            managerCallbacks: managerCallbacks,
+            Module: Module,
             makeModuleMap: makeModuleMap,
-            normalize: normalize,
+
             /**
              * Set a configuration for the context.
              * @param {Object} cfg config object to integrate.
              */
             configure: function (cfg) {
-                var paths, prop, packages, pkgs, packagePaths, requireWait;
-
                 //Make sure the baseUrl ends in a slash.
                 if (cfg.baseUrl) {
-                    if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== "/") {
-                        cfg.baseUrl += "/";
+                    if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
+                        cfg.baseUrl += '/';
                     }
                 }
 
                 //Save off the paths and packages since they require special processing,
                 //they are additive.
-                paths = config.paths;
-                packages = config.packages;
-                pkgs = config.pkgs;
+                var pkgs = config.pkgs,
+                    shim = config.shim,
+                    paths = config.paths,
+                    map = config.map;
 
                 //Mix in the config values, favoring the new values over
                 //existing ones in context.config.
                 mixin(config, cfg, true);
 
-                //Adjust paths if necessary.
-                if (cfg.paths) {
-                    for (prop in cfg.paths) {
-                        if (!(prop in empty)) {
-                            paths[prop] = cfg.paths[prop];
+                //Merge paths.
+                config.paths = mixin(paths, cfg.paths, true);
+
+                //Merge map
+                if (cfg.map) {
+                    config.map = mixin(map || {}, cfg.map, true, true);
+                }
+
+                //Merge shim
+                if (cfg.shim) {
+                    eachProp(cfg.shim, function (value, id) {
+                        //Normalize the structure
+                        if (isArray(value)) {
+                            value = {
+                                deps: value
+                            };
                         }
-                    }
-                    config.paths = paths;
-                }
-
-                packagePaths = cfg.packagePaths;
-                if (packagePaths || cfg.packages) {
-                    //Convert packagePaths into a packages config.
-                    if (packagePaths) {
-                        for (prop in packagePaths) {
-                            if (!(prop in empty)) {
-                                configurePackageDir(pkgs, packagePaths[prop], prop);
-                            }
+                        if (value.exports && !value.exports.__buildReady) {
+                            value.exports = context.makeShimExports(value.exports);
                         }
-                    }
-
-                    //Adjust packages if necessary.
-                    if (cfg.packages) {
-                        configurePackageDir(pkgs, cfg.packages);
-                    }
+                        shim[id] = value;
+                    });
+                    config.shim = shim;
+                }
+
+                //Adjust packages if necessary.
+                if (cfg.packages) {
+                    each(cfg.packages, function (pkgObj) {
+                        var location;
+
+                        pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj;
+                        location = pkgObj.location;
+
+                        //Create a brand new object on pkgs, since currentPackages can
+                        //be passed in again, and config.pkgs is the internal transformed
+                        //state for all package configs.
+                        pkgs[pkgObj.name] = {
+                            name: pkgObj.name,
+                            location: location || pkgObj.name,
+                            //Remove leading dot in main, so main paths are normalized,
+                            //and remove any trailing .js, since different package
+                            //envs have different conventions: some use a module name,
+                            //some use a file name.
+                            main: (pkgObj.main || 'main')
+                                  .replace(currDirRegExp, '')
+                                  .replace(jsSuffixRegExp, '')
+                        };
+                    });
 
                     //Done with modifications, assing packages back to context config
                     config.pkgs = pkgs;
                 }
 
-                //If priority loading is in effect, trigger the loads now
-                if (cfg.priority) {
-                    //Hold on to requireWait value, and reset it after done
-                    requireWait = context.requireWait;
-
-                    //Allow tracing some require calls to allow the fetching
-                    //of the priority config.
-                    context.requireWait = false;
-                    //But first, call resume to register any defined modules that may
-                    //be in a data-main built file before the priority config
-                    //call. Also grab any waiting define calls for this context.
-                    context.takeGlobalQueue();
-                    resume();
-
-                    context.require(cfg.priority);
-
-                    //Trigger a resume right away, for the case when
-                    //the script with the priority load is done as part
-                    //of a data-main call. In that case the normal resume
-                    //call will not happen because the scriptCount will be
-                    //at 1, since the script for data-main is being processed.
-                    resume();
-
-                    //Restore previous state.
-                    context.requireWait = requireWait;
-                    config.priorityWait = cfg.priority;
-                }
+                //If there are any "waiting to execute" modules in the registry,
+                //update the maps for them, since their info, like URLs to load,
+                //may have changed.
+                eachProp(registry, function (mod, id) {
+                    //If module already has init called, since it is too
+                    //late to modify them, and ignore unnormalized ones
+                    //since they are transient.
+                    if (!mod.inited && !mod.map.unnormalized) {
+                        mod.map = makeModuleMap(id);
+                    }
+                });
 
                 //If a deps array or a config callback is specified, then call
                 //require with those args. This is useful when require is defined as a
@@ -1306,81 +1487,136 @@
                 }
             },
 
-            requireDefined: function (moduleName, relModuleMap) {
-                return makeModuleMap(moduleName, relModuleMap).fullName in defined;
+            makeShimExports: function (exports) {
+                var func;
+                if (typeof exports === 'string') {
+                    func = function () {
+                        return getGlobal(exports);
+                    };
+                    //Save the exports for use in nodefine checking.
+                    func.exports = exports;
+                    return func;
+                } else {
+                    return function () {
+                        return exports.apply(global, arguments);
+                    };
+                }
             },
 
-            requireSpecified: function (moduleName, relModuleMap) {
-                return makeModuleMap(moduleName, relModuleMap).fullName in specified;
+            requireDefined: function (id, relMap) {
+                return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
             },
 
-            require: function (deps, callback, relModuleMap) {
-                var moduleName, fullName, moduleMap;
-                if (typeof deps === "string") {
+            requireSpecified: function (id, relMap) {
+                id = makeModuleMap(id, relMap, false, true).id;
+                return hasProp(defined, id) || hasProp(registry, id);
+            },
+
+            require: function (deps, callback, errback, relMap) {
+                var moduleName, id, map, requireMod, args;
+                if (typeof deps === 'string') {
                     if (isFunction(callback)) {
                         //Invalid call
-                        return req.onError(makeError("requireargs", "Invalid require call"));
+                        return onError(makeError('requireargs', 'Invalid require call'), errback);
                     }
 
                     //Synchronous access to one module. If require.get is
                     //available (as in the Node adapter), prefer that.
                     //In this case deps is the moduleName and callback is
-                    //the relModuleMap
+                    //the relMap
                     if (req.get) {
                         return req.get(context, deps, callback);
                     }
 
                     //Just return the module wanted. In this scenario, the
-                    //second arg (if passed) is just the relModuleMap.
+                    //second arg (if passed) is just the relMap.
                     moduleName = deps;
-                    relModuleMap = callback;
+                    relMap = callback;
 
                     //Normalize module name, if it contains . or ..
-                    moduleMap = makeModuleMap(moduleName, relModuleMap);
-                    fullName = moduleMap.fullName;
-
-                    if (!(fullName in defined)) {
-                        return req.onError(makeError("notloaded", "Module name '" +
-                                    moduleMap.fullName +
-                                    "' has not been loaded yet for context: " +
+                    map = makeModuleMap(moduleName, relMap, false, true);
+                    id = map.id;
+
+                    if (!hasProp(defined, id)) {
+                        return onError(makeError('notloaded', 'Module name "' +
+                                    id +
+                                    '" has not been loaded yet for context: ' +
                                     contextName));
                     }
-                    return defined[fullName];
-                }
-
-                //Call main but only if there are dependencies or
-                //a callback to call.
-                if (deps && deps.length || callback) {
-                    main(null, deps, callback, relModuleMap);
-                }
-
-                //If the require call does not trigger anything new to load,
-                //then resume the dependency processing.
-                if (!context.requireWait) {
-                    while (!context.scriptCount && context.paused.length) {
-                        //For built layers, there can be some defined
-                        //modules waiting for intake into the context,
-                        //in particular module plugins. Take them.
-                        context.takeGlobalQueue();
-                        resume();
+                    return defined[id];
+                }
+
+                //Callback require. Normalize args. if callback or errback is
+                //not a function, it means it is a relMap. Test errback first.
+                if (errback && !isFunction(errback)) {
+                    relMap = errback;
+                    errback = undefined;
+                }
+                if (callback && !isFunction(callback)) {
+                    relMap = callback;
+                    callback = undefined;
+                }
+
+                //Any defined modules in the global queue, intake them now.
+                takeGlobalQueue();
+
+                //Make sure any remaining defQueue items get properly processed.
+                while (defQueue.length) {
+                    args = defQueue.shift();
+                    if (args[0] === null) {
+                        return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1]));
+                    } else {
+                        //args are id, deps, factory. Should be normalized by the
+                        //define() function.
+                        callGetModule(args);
                     }
                 }
+
+                //Mark all the dependencies as needing to be loaded.
+                requireMod = getModule(makeModuleMap(null, relMap));
+
+                requireMod.init(deps, callback, errback, {
+                    enabled: true
+                });
+
+                checkLoaded();
+
                 return context.require;
             },
 
+            undef: function (id) {
+                //Bind any waiting define() calls to this context,
+                //fix for #408
+                takeGlobalQueue();
+
+                var map = makeModuleMap(id, null, true),
+                    mod = registry[id];
+
+                delete defined[id];
+                delete urlFetched[map.url];
+                delete undefEvents[id];
+
+                if (mod) {
+                    //Hold on to listeners in case the
+                    //module will be attempted to be reloaded
+                    //using a different config.
+                    if (mod.events.defined) {
+                        undefEvents[id] = mod.events;
+                    }
+
+                    removeWaiting(id);
+                }
+            },
+
             /**
-             * Internal method to transfer globalQueue items to this context's
-             * defQueue.
+             * Called to enable a module if it is still in the registry
+             * awaiting enablement. parent module is passed in for context,
+             * used by the optimizer.
              */
-            takeGlobalQueue: function () {
-                //Push all the globalDefQueue items into the context's defQueue
-                if (globalDefQueue.length) {
-                    //Array splice in the values since the context code has a
-                    //local var ref to defQueue, so cannot just reassign the one
-                    //on context.
-                    apsp.apply(context.defQueue,
-                               [context.defQueue.length - 1, 0].concat(globalDefQueue));
-                    globalDefQueue = [];
+            enable: function (depMap, parent) {
+                var mod = registry[depMap.id];
+                if (mod) {
+                    getModule(depMap).enable();
                 }
             },
 
@@ -1391,56 +1627,53 @@
              * @param {String} moduleName the name of the module to potentially complete.
              */
             completeLoad: function (moduleName) {
-                var args;
-
-                context.takeGlobalQueue();
+                var found, args, mod,
+                    shim = config.shim[moduleName] || {},
+                    shExports = shim.exports && shim.exports.exports;
+
+                takeGlobalQueue();
 
                 while (defQueue.length) {
                     args = defQueue.shift();
-
                     if (args[0] === null) {
                         args[0] = moduleName;
-                        break;
+                        //If already found an anonymous module and bound it
+                        //to this name, then this is some other anon module
+                        //waiting for its completeLoad to fire.
+                        if (found) {
+                            break;
+                        }
+                        found = true;
                     } else if (args[0] === moduleName) {
                         //Found matching define call for this script!
-                        break;
+                        found = true;
+                    }
+
+                    callGetModule(args);
+                }
+
+                //Do this after the cycle of callGetModule in case the result
+                //of those calls/init calls changes the registry.
+                mod = registry[moduleName];
+
+                if (!found && !defined[moduleName] && mod && !mod.inited) {
+                    if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
+                        if (hasPathFallback(moduleName)) {
+                            return;
+                        } else {
+                            return onError(makeError('nodefine',
+                                             'No define call for ' + moduleName,
+                                             null,
+                                             [moduleName]));
+                        }
                     } else {
-                        //Some other named define call, most likely the result
-                        //of a build layer that included many define calls.
-                        callDefMain(args);
-                        args = null;
+                        //A script that does not call define(), so just simulate
+                        //the call for it.
+                        callGetModule([moduleName, (shim.deps || []), shim.exports]);
                     }
                 }
-                if (args) {
-                    callDefMain(args);
-                } else {
-                    //A script that does not call define(), so just simulate
-                    //the call for it. Special exception for jQuery dynamic load.
-                    callDefMain([moduleName, [],
-                                moduleName === "jquery" && typeof jQuery !== "undefined" ?
-                                function () {
-                                    return jQuery;
-                                } : null]);
-                }
-
-                //If a global jQuery is defined, check for it. Need to do it here
-                //instead of main() since stock jQuery does not register as
-                //a module via define.
-                jQueryCheck();
-
-                //Doing this scriptCount decrement branching because sync envs
-                //need to decrement after resume, otherwise it looks like
-                //loading is complete after the first dependency is fetched.
-                //For browsers, it works fine to decrement after, but it means
-                //the checkLoaded setTimeout 50 ms cost is taken. To avoid
-                //that cost, decrement beforehand.
-                if (req.isAsync) {
-                    context.scriptCount -= 1;
-                }
-                resume();
-                if (!req.isAsync) {
-                    context.scriptCount -= 1;
-                }
+
+                checkLoaded();
             },
 
             /**
@@ -1449,7 +1682,7 @@
              * plain URLs like nameToUrl.
              */
             toUrl: function (moduleNamePlusExt, relModuleMap) {
-                var index = moduleNamePlusExt.lastIndexOf("."),
+                var index = moduleNamePlusExt.lastIndexOf('.'),
                     ext = null;
 
                 if (index !== -1) {
@@ -1457,43 +1690,52 @@
                     moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
                 }
 
-                return context.nameToUrl(moduleNamePlusExt, ext, relModuleMap);
+                return context.nameToUrl(normalize(moduleNamePlusExt, relModuleMap && relModuleMap.id, true),
+                                         ext);
             },
 
             /**
              * Converts a module name to a file path. Supports cases where
              * moduleName may actually be just an URL.
+             * Note that it **does not** call normalize on the moduleName,
+             * it is assumed to have already been normalized. This is an
+             * internal API, not a public one. Use toUrl for the public API.
              */
-            nameToUrl: function (moduleName, ext, relModuleMap) {
+            nameToUrl: function (moduleName, ext) {
                 var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url,
-                    config = context.config;
-
-                //Normalize module name if have a base relative module name to work from.
-                moduleName = normalize(moduleName, relModuleMap && relModuleMap.fullName);
+                    parentPath;
 
                 //If a colon is in the URL, it indicates a protocol is used and it is just
-                //an URL to a file, or if it starts with a slash or ends with .js, it is just a plain file.
+                //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
+                //or ends with .js, then assume the user meant to use an url and not a module id.
                 //The slash is important for protocol-less URLs as well as full paths.
                 if (req.jsExtRegExp.test(moduleName)) {
                     //Just a plain path, not module name lookup, so just return it.
                     //Add extension if it is included. This is a bit wonky, only non-.js things pass
                     //an extension, this method probably needs to be reworked.
-                    url = moduleName + (ext ? ext : "");
+                    url = moduleName + (ext || '');
                 } else {
                     //A module that needs to be converted to a path.
                     paths = config.paths;
                     pkgs = config.pkgs;
 
-                    syms = moduleName.split("/");
+                    syms = moduleName.split('/');
                     //For each module name segment, see if there is a path
                     //registered for it. Start with most specific name
                     //and work up from it.
-                    for (i = syms.length; i > 0; i--) {
-                        parentModule = syms.slice(0, i).join("/");
-                        if (paths[parentModule]) {
-                            syms.splice(0, i, paths[parentModule]);
+                    for (i = syms.length; i > 0; i -= 1) {
+                        parentModule = syms.slice(0, i).join('/');
+                        pkg = pkgs[parentModule];
+                        parentPath = paths[parentModule];
+                        if (parentPath) {
+                            //If an array, it means there are a few choices,
+                            //Choose the one that is desired
+                            if (isArray(parentPath)) {
+                                parentPath = parentPath[0];
+                            }
+                            syms.splice(0, i, parentPath);
                             break;
-                        } else if ((pkg = pkgs[parentModule])) {
+                        } else if (pkg) {
                             //If module name is just the package name, then looking
                             //for the main module.
                             if (moduleName === pkg.name) {
@@ -1507,22 +1749,65 @@
                     }
 
                     //Join the path parts together, then figure out if baseUrl is needed.
-                    url = syms.join("/") + (ext || ".js");
-                    url = (url.charAt(0) === '/' || url.match(/^\w+:/) ? "" : config.baseUrl) + url;
+                    url = syms.join('/');
+                    url += (ext || (/\?/.test(url) ? '' : '.js'));
+                    url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
                 }
 
                 return config.urlArgs ? url +
                                         ((url.indexOf('?') === -1 ? '?' : '&') +
                                          config.urlArgs) : url;
-            }
-        };
-
-        //Make these visible on the context so can be called at the very
-        //end of the file to bootstrap
-        context.jQueryCheck = jQueryCheck;
-        context.resume = resume;
-
-        return context;
+            },
+
+            //Delegates to req.load. Broken out as a separate function to
+            //allow overriding in the optimizer.
+            load: function (id, url) {
+                req.load(context, id, url);
+            },
+
+            /**
+             * Executes a module callack function. Broken out as a separate function
+             * solely to allow the build system to sequence the files in the built
+             * layer in the right sequence.
+             *
+             * @private
+             */
+            execCb: function (name, callback, args, exports) {
+                return callback.apply(exports, args);
+            },
+
+            /**
+             * callback for script loads, used to check status of loading.
+             *
+             * @param {Event} evt the event from the browser for the script
+             * that was loaded.
+             */
+            onScriptLoad: function (evt) {
+                //Using currentTarget instead of target for Firefox 2.0's sake. Not
+                //all old browsers will be supported, but this one was easy enough
+                //to support and still makes sense.
+                if (evt.type === 'load' ||
+                        (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
+                    //Reset interactive script so a script node is not held onto for
+                    //to long.
+                    interactiveScript = null;
+
+                    //Pull out the name of the module and the context.
+                    var data = getScriptData(evt);
+                    context.completeLoad(data.id);
+                }
+            },
+
+            /**
+             * Callback for script errors.
+             */
+            onScriptError: function (evt) {
+                var data = getScriptData(evt);
+                if (!hasPathFallback(data.id)) {
+                    return onError(makeError('scripterror', 'Script error', evt, [data.id]));
+                }
+            }
+        });
     }
 
     /**
@@ -1539,20 +1824,21 @@
      * on a require that are not standardized), and to give a short
      * name for minification/local scope use.
      */
-    req = requirejs = function (deps, callback) {
+    req = requirejs = function (deps, callback, errback, optional) {
 
         //Find the right context, use default
-        var contextName = defContextName,
-            context, config;
+        var context, config,
+            contextName = defContextName;
 
         // Determine if have config object in the call.
-        if (!isArray(deps) && typeof deps !== "string") {
+        if (!isArray(deps) && typeof deps !== 'string') {
             // deps is a config object
             config = deps;
             if (isArray(callback)) {
                 // Adjust args if there are dependencies
                 deps = callback;
-                callback = arguments[2];
+                callback = errback;
+                errback = optional;
             } else {
                 deps = [];
             }
@@ -1562,14 +1848,16 @@
             contextName = config.context;
         }
 
-        context = contexts[contextName] ||
-                  (contexts[contextName] = newContext(contextName));
+        context = contexts[contextName];
+        if (!context) {
+            context = contexts[contextName] = req.s.newContext(contextName);
+        }
 
         if (config) {
             context.configure(config);
         }
 
-        return context.require(deps, callback);
+        return context.require(deps, callback, errback);
     };
 
     /**
@@ -1587,31 +1875,29 @@
         require = req;
     }
 
-    /**
-     * Global require.toUrl(), to match global require, mostly useful
-     * for debugging/work in the global space.
-     */
-    req.toUrl = function (moduleNamePlusExt) {
-        return contexts[defContextName].toUrl(moduleNamePlusExt);
-    };
-
     req.version = version;
 
     //Used to filter out dependencies that are already paths.
     req.jsExtRegExp = /^\/|:|\?|\.js$/;
+    req.isBrowser = isBrowser;
     s = req.s = {
         contexts: contexts,
-        //Stores a list of URLs that should not get async script tag treatment.
-        skipAsync: {}
+        newContext: newContext
     };
 
-    req.isAsync = req.isBrowser = isBrowser;
+    //Create default context.
+    req({});
+
+    //Exports some context-sensitive methods on global require, using
+    //default context if no context specified.
+    addRequireMethods(req);
+
     if (isBrowser) {
-        head = s.head = document.getElementsByTagName("head")[0];
+        head = s.head = document.getElementsByTagName('head')[0];
         //If BASE tag is in play, using appendChild is a problem for IE6.
         //When that browser dies, this can be removed. Details in this jQuery bug:
         //http://dev.jquery.com/ticket/2709
-        baseElement = document.getElementsByTagName("base")[0];
+        baseElement = document.getElementsByTagName('base')[0];
         if (baseElement) {
             head = s.head = baseElement.parentNode;
         }
@@ -1636,34 +1922,140 @@
      * @param {Object} url the URL to the module.
      */
     req.load = function (context, moduleName, url) {
-        req.resourcesReady(false);
-
-        context.scriptCount += 1;
-        req.attach(url, context, moduleName);
-
-        //If tracking a jQuery, then make sure its ready callbacks
-        //are put on hold to prevent its ready callbacks from
-        //triggering too soon.
-        if (context.jQuery && !context.jQueryIncremented) {
-            jQueryHoldReady(context.jQuery, true);
-            context.jQueryIncremented = true;
+        var config = (context && context.config) || {},
+            node;
+        if (isBrowser) {
+            //In the browser so use a script tag
+            node = config.xhtml ?
+                    document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
+                    document.createElement('script');
+            node.type = config.scriptType || 'text/javascript';
+            node.charset = 'utf-8';
+            node.async = true;
+
+            node.setAttribute('data-requirecontext', context.contextName);
+            node.setAttribute('data-requiremodule', moduleName);
+
+            //Set up load listener. Test attachEvent first because IE9 has
+            //a subtle issue in its addEventListener and script onload firings
+            //that do not match the behavior of all other browsers with
+            //addEventListener support, which fire the onload event for a
+            //script right after the script execution. See:
+            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
+            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
+            //script execution mode.
+            if (node.attachEvent &&
+                    //Check if node.attachEvent is artificially added by custom script or
+                    //natively supported by browser
+                    //read https://github.com/jrburke/requirejs/issues/187
+                    //if we can NOT find [native code] then it must NOT natively supported.
+                    //in IE8, node.attachEvent does not have toString()
+                    //Note the test for "[native code" with no closing brace, see:
+                    //https://github.com/jrburke/requirejs/issues/273
+                    !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
+                    !isOpera) {
+                //Probably IE. IE (at least 6-8) do not fire
+                //script onload right after executing the script, so
+                //we cannot tie the anonymous define call to a name.
+                //However, IE reports the script as being in 'interactive'
+                //readyState at the time of the define call.
+                useInteractive = true;
+
+                node.attachEvent('onreadystatechange', context.onScriptLoad);
+                //It would be great to add an error handler here to catch
+                //404s in IE9+. However, onreadystatechange will fire before
+                //the error handler, so that does not help. If addEvenListener
+                //is used, then IE will fire error before load, but we cannot
+                //use that pathway given the connect.microsoft.com issue
+                //mentioned above about not doing the 'script execute,
+                //then fire the script load event listener before execute
+                //next script' that other browsers do.
+                //Best hope: IE10 fixes the issues,
+                //and then destroys all installs of IE 6-9.
+                //node.attachEvent('onerror', context.onScriptError);
+            } else {
+                node.addEventListener('load', context.onScriptLoad, false);
+                node.addEventListener('error', context.onScriptError, false);
+            }
+            node.src = url;
+
+            //For some cache cases in IE 6-8, the script executes before the end
+            //of the appendChild execution, so to tie an anonymous define
+            //call to the module name (which is stored on the node), hold on
+            //to a reference to this node, but clear after the DOM insertion.
+            currentlyAddingScript = node;
+            if (baseElement) {
+                head.insertBefore(node, baseElement);
+            } else {
+                head.appendChild(node);
+            }
+            currentlyAddingScript = null;
+
+            return node;
+        } else if (isWebWorker) {
+            //In a web worker, use importScripts. This is not a very
+            //efficient use of importScripts, importScripts will block until
+            //its script is downloaded and evaluated. However, if web workers
+            //are in play, the expectation that a build has been done so that
+            //only one script needs to be loaded anyway. This may need to be
+            //reevaluated if other use cases become common.
+            importScripts(url);
+
+            //Account for anonymous modules
+            context.completeLoad(moduleName);
         }
     };
 
     function getInteractiveScript() {
-        var scripts, i, script;
         if (interactiveScript && interactiveScript.readyState === 'interactive') {
             return interactiveScript;
         }
 
-        scripts = document.getElementsByTagName('script');
-        for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) {
+        eachReverse(scripts(), function (script) {
             if (script.readyState === 'interactive') {
                 return (interactiveScript = script);
             }
-        }
-
-        return null;
+        });
+        return interactiveScript;
+    }
+
+    //Look for a data-main script attribute, which could also adjust the baseUrl.
+    if (isBrowser) {
+        //Figure out baseUrl. Get it from the script tag with require.js in it.
+        eachReverse(scripts(), function (script) {
+            //Set the 'head' where we can append children by
+            //using the script's parent.
+            if (!head) {
+                head = script.parentNode;
+            }
+
+            //Look for a data-main attribute to set main script for the page
+            //to load. If it is there, the path to data main becomes the
+            //baseUrl, if it is not already set.
+            dataMain = script.getAttribute('data-main');
+            if (dataMain) {
+                //Set final baseUrl if there is not already an explicit one.
+                if (!cfg.baseUrl) {
+                    //Pull off the directory of data-main for use as the
+                    //baseUrl.
+                    src = dataMain.split('/');
+                    mainScript = src.pop();
+                    subPath = src.length ? src.join('/')  + '/' : './';
+
+                    cfg.baseUrl = subPath;
+                    dataMain = mainScript;
+                }
+
+                //Strip off any trailing .js since dataMain is now
+                //like a module name.
+                dataMain = dataMain.replace(jsSuffixRegExp, '');
+
+                //Put the data-main script in the files to load.
+                cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
+
+                return true;
+            }
+        });
     }
 
     /**
@@ -1699,7 +2091,7 @@
             if (callback.length) {
                 callback
                     .toString()
-                    .replace(commentRegExp, "")
+                    .replace(commentRegExp, '')
                     .replace(cjsRequireRegExp, function (match, dep) {
                         deps.push(dep);
                     });
@@ -1709,7 +2101,7 @@
                 //work though if it just needs require.
                 //REQUIRES the function to expect the CommonJS variables in the
                 //order listed below.
-                deps = (callback.length === 1 ? ["require"] : ["require", "exports", "module"]).concat(deps);
+                deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
             }
         }
 
@@ -1719,9 +2111,9 @@
             node = currentlyAddingScript || getInteractiveScript();
             if (node) {
                 if (!name) {
-                    name = node.getAttribute("data-requiremodule");
-                }
-                context = contexts[node.getAttribute("data-requirecontext")];
+                    name = node.getAttribute('data-requiremodule');
+                }
+                context = contexts[node.getAttribute('data-requirecontext')];
             }
         }
 
@@ -1732,326 +2124,27 @@
         //occurs. If no context, use the global queue, and get it processed
         //in the onscript load callback.
         (context ? context.defQueue : globalDefQueue).push([name, deps, callback]);
-
-        return undefined;
     };
 
     define.amd = {
-        multiversion: true,
-        plugins: true,
         jQuery: true
     };
 
+
     /**
      * Executes the text. Normally just uses eval, but can be modified
-     * to use a more environment specific call.
+     * to use a better, environment-specific call. Only used for transpiling
+     * loader plugins, not for plain JS modules.
      * @param {String} text the text to execute/evaluate.
      */
     req.exec = function (text) {
+        /*jslint evil: true */
         return eval(text);
     };
 
-    /**
-     * Executes a module callack function. Broken out as a separate function
-     * solely to allow the build system to sequence the files in the built
-     * layer in the right sequence.
-     *
-     * @private
-     */
-    req.execCb = function (name, callback, args, exports) {
-        return callback.apply(exports, args);
-    };
-
-
-    /**
-     * Adds a node to the DOM. Public function since used by the order plugin.
-     * This method should not normally be called by outside code.
-     */
-    req.addScriptToDom = function (node) {
-        //For some cache cases in IE 6-8, the script executes before the end
-        //of the appendChild execution, so to tie an anonymous define
-        //call to the module name (which is stored on the node), hold on
-        //to a reference to this node, but clear after the DOM insertion.
-        currentlyAddingScript = node;
-        if (baseElement) {
-            head.insertBefore(node, baseElement);
-        } else {
-            head.appendChild(node);
-        }
-        currentlyAddingScript = null;
-    };
-
-    /**
-     * callback for script loads, used to check status of loading.
-     *
-     * @param {Event} evt the event from the browser for the script
-     * that was loaded.
-     *
-     * @private
-     */
-    req.onScriptLoad = function (evt) {
-        //Using currentTarget instead of target for Firefox 2.0's sake. Not
-        //all old browsers will be supported, but this one was easy enough
-        //to support and still makes sense.
-        var node = evt.currentTarget || evt.srcElement, contextName, moduleName,
-            context;
-
-        if (evt.type === "load" || (node && readyRegExp.test(node.readyState))) {
-            //Reset interactive script so a script node is not held onto for
-            //to long.
-            interactiveScript = null;
-
-            //Pull out the name of the module and the context.
-            contextName = node.getAttribute("data-requirecontext");
-            moduleName = node.getAttribute("data-requiremodule");
-            context = contexts[contextName];
-
-            contexts[contextName].completeLoad(moduleName);
-
-            //Clean up script binding. Favor detachEvent because of IE9
-            //issue, see attachEvent/addEventListener comment elsewhere
-            //in this file.
-            if (node.detachEvent && !isOpera) {
-                //Probably IE. If not it will throw an error, which will be
-                //useful to know.
-                node.detachEvent("onreadystatechange", req.onScriptLoad);
-            } else {
-                node.removeEventListener("load", req.onScriptLoad, false);
-            }
-        }
-    };
-
-    /**
-     * Attaches the script represented by the URL to the current
-     * environment. Right now only supports browser loading,
-     * but can be redefined in other environments to do the right thing.
-     * @param {String} url the url of the script to attach.
-     * @param {Object} context the context that wants the script.
-     * @param {moduleName} the name of the module that is associated with the script.
-     * @param {Function} [callback] optional callback, defaults to require.onScriptLoad
-     * @param {String} [type] optional type, defaults to text/javascript
-     * @param {Function} [fetchOnlyFunction] optional function to indicate the script node
-     * should be set up to fetch the script but do not attach it to the DOM
-     * so that it can later be attached to execute it. This is a way for the
-     * order plugin to support ordered loading in IE. Once the script is fetched,
-     * but not executed, the fetchOnlyFunction will be called.
-     */
-    req.attach = function (url, context, moduleName, callback, type, fetchOnlyFunction) {
-        var node;
-        if (isBrowser) {
-            //In the browser so use a script tag
-            callback = callback || req.onScriptLoad;
-            node = context && context.config && context.config.xhtml ?
-                    document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") :
-                    document.createElement("script");
-            node.type = type || "text/javascript";
-            node.charset = "utf-8";
-            //Use async so Gecko does not block on executing the script if something
-            //like a long-polling comet tag is being run first. Gecko likes
-            //to evaluate scripts in DOM order, even for dynamic scripts.
-            //It will fetch them async, but only evaluate the contents in DOM
-            //order, so a long-polling script tag can delay execution of scripts
-            //after it. But telling Gecko we expect async gets us the behavior
-            //we want -- execute it whenever it is finished downloading. Only
-            //Helps Firefox 3.6+
-            //Allow some URLs to not be fetched async. Mostly helps the order!
-            //plugin
-            node.async = !s.skipAsync[url];
-
-            if (context) {
-                node.setAttribute("data-requirecontext", context.contextName);
-            }
-            node.setAttribute("data-requiremodule", moduleName);
-
-            //Set up load listener. Test attachEvent first because IE9 has
-            //a subtle issue in its addEventListener and script onload firings
-            //that do not match the behavior of all other browsers with
-            //addEventListener support, which fire the onload event for a
-            //script right after the script execution. See:
-            //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
-            //UNFORTUNATELY Opera implements attachEvent but does not follow the script
-            //script execution mode.
-            if (node.attachEvent && !isOpera) {
-                //Probably IE. IE (at least 6-8) do not fire
-                //script onload right after executing the script, so
-                //we cannot tie the anonymous define call to a name.
-                //However, IE reports the script as being in "interactive"
-                //readyState at the time of the define call.
-                useInteractive = true;
-
-
-                if (fetchOnlyFunction) {
-                    //Need to use old school onreadystate here since
-                    //when the event fires and the node is not attached
-                    //to the DOM, the evt.srcElement is null, so use
-                    //a closure to remember the node.
-                    node.onreadystatechange = function (evt) {
-                        //Script loaded but not executed.
-                        //Clear loaded handler, set the real one that
-                        //waits for script execution.
-                        if (node.readyState === 'loaded') {
-                            node.onreadystatechange = null;
-                            node.attachEvent("onreadystatechange", callback);
-                            fetchOnlyFunction(node);
-                        }
-                    };
-                } else {
-                    node.attachEvent("onreadystatechange", callback);
-                }
-            } else {
-                node.addEventListener("load", callback, false);
-            }
-            node.src = url;
-
-            //Fetch only means waiting to attach to DOM after loaded.
-            if (!fetchOnlyFunction) {
-                req.addScriptToDom(node);
-            }
-
-            return node;
-        } else if (isWebWorker) {
-            //In a web worker, use importScripts. This is not a very
-            //efficient use of importScripts, importScripts will block until
-            //its script is downloaded and evaluated. However, if web workers
-            //are in play, the expectation that a build has been done so that
-            //only one script needs to be loaded anyway. This may need to be
-            //reevaluated if other use cases become common.
-            importScripts(url);
-
-            //Account for anonymous modules
-            context.completeLoad(moduleName);
-        }
-        return null;
-    };
-
-    //Look for a data-main script attribute, which could also adjust the baseUrl.
-    if (isBrowser) {
-        //Figure out baseUrl. Get it from the script tag with require.js in it.
-        scripts = document.getElementsByTagName("script");
-
-        for (i = scripts.length - 1; i > -1 && (script = scripts[i]); i--) {
-            //Set the "head" where we can append children by
-            //using the script's parent.
-            if (!head) {
-                head = script.parentNode;
-            }
-
-            //Look for a data-main attribute to set main script for the page
-            //to load. If it is there, the path to data main becomes the
-            //baseUrl, if it is not already set.
-            if ((dataMain = script.getAttribute('data-main'))) {
-                if (!cfg.baseUrl) {
-                    //Pull off the directory of data-main for use as the
-                    //baseUrl.
-                    src = dataMain.split('/');
-                    mainScript = src.pop();
-                    subPath = src.length ? src.join('/')  + '/' : './';
-
-                    //Set final config.
-                    cfg.baseUrl = subPath;
-                    //Strip off any trailing .js since dataMain is now
-                    //like a module name.
-                    dataMain = mainScript.replace(jsSuffixRegExp, '');
-                }
-
-                //Put the data-main script in the files to load.
-                cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain];
-
-                break;
-            }
-        }
-    }
-
-    //See if there is nothing waiting across contexts, and if not, trigger
-    //resourcesReady.
-    req.checkReadyState = function () {
-        var contexts = s.contexts, prop;
-        for (prop in contexts) {
-            if (!(prop in empty)) {
-                if (contexts[prop].waitCount) {
-                    return;
-                }
-            }
-        }
-        req.resourcesReady(true);
-    };
-
-    /**
-     * Internal function that is triggered whenever all scripts/resources
-     * have been loaded by the loader. Can be overridden by other, for
-     * instance the domReady plugin, which wants to know when all resources
-     * are loaded.
-     */
-    req.resourcesReady = function (isReady) {
-        var contexts, context, prop;
-
-        //First, set the public variable indicating that resources are loading.
-        req.resourcesDone = isReady;
-
-        if (req.resourcesDone) {
-            //If jQuery with DOM ready delayed, release it now.
-            contexts = s.contexts;
-            for (prop in contexts) {
-                if (!(prop in empty)) {
-                    context = contexts[prop];
-                    if (context.jQueryIncremented) {
-                        jQueryHoldReady(context.jQuery, false);
-                        context.jQueryIncremented = false;
-                    }
-                }
-            }
-        }
-    };
-
-    //FF < 3.6 readyState fix. Needed so that domReady plugin
-    //works well in that environment, since require.js is normally
-    //loaded via an HTML script tag so it will be there before window load,
-    //where the domReady plugin is more likely to be loaded after window load.
-    req.pageLoaded = function () {
-        if (document.readyState !== "complete") {
-            document.readyState = "complete";
-        }
-    };
-    if (isBrowser) {
-        if (document.addEventListener) {
-            if (!document.readyState) {
-                document.readyState = "loading";
-                window.addEventListener("load", req.pageLoaded, false);
-            }
-        }
-    }
-
-    //Set up default context. If require was a configuration object, use that as base config.
+    //Set up with config info.
     req(cfg);
-
-    //If modules are built into require.js, then need to make sure dependencies are
-    //traced. Use a setTimeout in the browser world, to allow all the modules to register
-    //themselves. In a non-browser env, assume that modules are not built into require.js,
-    //which seems odd to do on the server.
-    if (req.isAsync && typeof setTimeout !== "undefined") {
-        ctx = s.contexts[(cfg.context || defContextName)];
-        //Indicate that the script that includes require() is still loading,
-        //so that require()'d dependencies are not traced until the end of the
-        //file is parsed (approximated via the setTimeout call).
-        ctx.requireWait = true;
-        setTimeout(function () {
-            ctx.requireWait = false;
-
-            //Any modules included with the require.js file will be in the
-            //global queue, assign them to this context.
-            ctx.takeGlobalQueue();
-
-            //Allow for jQuery to be loaded/already in the page, and if jQuery 1.4.3,
-            //make sure to hold onto it for readyWait triggering.
-            ctx.jQueryCheck();
-
-            if (!ctx.scriptCount) {
-                ctx.resume();
-            }
-            req.checkReadyState();
-        }, 0);
-    }
-}());
+}(this));
 
 
     if (env === 'rhino') {
@@ -2061,14 +2154,12 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint strict: false */
+/*jslint */
 /*global require: false, java: false, load: false */
 
 (function () {
-
+    'use strict';
     require.load = function (context, moduleName, url) {
-        //Indicate a the module is in process of loading.
-        context.scriptCount += 1;
 
         load(url);
 
@@ -2092,7 +2183,7 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint regexp: false, strict: false */
+/*jslint regexp: false */
 /*global require: false, define: false, requirejsVars: false, process: false */
 
 /**
@@ -2103,12 +2194,16 @@
  */
 
 (function () {
+    'use strict';
+
     var nodeReq = requirejsVars.nodeRequire,
         req = requirejsVars.require,
         def = requirejsVars.define,
         fs = nodeReq('fs'),
         path = nodeReq('path'),
-        vm = nodeReq('vm');
+        vm = nodeReq('vm'),
+        //In Node 0.7+ existsSync is on fs.
+        exists = fs.existsSync || path.existsSync;
 
     //Supply an implementation that allows synchronous get of a module.
     req.get = function (context, moduleName, relModuleMap) {
@@ -2120,9 +2215,9 @@
             moduleMap = context.makeModuleMap(moduleName, relModuleMap);
 
         //Normalize module name, if it contains . or ..
-        moduleName = moduleMap.fullName;
-
-        if (moduleName in context.defined) {
+        moduleName = moduleMap.id;
+
+        if (context.defined.hasOwnProperty(moduleName)) {
             ret = context.defined[moduleName];
         } else {
             if (ret === undefined) {
@@ -2148,10 +2243,7 @@
     req.load = function (context, moduleName, url) {
         var contents, err;
 
-        //Indicate a the module is in process of loading.
-        context.scriptCount += 1;
-
-        if (path.existsSync(url)) {
+        if (exists(url)) {
             contents = fs.readFileSync(url, 'utf8');
 
             contents = req.makeNodeWrapper(contents);
@@ -2167,13 +2259,18 @@
             }
         } else {
             def(moduleName, function () {
+                //Get the original name, since relative requires may be
+                //resolved differently in node (issue #202)
+                var originalName = context.registry[moduleName] &&
+                            context.registry[moduleName].map.originalName;
+
                 try {
-                    return (context.config.nodeRequire || req.nodeRequire)(moduleName);
+                    return (context.config.nodeRequire || req.nodeRequire)(originalName);
                 } catch (e) {
                     err = new Error('Calling node\'s require("' +
-                                        moduleName + '") failed with error: ' + e);
+                                        originalName + '") failed with error: ' + e);
                     err.originalError = e;
-                    err.moduleName = moduleName;
+                    err.moduleName = originalName;
                     return req.onError(err);
                 }
             });
@@ -2181,8 +2278,6 @@
 
         //Support anonymous modules.
         context.completeLoad(moduleName);
-
-        return undefined;
     };
 
     //Override to provide the function wrapper for define/require.
@@ -2256,6 +2351,40 @@
 }());
 if(env === 'node') {
 /**
+ * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+
+/*jslint strict: false */
+/*global define: false, load: false */
+
+//Needed so that rhino/assert can return a stub for uglify's consolidator.js
+define('node/assert', ['assert'], function (assert) {
+    return assert;
+});
+
+}
+
+if(env === 'rhino') {
+/**
+ * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+
+/*jslint strict: false */
+/*global define: false, load: false */
+
+//Just a stub for use with uglify's consolidator.js
+define('rhino/assert', function () {
+    return {};
+});
+
+}
+
+if(env === 'node') {
+/**
  * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
@@ -2353,6 +2482,7 @@
 define('node/file', ['fs', 'path'], function (fs, path) {
 
     var isWindows = process.platform === 'win32',
+        windowsDriveRegExp = /^[a-zA-Z]\:\/$/,
         file;
 
     function frontSlash(path) {
@@ -2374,8 +2504,8 @@
     }
 
     function mkDir(dir) {
-        if (!exists(dir)) {
-            fs.mkdirSync(dir, 0777);
+        if (!exists(dir) && (!isWindows || !windowsDriveRegExp.test(dir))) {
+            fs.mkdirSync(dir, 511);
         }
     }
 
@@ -2537,6 +2667,13 @@
         },
 
         /**
+         * Renames a file. May fail if "to" already exists or is on another drive.
+         */
+        renameFile: function (from, to) {
+            return fs.renameSync(from, to);
+        },
+
+        /**
          * Reads a *text* file.
          */
         readFile: function (/*String*/path, /*String?*/encoding) {
@@ -2598,6 +2735,31 @@
                     fs.unlinkSync(fileName);
                 }
             }
+        },
+
+
+        /**
+         * Deletes any empty directories under the given directory.
+         */
+        deleteEmptyDirs: function (startDir) {
+            var dirFileArray, i, fileName, filePath, stat;
+
+            if (file.exists(startDir)) {
+                dirFileArray = fs.readdirSync(startDir);
+                for (i = 0; i < dirFileArray.length; i++) {
+                    fileName = dirFileArray[i];
+                    filePath = path.join(startDir, fileName);
+                    stat = fs.statSync(filePath);
+                    if (stat.isDirectory()) {
+                        file.deleteEmptyDirs(filePath);
+                    }
+                }
+
+                //If directory is now empty, remove it.
+                if (fs.readdirSync(startDir).length ===  0) {
+                    file.deleteFile(startDir);
+                }
+            }
         }
     };
 
@@ -2615,7 +2777,7 @@
  */
 //Helper functions to deal with file I/O.
 
-/*jslint plusplus: false, strict: false */
+/*jslint plusplus: false, strict: true */
 /*global java: false, define: false */
 
 define('rhino/file', function () {
@@ -2659,7 +2821,7 @@
             if (typeof fileObj === "string") {
                 fileObj = new java.io.File(fileObj);
             }
-            return (fileObj.getAbsolutePath() + "").replace(file.backSlashRegExp, "/");
+            return (fileObj.getCanonicalPath() + "").replace(file.backSlashRegExp, "/");
         },
 
         getFilteredFileList: function (/*String*/startDir, /*RegExp*/regExpFilters, /*boolean?*/makeUnixPaths, /*boolean?*/startDirIsJavaObject) {
@@ -2758,7 +2920,7 @@
             parentDir = destFile.getParentFile();
             if (!parentDir.exists()) {
                 if (!parentDir.mkdirs()) {
-                    throw "Could not create directory: " + parentDir.getAbsolutePath();
+                    throw "Could not create directory: " + parentDir.getCanonicalPath();
                 }
             }
 
@@ -2770,6 +2932,13 @@
             destChannel.close();
 
             return true; //Boolean
+        },
+
+        /**
+         * Renames a file. May fail if "to" already exists or is on another drive.
+         */
+        renameFile: function (from, to) {
+            return (new java.io.File(from)).renameTo((new java.io.File(to)));
         },
 
         readFile: function (/*String*/path, /*String?*/encoding) {
@@ -2847,10 +3016,60 @@
                 }
                 fileObj["delete"]();
             }
+        },
+
+        /**
+         * Deletes any empty directories under the given directory.
+         * The startDirIsJavaObject is private to this implementation's
+         * recursion needs.
+         */
+        deleteEmptyDirs: function (startDir, startDirIsJavaObject) {
+            var topDir = startDir,
+                dirFileArray, i, fileObj;
+
+            if (!startDirIsJavaObject) {
+                topDir = new java.io.File(startDir);
+            }
+
+            if (topDir.exists()) {
+                dirFileArray = topDir.listFiles();
+                for (i = 0; i < dirFileArray.length; i++) {
+                    fileObj = dirFileArray[i];
+                    if (fileObj.isDirectory()) {
+                        file.deleteEmptyDirs(fileObj, true);
+                    }
+                }
+
+                //If the directory is empty now, delete it.
+                if (topDir.listFiles().length === 0) {
+                    file.deleteFile(String(topDir.getPath()));
+                }
+            }
         }
     };
 
     return file;
+});
+
+}
+
+if(env === 'node') {
+/*global process */
+define('node/quit', function () {
+    'use strict';
+    return function (code) {
+        return process.exit(code);
+    };
+});
+}
+
+if(env === 'rhino') {
+/*global quit */
+define('rhino/quit', function () {
+    'use strict';
+    return function (code) {
+        return quit(code);
+    };
 });
 
 }
@@ -2860,31 +3079,58 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint plusplus: false, strict: false */
-/*global define: false */
+/*jslint plusplus: true */
+/*global define */
 
 define('lang', function () {
+    'use strict';
+
     var lang = {
         backSlashRegExp: /\\/g,
         ostring: Object.prototype.toString,
 
-        isArray: Array.isArray ? Array.isArray : function (it) {
+        isArray: Array.isArray || function (it) {
             return lang.ostring.call(it) === "[object Array]";
         },
 
+        isFunction: function(it) {
+            return lang.ostring.call(it) === "[object Function]";
+        },
+
+        isRegExp: function(it) {
+            return it && it instanceof RegExp;
+        },
+
+        _mixin: function(dest, source, override){
+            var name;
+            for (name in source) {
+                if(source.hasOwnProperty(name)
+                    && (override || !dest.hasOwnProperty(name))) {
+                    dest[name] = source[name];
+                }
+            }
+
+            return dest; // Object
+        },
+
         /**
-         * Simple function to mix in properties from source into target,
-         * but only if target does not already have a property of the same name.
+         * mixin({}, obj1, obj2) is allowed. If the last argument is a boolean,
+         * then the source objects properties are force copied over to dest.
          */
-        mixin: function (target, source, override) {
-            //Use an empty object to avoid other bad JS code that modifies
-            //Object.prototype.
-            var empty = {}, prop;
-            for (prop in source) {
-                if (override || !(prop in target)) {
-                    target[prop] = source[prop];
-                }
-            }
+        mixin: function(dest){
+            var parameters = Array.prototype.slice.call(arguments),
+                override, i, l;
+
+            if (!dest) { dest = {}; }
+
+            if (parameters.length > 2 && typeof arguments[parameters.length-1] === 'boolean') {
+                override = parameters.pop();
+            }
+
+            for (i = 1, l = parameters.length; i < l; i++) {
+                lang._mixin(dest, parameters[i], override);
+            }
+            return dest; // Object
         },
 
         delegate: (function () {
@@ -2899,7 +3145,57 @@
                 }
                 return tmp; // Object
             };
-        }())
+        }()),
+
+        /**
+         * Helper function for iterating over an array. If the func returns
+         * a true value, it will break out of the loop.
+         */
+        each: function each(ary, func) {
+            if (ary) {
+                var i;
+                for (i = 0; i < ary.length; i += 1) {
+                    if (func(ary[i], i, ary)) {
+                        break;
+                    }
+                }
+            }
+        },
+
+        /**
+         * Cycles over properties in an object and calls a function for each
+         * property value. If the function returns a truthy value, then the
+         * iteration is stopped.
+         */
+        eachProp: function eachProp(obj, func) {
+            var prop;
+            for (prop in obj) {
+                if (obj.hasOwnProperty(prop)) {
+                    if (func(obj[prop], prop)) {
+                        break;
+                    }
+                }
+            }
+        },
+
+        //Similar to Function.prototype.bind, but the "this" object is specified
+        //first, since it is easier to read/figure out what "this" will be.
+        bind: function bind(obj, fn) {
+            return function () {
+                return fn.apply(obj, arguments);
+            };
+        },
+
+        //Escapes a content string to be be a string that has characters escaped
+        //for inclusion as part of a JS string.
+        jsEscape: function (content) {
+            return content.replace(/(["'\\])/g, '\\$1')
+                .replace(/[\f]/g, "\\f")
+                .replace(/[\b]/g, "\\b")
+                .replace(/[\n]/g, "\\n")
+                .replace(/[\t]/g, "\\t")
+                .replace(/[\r]/g, "\\r");
+        }
     };
     return lang;
 });
@@ -3005,8 +3301,4800 @@
 //so that the build does not attempt to inline some env modules,
 //like Node's fs and path.
 
-define('uglifyjs/parse-js', ["require", "exports", "module"], function(require, exports, module) {
-
+//Commit 465a4eae86c7bae191b1ee427571543ace777117 on July 19, 2012
+define('esprima', ['exports'], function(exports) {
+/*
+  Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
+  Copyright (C) 2012 Mathias Bynens <mathias@qiwi.be>
+  Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
+  Copyright (C) 2012 Kris Kowal <kris.kowal@cixar.com>
+  Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
+  Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
+  Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*jslint bitwise:true plusplus:true */
+/*global esprima:true, exports:true,
+throwError: true, createLiteral: true, generateStatement: true,
+parseAssignmentExpression: true, parseBlock: true, parseExpression: true,
+parseFunctionDeclaration: true, parseFunctionExpression: true,
+parseFunctionSourceElements: true, parseVariableIdentifier: true,
+parseLeftHandSideExpression: true,
+parseStatement: true, parseSourceElement: true */
+
+(function (exports) {
+    'use strict';
+
+    var Token,
+        TokenName,
+        Syntax,
+        PropertyKind,
+        Messages,
+        Regex,
+        source,
+        strict,
+        index,
+        lineNumber,
+        lineStart,
+        length,
+        buffer,
+        state,
+        extra;
+
+    Token = {
+        BooleanLiteral: 1,
+        EOF: 2,
+        Identifier: 3,
+        Keyword: 4,
+        NullLiteral: 5,
+        NumericLiteral: 6,
+        Punctuator: 7,
+        StringLiteral: 8
+    };
+
+    TokenName = {};
+    TokenName[Token.BooleanLiteral] = 'Boolean';
+    TokenName[Token.EOF] = '<end>';
+    TokenName[Token.Identifier] = 'Identifier';
+    TokenName[Token.Keyword] = 'Keyword';
+    TokenName[Token.NullLiteral] = 'Null';
+    TokenName[Token.NumericLiteral] = 'Numeric';
+    TokenName[Token.Punctuator] = 'Punctuator';
+    TokenName[Token.StringLiteral] = 'String';
+
+    Syntax = {
+        AssignmentExpression: 'AssignmentExpression',
+        ArrayExpression: 'ArrayExpression',
+        BlockStatement: 'BlockStatement',
+        BinaryExpression: 'BinaryExpression',
+        BreakStatement: 'BreakStatement',
+        CallExpression: 'CallExpression',
+        CatchClause: 'CatchClause',
+        ConditionalExpression: 'ConditionalExpression',
+        ContinueStatement: 'ContinueStatement',
+        DoWhileStatement: 'DoWhileStatement',
+        DebuggerStatement: 'DebuggerStatement',
+        EmptyStatement: 'EmptyStatement',
+        ExpressionStatement: 'ExpressionStatement',
+        ForStatement: 'ForStatement',
+        ForInStatement: 'ForInStatement',
+        FunctionDeclaration: 'FunctionDeclaration',
+        FunctionExpression: 'FunctionExpression',
+        Identifier: 'Identifier',
+        IfStatement: 'IfStatement',
+        Literal: 'Literal',
+        LabeledStatement: 'LabeledStatement',
+        LogicalExpression: 'LogicalExpression',
+        MemberExpression: 'MemberExpression',
+        NewExpression: 'NewExpression',
+        ObjectExpression: 'ObjectExpression',
+        Program: 'Program',
+        Property: 'Property',
+        ReturnStatement: 'ReturnStatement',
+        SequenceExpression: 'SequenceExpression',
+        SwitchStatement: 'SwitchStatement',
+        SwitchCase: 'SwitchCase',
+        ThisExpression: 'ThisExpression',
+        ThrowStatement: 'ThrowStatement',
+        TryStatement: 'TryStatement',
+        UnaryExpression: 'UnaryExpression',
+        UpdateExpression: 'UpdateExpression',
+        VariableDeclaration: 'VariableDeclaration',
+        VariableDeclarator: 'VariableDeclarator',
+        WhileStatement: 'WhileStatement',
+        WithStatement: 'WithStatement'
+    };
+
+    PropertyKind = {
+        Data: 1,
+        Get: 2,
+        Set: 4
+    };
+
+    // Error messages should be identical to V8.
+    Messages = {
+        UnexpectedToken:  'Unexpected token %0',
+        UnexpectedNumber:  'Unexpected number',
+        UnexpectedString:  'Unexpected string',
+        UnexpectedIdentifier:  'Unexpected identifier',
+        UnexpectedReserved:  'Unexpected reserved word',
+        UnexpectedEOS:  'Unexpected end of input',
+        NewlineAfterThrow:  'Illegal newline after throw',
+        InvalidRegExp: 'Invalid regular expression',
+        UnterminatedRegExp:  'Invalid regular expression: missing /',
+        InvalidLHSInAssignment:  'Invalid left-hand side in assignment',
+        InvalidLHSInForIn:  'Invalid left-hand side in for-in',
+        NoCatchOrFinally:  'Missing catch or finally after try',
+        UnknownLabel: 'Undefined label \'%0\'',
+        Redeclaration: '%0 \'%1\' has already been declared',
+        IllegalContinue: 'Illegal continue statement',
+        IllegalBreak: 'Illegal break statement',
+        IllegalReturn: 'Illegal return statement',
+        StrictModeWith:  'Strict mode code may not include a with statement',
+        StrictCatchVariable:  'Catch variable may not be eval or arguments in strict mode',
+        StrictVarName:  'Variable name may not be eval or arguments in strict mode',
+        StrictParamName:  'Parameter name eval or arguments is not allowed in strict mode',
+        StrictParamDupe: 'Strict mode function may not have duplicate parameter names',
+        StrictFunctionName:  'Function name may not be eval or arguments in strict mode',
+        StrictOctalLiteral:  'Octal literals are not allowed in strict mode.',
+        StrictDelete:  'Delete of an unqualified identifier in strict mode.',
+        StrictDuplicateProperty:  'Duplicate data property in object literal not allowed in strict mode',
+        AccessorDataProperty:  'Object literal may not have data and accessor property with the same name',
+        AccessorGetSet:  'Object literal may not have multiple get/set accessors with the same name',
+        StrictLHSAssignment:  'Assignment to eval or arguments is not allowed in strict mode',
+        StrictLHSPostfix:  'Postfix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictLHSPrefix:  'Prefix increment/decrement may not have eval or arguments operand in strict mode',
+        StrictReservedWord:  'Use of future reserved word in strict mode'
+    };
+
+    // See also tools/generate-unicode-regex.py.
+    Regex = {
+        NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'),
+        NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]')
+    };
+
+    // Ensure the condition is true, otherwise throw an error.
+    // This is only to have a better contract semantic, i.e. another safety net
+    // to catch a logic error. The condition shall be fulfilled in normal case.
+    // Do NOT use this to enforce a certain condition on any user input.
+
+    function assert(condition, message) {
+        if (!condition) {
+            throw new Error('ASSERT: ' + message);
+        }
+    }
+
+    function sliceSource(from, to) {
+        return source.slice(from, to);
+    }
+
+    if (typeof 'esprima'[0] === 'undefined') {
+        sliceSource = function sliceArraySource(from, to) {
+            return source.slice(from, to).join('');
+        };
+    }
+
+    function isDecimalDigit(ch) {
+        return '0123456789'.indexOf(ch) >= 0;
+    }
+
+    function isHexDigit(ch) {
+        return '0123456789abcdefABCDEF'.indexOf(ch) >= 0;
+    }
+
+    function isOctalDigit(ch) {
+        return '01234567'.indexOf(ch) >= 0;
+    }
+
+
+    // 7.2 White Space
+
+    function isWhiteSpace(ch) {
+        return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') ||
+            (ch === '\u000C') || (ch === '\u00A0') ||
+            (ch.charCodeAt(0) >= 0x1680 &&
+             '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0);
+    }
+
+    // 7.3 Line Terminators
+
+    function isLineTerminator(ch) {
+        return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029');
+    }
+
+    // 7.6 Identifier Names and Identifiers
+
+    function isIdentifierStart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch));
+    }
+
+    function isIdentifierPart(ch) {
+        return (ch === '$') || (ch === '_') || (ch === '\\') ||
+            (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+            ((ch >= '0') && (ch <= '9')) ||
+            ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch));
+    }
+
+    // 7.6.1.2 Future Reserved Words
+
+    function isFutureReservedWord(id) {
+        switch (id) {
+
+        // Future reserved words.
+        case 'class':
+        case 'enum':
+        case 'export':
+        case 'extends':
+        case 'import':
+        case 'super':
+            return true;
+        }
+
+        return false;
+    }
+
+    function isStrictModeReservedWord(id) {
+        switch (id) {
+
+        // Strict Mode reserved words.
+        case 'implements':
+        case 'interface':
+        case 'package':
+        case 'private':
+        case 'protected':
+        case 'public':
+        case 'static':
+        case 'yield':
+        case 'let':
+            return true;
+        }
+
+        return false;
+    }
+
+    function isRestrictedWord(id) {
+        return id === 'eval' || id === 'arguments';
+    }
+
+    // 7.6.1.1 Keywords
+
+    function isKeyword(id) {
+        var keyword = false;
+        switch (id.length) {
+        case 2:
+            keyword = (id === 'if') || (id === 'in') || (id === 'do');
+            break;
+        case 3:
+            keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try');
+            break;
+        case 4:
+            keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with');
+            break;
+        case 5:
+            keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw');
+            break;
+        case 6:
+            keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch');
+            break;
+        case 7:
+            keyword = (id === 'default') || (id === 'finally');
+            break;
+        case 8:
+            keyword = (id === 'function') || (id === 'continue') || (id === 'debugger');
+            break;
+        case 10:
+            keyword = (id === 'instanceof');
+            break;
+        }
+
+        if (keyword) {
+            return true;
+        }
+
+        switch (id) {
+        // Future reserved words.
+        // 'const' is specialized as Keyword in V8.
+        case 'const':
+            return true;
+
+        // For compatiblity to SpiderMonkey and ES.next
+        case 'yield':
+        case 'let':
+            return true;
+        }
+
+        if (strict && isStrictModeReservedWord(id)) {
+            return true;
+        }
+
+        return isFutureReservedWord(id);
+    }
+
+    // Return the next character and move forward.
+
+    function nextChar() {
+        return source[index++];
+    }
+
+    // 7.4 Comments
+
+    function skipComment() {
+        var ch, blockComment, lineComment;
+
+        blockComment = false;
+        lineComment = false;
+
+        while (index < length) {
+            ch = source[index];
+
+            if (lineComment) {
+                ch = nextChar();
+                if (isLineTerminator(ch)) {
+                    lineComment = false;
+                    if (ch === '\r' && source[index] === '\n') {
+                        ++index;
+                    }
+                    ++lineNumber;
+                    lineStart = index;
+                }
+            } else if (blockComment) {
+                if (isLineTerminator(ch)) {
+                    if (ch === '\r' && source[index + 1] === '\n') {
+                        ++index;
+                    }
+                    ++lineNumber;
+                    ++index;
+                    lineStart = index;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    ch = nextChar();
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                    if (ch === '*') {
+                        ch = source[index];
+                        if (ch === '/') {
+                            ++index;
+                            blockComment = false;
+                        }
+                    }
+                }
+            } else if (ch === '/') {
+                ch = source[index + 1];
+                if (ch === '/') {
+                    index += 2;
+                    lineComment = true;
+                } else if (ch === '*') {
+                    index += 2;
+                    blockComment = true;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    break;
+                }
+            } else if (isWhiteSpace(ch)) {
+                ++index;
+            } else if (isLineTerminator(ch)) {
+                ++index;
+                if (ch ===  '\r' && source[index] === '\n') {
+                    ++index;
+                }
+                ++lineNumber;
+                lineStart = index;
+            } else {
+                break;
+            }
+        }
+    }
+
+    function scanHexEscape(prefix) {
+        var i, len, ch, code = 0;
+
+        len = (prefix === 'u') ? 4 : 2;
+        for (i = 0; i < len; ++i) {
+            if (index < length && isHexDigit(source[index])) {
+                ch = nextChar();
+                code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase());
+            } else {
+                return '';
+            }
+        }
+        return String.fromCharCode(code);
+    }
+
+    function scanIdentifier() {
+        var ch, start, id, restore;
+
+        ch = source[index];
+        if (!isIdentifierStart(ch)) {
+            return;
+        }
+
+        start = index;
+        if (ch === '\\') {
+            ++index;
+            if (source[index] !== 'u') {
+                return;
+            }
+            ++index;
+            restore = index;
+            ch = scanHexEscape('u');
+            if (ch) {
+                if (ch === '\\' || !isIdentifierStart(ch)) {
+                    return;
+                }
+                id = ch;
+            } else {
+                index = restore;
+                id = 'u';
+            }
+        } else {
+            id = nextChar();
+        }
+
+        while (index < length) {
+            ch = source[index];
+            if (!isIdentifierPart(ch)) {
+                break;
+            }
+            if (ch === '\\') {
+                ++index;
+                if (source[index] !== 'u') {
+                    return;
+                }
+                ++index;
+                restore = index;
+                ch = scanHexEscape('u');
+                if (ch) {
+                    if (ch === '\\' || !isIdentifierPart(ch)) {
+                        return;
+                    }
+                    id += ch;
+                } else {
+                    index = restore;
+                    id += 'u';
+                }
+            } else {
+                id += nextChar();
+            }
+        }
+
+        // There is no keyword or literal with only one character.
+        // Thus, it must be an identifier.
+        if (id.length === 1) {
+            return {
+                type: Token.Identifier,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (isKeyword(id)) {
+            return {
+                type: Token.Keyword,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 7.8.1 Null Literals
+
+        if (id === 'null') {
+            return {
+                type: Token.NullLiteral,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 7.8.2 Boolean Literals
+
+        if (id === 'true' || id === 'false') {
+            return {
+                type: Token.BooleanLiteral,
+                value: id,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        return {
+            type: Token.Identifier,
+            value: id,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    // 7.7 Punctuators
+
+    function scanPunctuator() {
+        var start = index,
+            ch1 = source[index],
+            ch2,
+            ch3,
+            ch4;
+
+        // Check for most common single-character punctuators.
+
+        if (ch1 === ';' || ch1 === '{' || ch1 === '}') {
+            ++index;
+            return {
+                type: Token.Punctuator,
+                value: ch1,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === ',' || ch1 === '(' || ch1 === ')') {
+            ++index;
+            return {
+                type: Token.Punctuator,
+                value: ch1,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // Dot (.) can also start a floating-point number, hence the need
+        // to check the next character.
+
+        ch2 = source[index + 1];
+        if (ch1 === '.' && !isDecimalDigit(ch2)) {
+            return {
+                type: Token.Punctuator,
+                value: nextChar(),
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // Peek more characters.
+
+        ch3 = source[index + 2];
+        ch4 = source[index + 3];
+
+        // 4-character punctuator: >>>=
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+            if (ch4 === '=') {
+                index += 4;
+                return {
+                    type: Token.Punctuator,
+                    value: '>>>=',
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        // 3-character punctuators: === !== >>> <<= >>=
+
+        if (ch1 === '=' && ch2 === '=' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '===',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '!' && ch2 === '=' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '!==',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '>') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '>>>',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '<' && ch2 === '<' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '<<=',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        if (ch1 === '>' && ch2 === '>' && ch3 === '=') {
+            index += 3;
+            return {
+                type: Token.Punctuator,
+                value: '>>=',
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+
+        // 2-character punctuators: <= >= == != ++ -- << >> && ||
+        // += -= *= %= &= |= ^= /=
+
+        if (ch2 === '=') {
+            if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) {
+                index += 2;
+                return {
+                    type: Token.Punctuator,
+                    value: ch1 + ch2,
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) {
+            if ('+-<>&|'.indexOf(ch2) >= 0) {
+                index += 2;
+                return {
+                    type: Token.Punctuator,
+                    value: ch1 + ch2,
+                    lineNumber: lineNumber,
+                    lineStart: lineStart,
+                    range: [start, index]
+                };
+            }
+        }
+
+        // The remaining 1-character punctuators.
+
+        if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) {
+            return {
+                type: Token.Punctuator,
+                value: nextChar(),
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [start, index]
+            };
+        }
+    }
+
+    // 7.8.3 Numeric Literals
+
+    function scanNumericLiteral() {
+        var number, start, ch;
+
+        ch = source[index];
+        assert(isDecimalDigit(ch) || (ch === '.'),
+            'Numeric literal must start with a decimal digit or a decimal point');
+
+        start = index;
+        number = '';
+        if (ch !== '.') {
+            number = nextChar();
+            ch = source[index];
+
+            // Hex number starts with '0x'.
+            // Octal number starts with '0'.
+            if (number === '0') {
+                if (ch === 'x' || ch === 'X') {
+                    number += nextChar();
+                    while (index < length) {
+                        ch = source[index];
+                        if (!isHexDigit(ch)) {
+                            break;
+                        }
+                        number += nextChar();
+                    }
+
+                    if (number.length <= 2) {
+                        // only 0x
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+
+                    if (index < length) {
+                        ch = source[index];
+                        if (isIdentifierStart(ch)) {
+                            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                        }
+                    }
+                    return {
+                        type: Token.NumericLiteral,
+                        value: parseInt(number, 16),
+                        lineNumber: lineNumber,
+                        lineStart: lineStart,
+                        range: [start, index]
+                    };
+                } else if (isOctalDigit(ch)) {
+                    number += nextChar();
+                    while (index < length) {
+                        ch = source[index];
+                        if (!isOctalDigit(ch)) {
+                            break;
+                        }
+                        number += nextChar();
+                    }
+
+                    if (index < length) {
+                        ch = source[index];
+                        if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+                            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                        }
+                    }
+                    return {
+                        type: Token.NumericLiteral,
+                        value: parseInt(number, 8),
+                        octal: true,
+                        lineNumber: lineNumber,
+                        lineStart: lineStart,
+                        range: [start, index]
+                    };
+                }
+
+                // decimal number starts with '0' such as '09' is illegal.
+                if (isDecimalDigit(ch)) {
+                    throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                }
+            }
+
+            while (index < length) {
+                ch = source[index];
+                if (!isDecimalDigit(ch)) {
+                    break;
+                }
+                number += nextChar();
+            }
+        }
+
+        if (ch === '.') {
+            number += nextChar();
+            while (index < length) {
+                ch = source[index];
+                if (!isDecimalDigit(ch)) {
+                    break;
+                }
+                number += nextChar();
+            }
+        }
+
+        if (ch === 'e' || ch === 'E') {
+            number += nextChar();
+
+            ch = source[index];
+            if (ch === '+' || ch === '-') {
+                number += nextChar();
+            }
+
+            ch = source[index];
+            if (isDecimalDigit(ch)) {
+                number += nextChar();
+                while (index < length) {
+                    ch = source[index];
+                    if (!isDecimalDigit(ch)) {
+                        break;
+                    }
+                    number += nextChar();
+                }
+            } else {
+                ch = 'character ' + ch;
+                if (index >= length) {
+                    ch = '<end>';
+                }
+                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+            }
+        }
+
+        if (index < length) {
+            ch = source[index];
+            if (isIdentifierStart(ch)) {
+                throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+            }
+        }
+
+        return {
+            type: Token.NumericLiteral,
+            value: parseFloat(number),
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    // 7.8.4 String Literals
+
+    function scanStringLiteral() {
+        var str = '', quote, start, ch, code, unescaped, restore, octal = false;
+
+        quote = source[index];
+        assert((quote === '\'' || quote === '"'),
+            'String literal must starts with a quote');
+
+        start = index;
+        ++index;
+
+        while (index < length) {
+            ch = nextChar();
+
+            if (ch === quote) {
+                quote = '';
+                break;
+            } else if (ch === '\\') {
+                ch = nextChar();
+                if (!isLineTerminator(ch)) {
+                    switch (ch) {
+                    case 'n':
+                        str += '\n';
+                        break;
+                    case 'r':
+                        str += '\r';
+                        break;
+                    case 't':
+                        str += '\t';
+                        break;
+                    case 'u':
+                    case 'x':
+                        restore = index;
+                        unescaped = scanHexEscape(ch);
+                        if (unescaped) {
+                            str += unescaped;
+                        } else {
+                            index = restore;
+                            str += ch;
+                        }
+                        break;
+                    case 'b':
+                        str += '\b';
+                        break;
+                    case 'f':
+                        str += '\f';
+                        break;
+                    case 'v':
+                        str += '\v';
+                        break;
+
+                    default:
+                        if (isOctalDigit(ch)) {
+                            code = '01234567'.indexOf(ch);
+
+                            // \0 is not octal escape sequence
+                            if (code !== 0) {
+                                octal = true;
+                            }
+
+                            if (index < length && isOctalDigit(source[index])) {
+                                octal = true;
+                                code = code * 8 + '01234567'.indexOf(nextChar());
+
+                                // 3 digits are only allowed when string starts
+                                // with 0, 1, 2, 3
+                                if ('0123'.indexOf(ch) >= 0 &&
+                                        index < length &&
+                                        isOctalDigit(source[index])) {
+                                    code = code * 8 + '01234567'.indexOf(nextChar());
+                                }
+                            }
+                            str += String.fromCharCode(code);
+                        } else {
+                            str += ch;
+                        }
+                        break;
+                    }
+                } else {
+                    ++lineNumber;
+                    if (ch ===  '\r' && source[index] === '\n') {
+                        ++index;
+                    }
+                }
+            } else if (isLineTerminator(ch)) {
+                break;
+            } else {
+                str += ch;
+            }
+        }
+
+        if (quote !== '') {
+            throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+        }
+
+        return {
+            type: Token.StringLiteral,
+            value: str,
+            octal: octal,
+            lineNumber: lineNumber,
+            lineStart: lineStart,
+            range: [start, index]
+        };
+    }
+
+    function scanRegExp() {
+        var str = '', ch, start, pattern, flags, value, classMarker = false, restore;
+
+        buffer = null;
+        skipComment();
+
+        start = index;
+        ch = source[index];
+        assert(ch === '/', 'Regular expression literal must start with a slash');
+        str = nextChar();
+
+        while (index < length) {
+            ch = nextChar();
+            str += ch;
+            if (classMarker) {
+                if (ch === ']') {
+                    classMarker = false;
+                }
+            } else {
+                if (ch === '\\') {
+                    ch = nextChar();
+                    // ECMA-262 7.8.5
+                    if (isLineTerminator(ch)) {
+                        throwError({}, Messages.UnterminatedRegExp);
+                    }
+                    str += ch;
+                } else if (ch === '/') {
+                    break;
+                } else if (ch === '[') {
+                    classMarker = true;
+                } else if (isLineTerminator(ch)) {
+                    throwError({}, Messages.UnterminatedRegExp);
+                }
+            }
+        }
+
+        if (str.length === 1) {
+            throwError({}, Messages.UnterminatedRegExp);
+        }
+
+        // Exclude leading and trailing slash.
+        pattern = str.substr(1, str.length - 2);
+
+        flags = '';
+        while (index < length) {
+            ch = source[index];
+            if (!isIdentifierPart(ch)) {
+                break;
+            }
+
+            ++index;
+            if (ch === '\\' && index < length) {
+                ch = source[index];
+                if (ch === 'u') {
+                    ++index;
+                    restore = index;
+                    ch = scanHexEscape('u');
+                    if (ch) {
+                        flags += ch;
+                        str += '\\u';
+                        for (; restore < index; ++restore) {
+                            str += source[restore];
+                        }
+                    } else {
+                        index = restore;
+                        flags += 'u';
+                        str += '\\u';
+                    }
+                } else {
+                    str += '\\';
+                }
+            } else {
+                flags += ch;
+                str += ch;
+            }
+        }
+
+        try {
+            value = new RegExp(pattern, flags);
+        } catch (e) {
+            throwError({}, Messages.InvalidRegExp);
+        }
+
+        return {
+            literal: str,
+            value: value,
+            range: [start, index]
+        };
+    }
+
+    function isIdentifierName(token) {
+        return token.type === Token.Identifier ||
+            token.type === Token.Keyword ||
+            token.type === Token.BooleanLiteral ||
+            token.type === Token.NullLiteral;
+    }
+
+    function advance() {
+        var ch, token;
+
+        skipComment();
+
+        if (index >= length) {
+            return {
+                type: Token.EOF,
+                lineNumber: lineNumber,
+                lineStart: lineStart,
+                range: [index, index]
+            };
+        }
+
+        token = scanPunctuator();
+        if (typeof token !== 'undefined') {
+            return token;
+        }
+
+        ch = source[index];
+
+        if (ch === '\'' || ch === '"') {
+            return scanStringLiteral();
+        }
+
+        if (ch === '.' || isDecimalDigit(ch)) {
+            return scanNumericLiteral();
+        }
+
+        token = scanIdentifier();
+        if (typeof token !== 'undefined') {
+            return token;
+        }
+
+        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+    }
+
+    function lex() {
+        var token;
+
+        if (buffer) {
+            index = buffer.range[1];
+            lineNumber = buffer.lineNumber;
+            lineStart = buffer.lineStart;
+            token = buffer;
+            buffer = null;
+            return token;
+        }
+
+        buffer = null;
+        return advance();
+    }
+
+    function lookahead() {
+        var pos, line, start;
+
+        if (buffer !== null) {
+            return buffer;
+        }
+
+        pos = index;
+        line = lineNumber;
+        start = lineStart;
+        buffer = advance();
+        index = pos;
+        lineNumber = line;
+        lineStart = start;
+
+        return buffer;
+    }
+
+    // Return true if there is a line terminator before the next token.
+
+    function peekLineTerminator() {
+        var pos, line, start, found;
+
+        pos = index;
+        line = lineNumber;
+        start = lineStart;
+        skipComment();
+        found = lineNumber !== line;
+        index = pos;
+        lineNumber = line;
+        lineStart = start;
+
+        return found;
+    }
+
+    // Throw an exception
+
+    function throwError(token, messageFormat) {
+        var error,
+            args = Array.prototype.slice.call(arguments, 2),
+            msg = messageFormat.replace(
+                /%(\d)/g,
+                function (whole, index) {
+                    return args[index] || '';
+                }
+            );
+
+        if (typeof token.lineNumber === 'number') {
+            error = new Error('Line ' + token.lineNumber + ': ' + msg);
+            error.index = token.range[0];
+            error.lineNumber = token.lineNumber;
+            error.column = token.range[0] - lineStart + 1;
+        } else {
+            error = new Error('Line ' + lineNumber + ': ' + msg);
+            error.index = index;
+            error.lineNumber = lineNumber;
+            error.column = index - lineStart + 1;
+        }
+
+        throw error;
+    }
+
+    function throwErrorTolerant() {
+        var error;
+        try {
+            throwError.apply(null, arguments);
+        } catch (e) {
+            if (extra.errors) {
+                extra.errors.push(e);
+            } else {
+                throw e;
+            }
+        }
+    }
+
+
+    // Throw an exception because of the token.
+
+    function throwUnexpected(token) {
+        var s;
+
+        if (token.type === Token.EOF) {
+            throwError(token, Messages.UnexpectedEOS);
+        }
+
+        if (token.type === Token.NumericLiteral) {
+            throwError(token, Messages.UnexpectedNumber);
+        }
+
+        if (token.type === Token.StringLiteral) {
+            throwError(token, Messages.UnexpectedString);
+        }
+
+        if (token.type === Token.Identifier) {
+            throwError(token, Messages.UnexpectedIdentifier);
+        }
+
+        if (token.type === Token.Keyword) {
+            if (isFutureReservedWord(token.value)) {
+                throwError(token, Messages.UnexpectedReserved);
+            } else if (strict && isStrictModeReservedWord(token.value)) {
+                throwError(token, Messages.StrictReservedWord);
+            }
+            throwError(token, Messages.UnexpectedToken, token.value);
+        }
+
+        // BooleanLiteral, NullLiteral, or Punctuator.
+        throwError(token, Messages.UnexpectedToken, token.value);
+    }
+
+    // Expect the next token to match the specified punctuator.
+    // If not, an exception will be thrown.
+
+    function expect(value) {
+        var token = lex();
+        if (token.type !== Token.Punctuator || token.value !== value) {
+            throwUnexpected(token);
+        }
+    }
+
+    // Expect the next token to match the specified keyword.
+    // If not, an exception will be thrown.
+
+    function expectKeyword(keyword) {
+        var token = lex();
+        if (token.type !== Token.Keyword || token.value !== keyword) {
+            throwUnexpected(token);
+        }
+    }
+
+    // Return true if the next token matches the specified punctuator.
+
+    function match(value) {
+        var token = lookahead();
+        return token.type === Token.Punctuator && token.value === value;
+    }
+
+    // Return true if the next token matches the specified keyword
+
+    function matchKeyword(keyword) {
+        var token = lookahead();
+        return token.type === Token.Keyword && token.value === keyword;
+    }
+
+    // Return true if the next token is an assignment operator
+
+    function matchAssign() {
+        var token = lookahead(),
+            op = token.value;
+
+        if (token.type !== Token.Punctuator) {
+            return false;
+        }
+        return op === '=' ||
+            op === '*=' ||
+            op === '/=' ||
+            op === '%=' ||
+            op === '+=' ||
+            op === '-=' ||
+            op === '<<=' ||
+            op === '>>=' ||
+            op === '>>>=' ||
+            op === '&=' ||
+            op === '^=' ||
+            op === '|=';
+    }
+
+    function consumeSemicolon() {
+        var token, line;
+
+        // Catch the very common case first.
+        if (source[index] === ';') {
+            lex();
+            return;
+        }
+
+        line = lineNumber;
+        skipComment();
+        if (lineNumber !== line) {
+            return;
+        }
+
+        if (match(';')) {
+            lex();
+            return;
+        }
+
+        token = lookahead();
+        if (token.type !== Token.EOF && !match('}')) {
+            throwUnexpected(token);
+        }
+        return;
+    }
+
+    // Return true if provided expression is LeftHandSideExpression
+
+    function isLeftHandSide(expr) {
+        return expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression;
+    }
+
+    // 11.1.4 Array Initialiser
+
+    function parseArrayInitialiser() {
+        var elements = [],
+            undef;
+
+        expect('[');
+
+        while (!match(']')) {
+            if (match(',')) {
+                lex();
+                elements.push(undef);
+            } else {
+                elements.push(parseAssignmentExpression());
+
+                if (!match(']')) {
+                    expect(',');
+                }
+            }
+        }
+
+        expect(']');
+
+        return {
+            type: Syntax.ArrayExpression,
+            elements: elements
+        };
+    }
+
+    // 11.1.5 Object Initialiser
+
+    function parsePropertyFunction(param, first) {
+        var previousStrict, body;
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (first && strict && isRestrictedWord(param[0].name)) {
+            throwError(first, Messages.StrictParamName);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionExpression,
+            id: null,
+            params: param,
+            body: body
+        };
+    }
+
+    function parseObjectPropertyKey() {
+        var token = lex();
+
+        // Note: This function is called only from parseObjectProperty(), where
+        // EOF and Punctuator tokens are already filtered out.
+
+        if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) {
+            if (strict && token.octal) {
+                throwError(token, Messages.StrictOctalLiteral);
+            }
+            return createLiteral(token);
+        }
+
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
+    }
+
+    function parseObjectProperty() {
+        var token, key, id, param;
+
+        token = lookahead();
+
+        if (token.type === Token.Identifier) {
+
+            id = parseObjectPropertyKey();
+
+            // Property Assignment: Getter and Setter.
+
+            if (token.value === 'get' && !match(':')) {
+                key = parseObjectPropertyKey();
+                expect('(');
+                expect(')');
+                return {
+                    type: Syntax.Property,
+                    key: key,
+                    value: parsePropertyFunction([]),
+                    kind: 'get'
+                };
+            } else if (token.value === 'set' && !match(':')) {
+                key = parseObjectPropertyKey();
+                expect('(');
+                token = lookahead();
+                if (token.type !== Token.Identifier) {
+                    throwUnexpected(lex());
+                }
+                param = [ parseVariableIdentifier() ];
+                expect(')');
+                return {
+                    type: Syntax.Property,
+                    key: key,
+                    value: parsePropertyFunction(param, token),
+                    kind: 'set'
+                };
+            } else {
+                expect(':');
+                return {
+                    type: Syntax.Property,
+                    key: id,
+                    value: parseAssignmentExpression(),
+                    kind: 'init'
+                };
+            }
+        } else if (token.type === Token.EOF || token.type === Token.Punctuator) {
+            throwUnexpected(token);
+        } else {
+            key = parseObjectPropertyKey();
+            expect(':');
+            return {
+                type: Syntax.Property,
+                key: key,
+                value: parseAssignmentExpression(),
+                kind: 'init'
+            };
+        }
+    }
+
+    function parseObjectInitialiser() {
+        var token, properties = [], property, name, kind, map = {}, toString = String;
+
+        expect('{');
+
+        while (!match('}')) {
+            property = parseObjectProperty();
+
+            if (property.key.type === Syntax.Identifier) {
+                name = property.key.name;
+            } else {
+                name = toString(property.key.value);
+            }
+            kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set;
+            if (Object.prototype.hasOwnProperty.call(map, name)) {
+                if (map[name] === PropertyKind.Data) {
+                    if (strict && kind === PropertyKind.Data) {
+                        throwErrorTolerant({}, Messages.StrictDuplicateProperty);
+                    } else if (kind !== PropertyKind.Data) {
+                        throwError({}, Messages.AccessorDataProperty);
+                    }
+                } else {
+                    if (kind === PropertyKind.Data) {
+                        throwError({}, Messages.AccessorDataProperty);
+                    } else if (map[name] & kind) {
+                        throwError({}, Messages.AccessorGetSet);
+                    }
+                }
+                map[name] |= kind;
+            } else {
+                map[name] = kind;
+            }
+
+            properties.push(property);
+
+            if (!match('}')) {
+                expect(',');
+            }
+        }
+
+        expect('}');
+
+        return {
+            type: Syntax.ObjectExpression,
+            properties: properties
+        };
+    }
+
+    // 11.1 Primary Expressions
+
+    function parsePrimaryExpression() {
+        var expr,
+            token = lookahead(),
+            type = token.type;
+
+        if (type === Token.Identifier) {
+            return {
+                type: Syntax.Identifier,
+                name: lex().value
+            };
+        }
+
+        if (type === Token.StringLiteral || type === Token.NumericLiteral) {
+            if (strict && token.octal) {
+                throwErrorTolerant(token, Messages.StrictOctalLiteral);
+            }
+            return createLiteral(lex());
+        }
+
+        if (type === Token.Keyword) {
+            if (matchKeyword('this')) {
+                lex();
+                return {
+                    type: Syntax.ThisExpression
+                };
+            }
+
+            if (matchKeyword('function')) {
+                return parseFunctionExpression();
+            }
+        }
+
+        if (type === Token.BooleanLiteral) {
+            lex();
+            token.value = (token.value === 'true');
+            return createLiteral(token);
+        }
+
+        if (type === Token.NullLiteral) {
+            lex();
+            token.value = null;
+            return createLiteral(token);
+        }
+
+        if (match('[')) {
+            return parseArrayInitialiser();
+        }
+
+        if (match('{')) {
+            return parseObjectInitialiser();
+        }
+
+        if (match('(')) {
+            lex();
+            state.lastParenthesized = expr = parseExpression();
+            expect(')');
+            return expr;
+        }
+
+        if (match('/') || match('/=')) {
+            return createLiteral(scanRegExp());
+        }
+
+        return throwUnexpected(lex());
+    }
+
+    // 11.2 Left-Hand-Side Expressions
+
+    function parseArguments() {
+        var args = [];
+
+        expect('(');
+
+        if (!match(')')) {
+            while (index < length) {
+                args.push(parseAssignmentExpression());
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        return args;
+    }
+
+    function parseNonComputedProperty() {
+        var token = lex();
+
+        if (!isIdentifierName(token)) {
+            throwUnexpected(token);
+        }
+
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
+    }
+
+    function parseNonComputedMember(object) {
+        return {
+            type: Syntax.MemberExpression,
+            computed: false,
+            object: object,
+            property: parseNonComputedProperty()
+        };
+    }
+
+    function parseComputedMember(object) {
+        var property, expr;
+
+        expect('[');
+        property = parseExpression();
+        expr = {
+            type: Syntax.MemberExpression,
+            computed: true,
+            object: object,
+            property: property
+        };
+        expect(']');
+        return expr;
+    }
+
+    function parseCallMember(object) {
+        return {
+            type: Syntax.CallExpression,
+            callee: object,
+            'arguments': parseArguments()
+        };
+    }
+
+    function parseNewExpression() {
+        var expr;
+
+        expectKeyword('new');
+
+        expr = {
+            type: Syntax.NewExpression,
+            callee: parseLeftHandSideExpression(),
+            'arguments': []
+        };
+
+        if (match('(')) {
+            expr['arguments'] = parseArguments();
+        }
+
+        return expr;
+    }
+
+    function parseLeftHandSideExpressionAllowCall() {
+        var useNew, expr;
+
+        useNew = matchKeyword('new');
+        expr = useNew ? parseNewExpression() : parsePrimaryExpression();
+
+        while (index < length) {
+            if (match('.')) {
+                lex();
+                expr = parseNonComputedMember(expr);
+            } else if (match('[')) {
+                expr = parseComputedMember(expr);
+            } else if (match('(')) {
+                expr = parseCallMember(expr);
+            } else {
+                break;
+            }
+        }
+
+        return expr;
+    }
+
+    function parseLeftHandSideExpression() {
+        var useNew, expr;
+
+        useNew = matchKeyword('new');
+        expr = useNew ? parseNewExpression() : parsePrimaryExpression();
+
+        while (index < length) {
+            if (match('.')) {
+                lex();
+                expr = parseNonComputedMember(expr);
+            } else if (match('[')) {
+                expr = parseComputedMember(expr);
+            } else {
+                break;
+            }
+        }
+
+        return expr;
+    }
+
+    // 11.3 Postfix Expressions
+
+    function parsePostfixExpression() {
+        var expr = parseLeftHandSideExpressionAllowCall();
+
+        if ((match('++') || match('--')) && !peekLineTerminator()) {
+            // 11.3.1, 11.3.2
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSPostfix);
+            }
+
+            if (!isLeftHandSide(expr)) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+
+            expr = {
+                type: Syntax.UpdateExpression,
+                operator: lex().value,
+                argument: expr,
+                prefix: false
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.4 Unary Operators
+
+    function parseUnaryExpression() {
+        var token, expr;
+
+        if (match('++') || match('--')) {
+            token = lex();
+            expr = parseUnaryExpression();
+            // 11.4.4, 11.4.5
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSPrefix);
+            }
+
+            if (!isLeftHandSide(expr)) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+
+            expr = {
+                type: Syntax.UpdateExpression,
+                operator: token.value,
+                argument: expr,
+                prefix: true
+            };
+            return expr;
+        }
+
+        if (match('+') || match('-') || match('~') || match('!')) {
+            expr = {
+                type: Syntax.UnaryExpression,
+                operator: lex().value,
+                argument: parseUnaryExpression()
+            };
+            return expr;
+        }
+
+        if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) {
+            expr = {
+                type: Syntax.UnaryExpression,
+                operator: lex().value,
+                argument: parseUnaryExpression()
+            };
+            if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) {
+                throwErrorTolerant({}, Messages.StrictDelete);
+            }
+            return expr;
+        }
+
+        return parsePostfixExpression();
+    }
+
+    // 11.5 Multiplicative Operators
+
+    function parseMultiplicativeExpression() {
+        var expr = parseUnaryExpression();
+
+        while (match('*') || match('/') || match('%')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseUnaryExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.6 Additive Operators
+
+    function parseAdditiveExpression() {
+        var expr = parseMultiplicativeExpression();
+
+        while (match('+') || match('-')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseMultiplicativeExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.7 Bitwise Shift Operators
+
+    function parseShiftExpression() {
+        var expr = parseAdditiveExpression();
+
+        while (match('<<') || match('>>') || match('>>>')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseAdditiveExpression()
+            };
+        }
+
+        return expr;
+    }
+    // 11.8 Relational Operators
+
+    function parseRelationalExpression() {
+        var expr, previousAllowIn;
+
+        previousAllowIn = state.allowIn;
+        state.allowIn = true;
+
+        expr = parseShiftExpression();
+
+        while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseShiftExpression()
+            };
+        }
+
+        state.allowIn = previousAllowIn;
+        return expr;
+    }
+
+    // 11.9 Equality Operators
+
+    function parseEqualityExpression() {
+        var expr = parseRelationalExpression();
+
+        while (match('==') || match('!=') || match('===') || match('!==')) {
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseRelationalExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.10 Binary Bitwise Operators
+
+    function parseBitwiseANDExpression() {
+        var expr = parseEqualityExpression();
+
+        while (match('&')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '&',
+                left: expr,
+                right: parseEqualityExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseBitwiseXORExpression() {
+        var expr = parseBitwiseANDExpression();
+
+        while (match('^')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '^',
+                left: expr,
+                right: parseBitwiseANDExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseBitwiseORExpression() {
+        var expr = parseBitwiseXORExpression();
+
+        while (match('|')) {
+            lex();
+            expr = {
+                type: Syntax.BinaryExpression,
+                operator: '|',
+                left: expr,
+                right: parseBitwiseXORExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.11 Binary Logical Operators
+
+    function parseLogicalANDExpression() {
+        var expr = parseBitwiseORExpression();
+
+        while (match('&&')) {
+            lex();
+            expr = {
+                type: Syntax.LogicalExpression,
+                operator: '&&',
+                left: expr,
+                right: parseBitwiseORExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    function parseLogicalORExpression() {
+        var expr = parseLogicalANDExpression();
+
+        while (match('||')) {
+            lex();
+            expr = {
+                type: Syntax.LogicalExpression,
+                operator: '||',
+                left: expr,
+                right: parseLogicalANDExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.12 Conditional Operator
+
+    function parseConditionalExpression() {
+        var expr, previousAllowIn, consequent;
+
+        expr = parseLogicalORExpression();
+
+        if (match('?')) {
+            lex();
+            previousAllowIn = state.allowIn;
+            state.allowIn = true;
+            consequent = parseAssignmentExpression();
+            state.allowIn = previousAllowIn;
+            expect(':');
+
+            expr = {
+                type: Syntax.ConditionalExpression,
+                test: expr,
+                consequent: consequent,
+                alternate: parseAssignmentExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.13 Assignment Operators
+
+    function parseAssignmentExpression() {
+        var expr;
+
+        expr = parseConditionalExpression();
+
+        if (matchAssign()) {
+            // LeftHandSideExpression
+            if (!isLeftHandSide(expr)) {
+                throwError({}, Messages.InvalidLHSInAssignment);
+            }
+
+            // 11.13.1
+            if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) {
+                throwError({}, Messages.StrictLHSAssignment);
+            }
+
+            expr = {
+                type: Syntax.AssignmentExpression,
+                operator: lex().value,
+                left: expr,
+                right: parseAssignmentExpression()
+            };
+        }
+
+        return expr;
+    }
+
+    // 11.14 Comma Operator
+
+    function parseExpression() {
+        var expr = parseAssignmentExpression();
+
+        if (match(',')) {
+            expr = {
+                type: Syntax.SequenceExpression,
+                expressions: [ expr ]
+            };
+
+            while (index < length) {
+                if (!match(',')) {
+                    break;
+                }
+                lex();
+                expr.expressions.push(parseAssignmentExpression());
+            }
+
+        }
+        return expr;
+    }
+
+    // 12.1 Block
+
+    function parseStatementList() {
+        var list = [],
+            statement;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            statement = parseSourceElement();
+            if (typeof statement === 'undefined') {
+                break;
+            }
+            list.push(statement);
+        }
+
+        return list;
+    }
+
+    function parseBlock() {
+        var block;
+
+        expect('{');
+
+        block = parseStatementList();
+
+        expect('}');
+
+        return {
+            type: Syntax.BlockStatement,
+            body: block
+        };
+    }
+
+    // 12.2 Variable Statement
+
+    function parseVariableIdentifier() {
+        var token = lex();
+
+        if (token.type !== Token.Identifier) {
+            throwUnexpected(token);
+        }
+
+        return {
+            type: Syntax.Identifier,
+            name: token.value
+        };
+    }
+
+    function parseVariableDeclaration(kind) {
+        var id = parseVariableIdentifier(),
+            init = null;
+
+        // 12.2.1
+        if (strict && isRestrictedWord(id.name)) {
+            throwErrorTolerant({}, Messages.StrictVarName);
+        }
+
+        if (kind === 'const') {
+            expect('=');
+            init = parseAssignmentExpression();
+        } else if (match('=')) {
+            lex();
+            init = parseAssignmentExpression();
+        }
+
+        return {
+            type: Syntax.VariableDeclarator,
+            id: id,
+            init: init
+        };
+    }
+
+    function parseVariableDeclarationList(kind) {
+        var list = [];
+
+        while (index < length) {
+            list.push(parseVariableDeclaration(kind));
+            if (!match(',')) {
+                break;
+            }
+            lex();
+        }
+
+        return list;
+    }
+
+    function parseVariableStatement() {
+        var declarations;
+
+        expectKeyword('var');
+
+        declarations = parseVariableDeclarationList();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: declarations,
+            kind: 'var'
+        };
+    }
+
+    // kind may be `const` or `let`
+    // Both are experimental and not in the specification yet.
+    // see http://wiki.ecmascript.org/doku.php?id=harmony:const
+    // and http://wiki.ecmascript.org/doku.php?id=harmony:let
+    function parseConstLetDeclaration(kind) {
+        var declarations;
+
+        expectKeyword(kind);
+
+        declarations = parseVariableDeclarationList(kind);
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: declarations,
+            kind: kind
+        };
+    }
+
+    // 12.3 Empty Statement
+
+    function parseEmptyStatement() {
+        expect(';');
+
+        return {
+            type: Syntax.EmptyStatement
+        };
+    }
+
+    // 12.4 Expression Statement
+
+    function parseExpressionStatement() {
+        var expr = parseExpression();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ExpressionStatement,
+            expression: expr
+        };
+    }
+
+    // 12.5 If statement
+
+    function parseIfStatement() {
+        var test, consequent, alternate;
+
+        expectKeyword('if');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        consequent = parseStatement();
+
+        if (matchKeyword('else')) {
+            lex();
+            alternate = parseStatement();
+        } else {
+            alternate = null;
+        }
+
+        return {
+            type: Syntax.IfStatement,
+            test: test,
+            consequent: consequent,
+            alternate: alternate
+        };
+    }
+
+    // 12.6 Iteration Statements
+
+    function parseDoWhileStatement() {
+        var body, test, oldInIteration;
+
+        expectKeyword('do');
+
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
+
+        body = parseStatement();
+
+        state.inIteration = oldInIteration;
+
+        expectKeyword('while');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        if (match(';')) {
+            lex();
+        }
+
+        return {
+            type: Syntax.DoWhileStatement,
+            body: body,
+            test: test
+        };
+    }
+
+    function parseWhileStatement() {
+        var test, body, oldInIteration;
+
+        expectKeyword('while');
+
+        expect('(');
+
+        test = parseExpression();
+
+        expect(')');
+
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
+
+        body = parseStatement();
+
+        state.inIteration = oldInIteration;
+
+        return {
+            type: Syntax.WhileStatement,
+            test: test,
+            body: body
+        };
+    }
+
+    function parseForVariableDeclaration() {
+        var token = lex();
+
+        return {
+            type: Syntax.VariableDeclaration,
+            declarations: parseVariableDeclarationList(),
+            kind: token.value
+        };
+    }
+
+    function parseForStatement() {
+        var init, test, update, left, right, body, oldInIteration;
+
+        init = test = update = null;
+
+        expectKeyword('for');
+
+        expect('(');
+
+        if (match(';')) {
+            lex();
+        } else {
+            if (matchKeyword('var') || matchKeyword('let')) {
+                state.allowIn = false;
+                init = parseForVariableDeclaration();
+                state.allowIn = true;
+
+                if (init.declarations.length === 1 && matchKeyword('in')) {
+                    lex();
+                    left = init;
+                    right = parseExpression();
+                    init = null;
+                }
+            } else {
+                state.allowIn = false;
+                init = parseExpression();
+                state.allowIn = true;
+
+                if (matchKeyword('in')) {
+                    // LeftHandSideExpression
+                    if (!isLeftHandSide(init)) {
+                        throwError({}, Messages.InvalidLHSInForIn);
+                    }
+
+                    lex();
+                    left = init;
+                    right = parseExpression();
+                    init = null;
+                }
+            }
+
+            if (typeof left === 'undefined') {
+                expect(';');
+            }
+        }
+
+        if (typeof left === 'undefined') {
+
+            if (!match(';')) {
+                test = parseExpression();
+            }
+            expect(';');
+
+            if (!match(')')) {
+                update = parseExpression();
+            }
+        }
+
+        expect(')');
+
+        oldInIteration = state.inIteration;
+        state.inIteration = true;
+
+        body = parseStatement();
+
+        state.inIteration = oldInIteration;
+
+        if (typeof left === 'undefined') {
+            return {
+                type: Syntax.ForStatement,
+                init: init,
+                test: test,
+                update: update,
+                body: body
+            };
+        }
+
+        return {
+            type: Syntax.ForInStatement,
+            left: left,
+            right: right,
+            body: body,
+            each: false
+        };
+    }
+
+    // 12.7 The continue statement
+
+    function parseContinueStatement() {
+        var token, label = null;
+
+        expectKeyword('continue');
+
+        // Optimize the most common form: 'continue;'.
+        if (source[index] === ';') {
+            lex();
+
+            if (!state.inIteration) {
+                throwError({}, Messages.IllegalContinue);
+            }
+
+            return {
+                type: Syntax.ContinueStatement,
+                label: null
+            };
+        }
+
+        if (peekLineTerminator()) {
+            if (!state.inIteration) {
+                throwError({}, Messages.IllegalContinue);
+            }
+
+            return {
+                type: Syntax.ContinueStatement,
+                label: null
+            };
+        }
+
+        token = lookahead();
+        if (token.type === Token.Identifier) {
+            label = parseVariableIdentifier();
+
+            if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
+                throwError({}, Messages.UnknownLabel, label.name);
+            }
+        }
+
+        consumeSemicolon();
+
+        if (label === null && !state.inIteration) {
+            throwError({}, Messages.IllegalContinue);
+        }
+
+        return {
+            type: Syntax.ContinueStatement,
+            label: label
+        };
+    }
+
+    // 12.8 The break statement
+
+    function parseBreakStatement() {
+        var token, label = null;
+
+        expectKeyword('break');
+
+        // Optimize the most common form: 'break;'.
+        if (source[index] === ';') {
+            lex();
+
+            if (!(state.inIteration || state.inSwitch)) {
+                throwError({}, Messages.IllegalBreak);
+            }
+
+            return {
+                type: Syntax.BreakStatement,
+                label: null
+            };
+        }
+
+        if (peekLineTerminator()) {
+            if (!(state.inIteration || state.inSwitch)) {
+                throwError({}, Messages.IllegalBreak);
+            }
+
+            return {
+                type: Syntax.BreakStatement,
+                label: null
+            };
+        }
+
+        token = lookahead();
+        if (token.type === Token.Identifier) {
+            label = parseVariableIdentifier();
+
+            if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) {
+                throwError({}, Messages.UnknownLabel, label.name);
+            }
+        }
+
+        consumeSemicolon();
+
+        if (label === null && !(state.inIteration || state.inSwitch)) {
+            throwError({}, Messages.IllegalBreak);
+        }
+
+        return {
+            type: Syntax.BreakStatement,
+            label: label
+        };
+    }
+
+    // 12.9 The return statement
+
+    function parseReturnStatement() {
+        var token, argument = null;
+
+        expectKeyword('return');
+
+        if (!state.inFunctionBody) {
+            throwErrorTolerant({}, Messages.IllegalReturn);
+        }
+
+        // 'return' followed by a space and an identifier is very common.
+        if (source[index] === ' ') {
+            if (isIdentifierStart(source[index + 1])) {
+                argument = parseExpression();
+                consumeSemicolon();
+                return {
+                    type: Syntax.ReturnStatement,
+                    argument: argument
+                };
+            }
+        }
+
+        if (peekLineTerminator()) {
+            return {
+                type: Syntax.ReturnStatement,
+                argument: null
+            };
+        }
+
+        if (!match(';')) {
+            token = lookahead();
+            if (!match('}') && token.type !== Token.EOF) {
+                argument = parseExpression();
+            }
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ReturnStatement,
+            argument: argument
+        };
+    }
+
+    // 12.10 The with statement
+
+    function parseWithStatement() {
+        var object, body;
+
+        if (strict) {
+            throwErrorTolerant({}, Messages.StrictModeWith);
+        }
+
+        expectKeyword('with');
+
+        expect('(');
+
+        object = parseExpression();
+
+        expect(')');
+
+        body = parseStatement();
+
+        return {
+            type: Syntax.WithStatement,
+            object: object,
+            body: body
+        };
+    }
+
+    // 12.10 The swith statement
+
+    function parseSwitchCase() {
+        var test,
+            consequent = [],
+            statement;
+
+        if (matchKeyword('default')) {
+            lex();
+            test = null;
+        } else {
+            expectKeyword('case');
+            test = parseExpression();
+        }
+        expect(':');
+
+        while (index < length) {
+            if (match('}') || matchKeyword('default') || matchKeyword('case')) {
+                break;
+            }
+            statement = parseStatement();
+            if (typeof statement === 'undefined') {
+                break;
+            }
+            consequent.push(statement);
+        }
+
+        return {
+            type: Syntax.SwitchCase,
+            test: test,
+            consequent: consequent
+        };
+    }
+
+    function parseSwitchStatement() {
+        var discriminant, cases, oldInSwitch;
+
+        expectKeyword('switch');
+
+        expect('(');
+
+        discriminant = parseExpression();
+
+        expect(')');
+
+        expect('{');
+
+        if (match('}')) {
+            lex();
+            return {
+                type: Syntax.SwitchStatement,
+                discriminant: discriminant
+            };
+        }
+
+        cases = [];
+
+        oldInSwitch = state.inSwitch;
+        state.inSwitch = true;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            cases.push(parseSwitchCase());
+        }
+
+        state.inSwitch = oldInSwitch;
+
+        expect('}');
+
+        return {
+            type: Syntax.SwitchStatement,
+            discriminant: discriminant,
+            cases: cases
+        };
+    }
+
+    // 12.13 The throw statement
+
+    function parseThrowStatement() {
+        var argument;
+
+        expectKeyword('throw');
+
+        if (peekLineTerminator()) {
+            throwError({}, Messages.NewlineAfterThrow);
+        }
+
+        argument = parseExpression();
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ThrowStatement,
+            argument: argument
+        };
+    }
+
+    // 12.14 The try statement
+
+    function parseCatchClause() {
+        var param;
+
+        expectKeyword('catch');
+
+        expect('(');
+        if (!match(')')) {
+            param = parseExpression();
+            // 12.14.1
+            if (strict && param.type === Syntax.Identifier && isRestrictedWord(param.name)) {
+                throwErrorTolerant({}, Messages.StrictCatchVariable);
+            }
+        }
+        expect(')');
+
+        return {
+            type: Syntax.CatchClause,
+            param: param,
+            guard: null,
+            body: parseBlock()
+        };
+    }
+
+    function parseTryStatement() {
+        var block, handlers = [], finalizer = null;
+
+        expectKeyword('try');
+
+        block = parseBlock();
+
+        if (matchKeyword('catch')) {
+            handlers.push(parseCatchClause());
+        }
+
+        if (matchKeyword('finally')) {
+            lex();
+            finalizer = parseBlock();
+        }
+
+        if (handlers.length === 0 && !finalizer) {
+            throwError({}, Messages.NoCatchOrFinally);
+        }
+
+        return {
+            type: Syntax.TryStatement,
+            block: block,
+            handlers: handlers,
+            finalizer: finalizer
+        };
+    }
+
+    // 12.15 The debugger statement
+
+    function parseDebuggerStatement() {
+        expectKeyword('debugger');
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.DebuggerStatement
+        };
+    }
+
+    // 12 Statements
+
+    function parseStatement() {
+        var token = lookahead(),
+            expr,
+            labeledBody;
+
+        if (token.type === Token.EOF) {
+            throwUnexpected(token);
+        }
+
+        if (token.type === Token.Punctuator) {
+            switch (token.value) {
+            case ';':
+                return parseEmptyStatement();
+            case '{':
+                return parseBlock();
+            case '(':
+                return parseExpressionStatement();
+            default:
+                break;
+            }
+        }
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'break':
+                return parseBreakStatement();
+            case 'continue':
+                return parseContinueStatement();
+            case 'debugger':
+                return parseDebuggerStatement();
+            case 'do':
+                return parseDoWhileStatement();
+            case 'for':
+                return parseForStatement();
+            case 'function':
+                return parseFunctionDeclaration();
+            case 'if':
+                return parseIfStatement();
+            case 'return':
+                return parseReturnStatement();
+            case 'switch':
+                return parseSwitchStatement();
+            case 'throw':
+                return parseThrowStatement();
+            case 'try':
+                return parseTryStatement();
+            case 'var':
+                return parseVariableStatement();
+            case 'while':
+                return parseWhileStatement();
+            case 'with':
+                return parseWithStatement();
+            default:
+                break;
+            }
+        }
+
+        expr = parseExpression();
+
+        // 12.12 Labelled Statements
+        if ((expr.type === Syntax.Identifier) && match(':')) {
+            lex();
+
+            if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) {
+                throwError({}, Messages.Redeclaration, 'Label', expr.name);
+            }
+
+            state.labelSet[expr.name] = true;
+            labeledBody = parseStatement();
+            delete state.labelSet[expr.name];
+
+            return {
+                type: Syntax.LabeledStatement,
+                label: expr,
+                body: labeledBody
+            };
+        }
+
+        consumeSemicolon();
+
+        return {
+            type: Syntax.ExpressionStatement,
+            expression: expr
+        };
+    }
+
+    // 13 Function Definition
+
+    function parseFunctionSourceElements() {
+        var sourceElement, sourceElements = [], token, directive, firstRestricted,
+            oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody;
+
+        expect('{');
+
+        while (index < length) {
+            token = lookahead();
+            if (token.type !== Token.StringLiteral) {
+                break;
+            }
+
+            sourceElement = parseSourceElement();
+            sourceElements.push(sourceElement);
+            if (sourceElement.expression.type !== Syntax.Literal) {
+                // this is not directive
+                break;
+            }
+            directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
+            if (directive === 'use strict') {
+                strict = true;
+                if (firstRestricted) {
+                    throwError(firstRestricted, Messages.StrictOctalLiteral);
+                }
+            } else {
+                if (!firstRestricted && token.octal) {
+                    firstRestricted = token;
+                }
+            }
+        }
+
+        oldLabelSet = state.labelSet;
+        oldInIteration = state.inIteration;
+        oldInSwitch = state.inSwitch;
+        oldInFunctionBody = state.inFunctionBody;
+
+        state.labelSet = {};
+        state.inIteration = false;
+        state.inSwitch = false;
+        state.inFunctionBody = true;
+
+        while (index < length) {
+            if (match('}')) {
+                break;
+            }
+            sourceElement = parseSourceElement();
+            if (typeof sourceElement === 'undefined') {
+                break;
+            }
+            sourceElements.push(sourceElement);
+        }
+
+        expect('}');
+
+        state.labelSet = oldLabelSet;
+        state.inIteration = oldInIteration;
+        state.inSwitch = oldInSwitch;
+        state.inFunctionBody = oldInFunctionBody;
+
+        return {
+            type: Syntax.BlockStatement,
+            body: sourceElements
+        };
+    }
+
+    function parseFunctionDeclaration() {
+        var id, param, params = [], body, token, firstRestricted, message, previousStrict, paramSet;
+
+        expectKeyword('function');
+        token = lookahead();
+        id = parseVariableIdentifier();
+        if (strict) {
+            if (isRestrictedWord(token.value)) {
+                throwError(token, Messages.StrictFunctionName);
+            }
+        } else {
+            if (isRestrictedWord(token.value)) {
+                firstRestricted = token;
+                message = Messages.StrictFunctionName;
+            } else if (isStrictModeReservedWord(token.value)) {
+                firstRestricted = token;
+                message = Messages.StrictReservedWord;
+            }
+        }
+
+        expect('(');
+
+        if (!match(')')) {
+            paramSet = {};
+            while (index < length) {
+                token = lookahead();
+                param = parseVariableIdentifier();
+                if (strict) {
+                    if (isRestrictedWord(token.value)) {
+                        throwError(token, Messages.StrictParamName);
+                    }
+                    if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        throwError(token, Messages.StrictParamDupe);
+                    }
+                } else if (!firstRestricted) {
+                    if (isRestrictedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamName;
+                    } else if (isStrictModeReservedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictReservedWord;
+                    } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamDupe;
+                    }
+                }
+                params.push(param);
+                paramSet[param.name] = true;
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (strict && firstRestricted) {
+            throwError(firstRestricted, message);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionDeclaration,
+            id: id,
+            params: params,
+            body: body
+        };
+    }
+
+    function parseFunctionExpression() {
+        var token, id = null, firstRestricted, message, param, params = [], body, previousStrict, paramSet;
+
+        expectKeyword('function');
+
+        if (!match('(')) {
+            token = lookahead();
+            id = parseVariableIdentifier();
+            if (strict) {
+                if (isRestrictedWord(token.value)) {
+                    throwError(token, Messages.StrictFunctionName);
+                }
+            } else {
+                if (isRestrictedWord(token.value)) {
+                    firstRestricted = token;
+                    message = Messages.StrictFunctionName;
+                } else if (isStrictModeReservedWord(token.value)) {
+                    firstRestricted = token;
+                    message = Messages.StrictReservedWord;
+                }
+            }
+        }
+
+        expect('(');
+
+        if (!match(')')) {
+            paramSet = {};
+            while (index < length) {
+                token = lookahead();
+                param = parseVariableIdentifier();
+                if (strict) {
+                    if (isRestrictedWord(token.value)) {
+                        throwError(token, Messages.StrictParamName);
+                    }
+                    if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        throwError(token, Messages.StrictParamDupe);
+                    }
+                } else if (!firstRestricted) {
+                    if (isRestrictedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamName;
+                    } else if (isStrictModeReservedWord(token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictReservedWord;
+                    } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) {
+                        firstRestricted = token;
+                        message = Messages.StrictParamDupe;
+                    }
+                }
+                params.push(param);
+                paramSet[param.name] = true;
+                if (match(')')) {
+                    break;
+                }
+                expect(',');
+            }
+        }
+
+        expect(')');
+
+        previousStrict = strict;
+        body = parseFunctionSourceElements();
+        if (strict && firstRestricted) {
+            throwError(firstRestricted, message);
+        }
+        strict = previousStrict;
+
+        return {
+            type: Syntax.FunctionExpression,
+            id: id,
+            params: params,
+            body: body
+        };
+    }
+
+    // 14 Program
+
+    function parseSourceElement() {
+        var token = lookahead();
+
+        if (token.type === Token.Keyword) {
+            switch (token.value) {
+            case 'const':
+            case 'let':
+                return parseConstLetDeclaration(token.value);
+            case 'function':
+                return parseFunctionDeclaration();
+            default:
+                return parseStatement();
+            }
+        }
+
+        if (token.type !== Token.EOF) {
+            return parseStatement();
+        }
+    }
+
+    function parseSourceElements() {
+        var sourceElement, sourceElements = [], token, directive, firstRestricted;
+
+        while (index < length) {
+            token = lookahead();
+            if (token.type !== Token.StringLiteral) {
+                break;
+            }
+
+            sourceElement = parseSourceElement();
+            sourceElements.push(sourceElement);
+            if (sourceElement.expression.type !== Syntax.Literal) {
+                // this is not directive
+                break;
+            }
+            directive = sliceSource(token.range[0] + 1, token.range[1] - 1);
+            if (directive === 'use strict') {
+                strict = true;
+                if (firstRestricted) {
+                    throwError(firstRestricted, Messages.StrictOctalLiteral);
+                }
+            } else {
+                if (!firstRestricted && token.octal) {
+                    firstRestricted = token;
+                }
+            }
+        }
+
+        while (index < length) {
+            sourceElement = parseSourceElement();
+            if (typeof sourceElement === 'undefined') {
+                break;
+            }
+            sourceElements.push(sourceElement);
+        }
+        return sourceElements;
+    }
+
+    function parseProgram() {
+        var program;
+        strict = false;
+        program = {
+            type: Syntax.Program,
+            body: parseSourceElements()
+        };
+        return program;
+    }
+
+    // The following functions are needed only when the option to preserve
+    // the comments is active.
+
+    function addComment(start, end, type, value) {
+        assert(typeof start === 'number', 'Comment must have valid position');
+
+        // Because the way the actual token is scanned, often the comments
+        // (if any) are skipped twice during the lexical analysis.
+        // Thus, we need to skip adding a comment if the comment array already
+        // handled it.
+        if (extra.comments.length > 0) {
+            if (extra.comments[extra.comments.length - 1].range[1] > start) {
+                return;
+            }
+        }
+
+        extra.comments.push({
+            range: [start, end],
+            type: type,
+            value: value
+        });
+    }
+
+    function scanComment() {
+        var comment, ch, start, blockComment, lineComment;
+
+        comment = '';
+        blockComment = false;
+        lineComment = false;
+
+        while (index < length) {
+            ch = source[index];
+
+            if (lineComment) {
+                ch = nextChar();
+                if (index >= length) {
+                    lineComment = false;
+                    comment += ch;
+                    addComment(start, index, 'Line', comment);
+                } else if (isLineTerminator(ch)) {
+                    lineComment = false;
+                    addComment(start, index, 'Line', comment);
+                    if (ch === '\r' && source[index] === '\n') {
+                        ++index;
+                    }
+                    ++lineNumber;
+                    lineStart = index;
+                    comment = '';
+                } else {
+                    comment += ch;
+                }
+            } else if (blockComment) {
+                if (isLineTerminator(ch)) {
+                    if (ch === '\r' && source[index + 1] === '\n') {
+                        ++index;
+                        comment += '\r\n';
+                    } else {
+                        comment += ch;
+                    }
+                    ++lineNumber;
+                    ++index;
+                    lineStart = index;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    ch = nextChar();
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                    comment += ch;
+                    if (ch === '*') {
+                        ch = source[index];
+                        if (ch === '/') {
+                            comment = comment.substr(0, comment.length - 1);
+                            blockComment = false;
+                            ++index;
+                            addComment(start, index, 'Block', comment);
+                            comment = '';
+                        }
+                    }
+                }
+            } else if (ch === '/') {
+                ch = source[index + 1];
+                if (ch === '/') {
+                    start = index;
+                    index += 2;
+                    lineComment = true;
+                } else if (ch === '*') {
+                    start = index;
+                    index += 2;
+                    blockComment = true;
+                    if (index >= length) {
+                        throwError({}, Messages.UnexpectedToken, 'ILLEGAL');
+                    }
+                } else {
+                    break;
+                }
+            } else if (isWhiteSpace(ch)) {
+                ++index;
+            } else if (isLineTerminator(ch)) {
+                ++index;
+                if (ch ===  '\r' && source[index] === '\n') {
+                    ++index;
+                }
+                ++lineNumber;
+                lineStart = index;
+            } else {
+                break;
+            }
+        }
+    }
+
+    function collectToken() {
+        var token = extra.advance(),
+            range,
+            value;
+
+        if (token.type !== Token.EOF) {
+            range = [token.range[0], token.range[1]];
+            value = sliceSource(token.range[0], token.range[1]);
+            extra.tokens.push({
+                type: TokenName[token.type],
+                value: value,
+                range: range
+            });
+        }
+
+        return token;
+    }
+
+    function collectRegex() {
+        var pos, regex, token;
+
+        skipComment();
+
+        pos = index;
+        regex = extra.scanRegExp();
+
+        // Pop the previous token, which is likely '/' or '/='
+        if (extra.tokens.length > 0) {
+            token = extra.tokens[extra.tokens.length - 1];
+            if (token.range[0] === pos && token.type === 'Punctuator') {
+                if (token.value === '/' || token.value === '/=') {
+                    extra.tokens.pop();
+                }
+            }
+        }
+
+        extra.tokens.push({
+            type: 'RegularExpression',
+            value: regex.literal,
+            range: [pos, index]
+        });
+
+        return regex;
+    }
+
+    function createLiteral(token) {
+        return {
+            type: Syntax.Literal,
+            value: token.value
+        };
+    }
+
+    function createRawLiteral(token) {
+        return {
+            type: Syntax.Literal,
+            value: token.value,
+            raw: sliceSource(token.range[0], token.range[1])
+        };
+    }
+
+    function wrapTrackingFunction(range, loc) {
+
+        return function (parseFunction) {
+
+            function isBinary(node) {
+                return node.type === Syntax.LogicalExpression ||
+                    node.type === Syntax.BinaryExpression;
+            }
+
+            function visit(node) {
+                if (isBinary(node.left)) {
+                    visit(node.left);
+                }
+                if (isBinary(node.right)) {
+                    visit(node.right);
+                }
+
+                if (range && typeof node.range === 'undefined') {
+                    node.range = [node.left.range[0], node.right.range[1]];
+                }
+                if (loc && typeof node.loc === 'undefined') {
+                    node.loc = {
+                        start: node.left.loc.start,
+                        end: node.right.loc.end
+                    };
+                }
+            }
+
+            return function () {
+                var node, rangeInfo, locInfo;
+
+                skipComment();
+                rangeInfo = [index, 0];
+                locInfo = {
+                    start: {
+                        line: lineNumber,
+                        column: index - lineStart
+                    }
+                };
+
+                node = parseFunction.apply(null, arguments);
+                if (typeof node !== 'undefined') {
+
+                    if (range) {
+                        rangeInfo[1] = index;
+                        node.range = rangeInfo;
+                    }
+
+                    if (loc) {
+                        locInfo.end = {
+                            line: lineNumber,
+                            column: index - lineStart
+                        };
+                        node.loc = locInfo;
+                    }
+
+                    if (isBinary(node)) {
+                        visit(node);
+                    }
+
+                    if (node.type === Syntax.MemberExpression) {
+                        if (typeof node.object.range !== 'undefined') {
+                            node.range[0] = node.object.range[0];
+                        }
+                        if (typeof node.object.loc !== 'undefined') {
+                            node.loc.start = node.object.loc.start;
+                        }
+                    }
+
+                    if (node.type === Syntax.CallExpression) {
+                        if (typeof node.callee.range !== 'undefined') {
+                            node.range[0] = node.callee.range[0];
+                        }
+                        if (typeof node.callee.loc !== 'undefined') {
+                            node.loc.start = node.callee.loc.start;
+                        }
+                    }
+                    return node;
+                }
+            };
+
+        };
+    }
+
+    function patch() {
+
+        var wrapTracking;
+
+        if (extra.comments) {
+            extra.skipComment = skipComment;
+            skipComment = scanComment;
+        }
+
+        if (extra.raw) {
+            extra.createLiteral = createLiteral;
+            createLiteral = createRawLiteral;
+        }
+
+        if (extra.range || extra.loc) {
+
+            wrapTracking = wrapTrackingFunction(extra.range, extra.loc);
+
+            extra.parseAdditiveExpression = parseAdditiveExpression;
+            extra.parseAssignmentExpression = parseAssignmentExpression;
+            extra.parseBitwiseANDExpression = parseBitwiseANDExpression;
+            extra.parseBitwiseORExpression = parseBitwiseORExpression;
+            extra.parseBitwiseXORExpression = parseBitwiseXORExpression;
+            extra.parseBlock = parseBlock;
+            extra.parseFunctionSourceElements = parseFunctionSourceElements;
+            extra.parseCallMember = parseCallMember;
+            extra.parseCatchClause = parseCatchClause;
+            extra.parseComputedMember = parseComputedMember;
+            extra.parseConditionalExpression = parseConditionalExpression;
+            extra.parseConstLetDeclaration = parseConstLetDeclaration;
+            extra.parseEqualityExpression = parseEqualityExpression;
+            extra.parseExpression = parseExpression;
+            extra.parseForVariableDeclaration = parseForVariableDeclaration;
+            extra.parseFunctionDeclaration = parseFunctionDeclaration;
+            extra.parseFunctionExpression = parseFunctionExpression;
+            extra.parseLogicalANDExpression = parseLogicalANDExpression;
+            extra.parseLogicalORExpression = parseLogicalORExpression;
+            extra.parseMultiplicativeExpression = parseMultiplicativeExpression;
+            extra.parseNewExpression = parseNewExpression;
+            extra.parseNonComputedMember = parseNonComputedMember;
+            extra.parseNonComputedProperty = parseNonComputedProperty;
+            extra.parseObjectProperty = parseObjectProperty;
+            extra.parseObjectPropertyKey = parseObjectPropertyKey;
+            extra.parsePostfixExpression = parsePostfixExpression;
+            extra.parsePrimaryExpression = parsePrimaryExpression;
+            extra.parseProgram = parseProgram;
+            extra.parsePropertyFunction = parsePropertyFunction;
+            extra.parseRelationalExpression = parseRelationalExpression;
+            extra.parseStatement = parseStatement;
+            extra.parseShiftExpression = parseShiftExpression;
+            extra.parseSwitchCase = parseSwitchCase;
+            extra.parseUnaryExpression = parseUnaryExpression;
+            extra.parseVariableDeclaration = parseVariableDeclaration;
+            extra.parseVariableIdentifier = parseVariableIdentifier;
+
+            parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression);
+            parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression);
+            parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression);
+            parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression);
+            parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression);
+            parseBlock = wrapTracking(extra.parseBlock);
+            parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements);
+            parseCallMember = wrapTracking(extra.parseCallMember);
+            parseCatchClause = wrapTracking(extra.parseCatchClause);
+            parseComputedMember = wrapTracking(extra.parseComputedMember);
+            parseConditionalExpression = wrapTracking(extra.parseConditionalExpression);
+            parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration);
+            parseEqualityExpression = wrapTracking(extra.parseEqualityExpression);
+            parseExpression = wrapTracking(extra.parseExpression);
+            parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration);
+            parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration);
+            parseFunctionExpression = wrapTracking(extra.parseFunctionExpression);
+            parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression);
+            parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression);
+            parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression);
+            parseNewExpression = wrapTracking(extra.parseNewExpression);
+            parseNonComputedMember = wrapTracking(extra.parseNonComputedMember);
+            parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty);
+            parseObjectProperty = wrapTracking(extra.parseObjectProperty);
+            parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey);
+            parsePostfixExpression = wrapTracking(extra.parsePostfixExpression);
+            parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression);
+            parseProgram = wrapTracking(extra.parseProgram);
+            parsePropertyFunction = wrapTracking(extra.parsePropertyFunction);
+            parseRelationalExpression = wrapTracking(extra.parseRelationalExpression);
+            parseStatement = wrapTracking(extra.parseStatement);
+            parseShiftExpression = wrapTracking(extra.parseShiftExpression);
+            parseSwitchCase = wrapTracking(extra.parseSwitchCase);
+            parseUnaryExpression = wrapTracking(extra.parseUnaryExpression);
+            parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration);
+            parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier);
+        }
+
+        if (typeof extra.tokens !== 'undefined') {
+            extra.advance = advance;
+            extra.scanRegExp = scanRegExp;
+
+            advance = collectToken;
+            scanRegExp = collectRegex;
+        }
+    }
+
+    function unpatch() {
+        if (typeof extra.skipComment === 'function') {
+            skipComment = extra.skipComment;
+        }
+
+        if (extra.raw) {
+            createLiteral = extra.createLiteral;
+        }
+
+        if (extra.range || extra.loc) {
+            parseAdditiveExpression = extra.parseAdditiveExpression;
+            parseAssignmentExpression = extra.parseAssignmentExpression;
+            parseBitwiseANDExpression = extra.parseBitwiseANDExpression;
+            parseBitwiseORExpression = extra.parseBitwiseORExpression;
+            parseBitwiseXORExpression = extra.parseBitwiseXORExpression;
+            parseBlock = extra.parseBlock;
+            parseFunctionSourceElements = extra.parseFunctionSourceElements;
+            parseCallMember = extra.parseCallMember;
+            parseCatchClause = extra.parseCatchClause;
+            parseComputedMember = extra.parseComputedMember;
+            parseConditionalExpression = extra.parseConditionalExpression;
+            parseConstLetDeclaration = extra.parseConstLetDeclaration;
+            parseEqualityExpression = extra.parseEqualityExpression;
+            parseExpression = extra.parseExpression;
+            parseForVariableDeclaration = extra.parseForVariableDeclaration;
+            parseFunctionDeclaration = extra.parseFunctionDeclaration;
+            parseFunctionExpression = extra.parseFunctionExpression;
+            parseLogicalANDExpression = extra.parseLogicalANDExpression;
+            parseLogicalORExpression = extra.parseLogicalORExpression;
+            parseMultiplicativeExpression = extra.parseMultiplicativeExpression;
+            parseNewExpression = extra.parseNewExpression;
+            parseNonComputedMember = extra.parseNonComputedMember;
+            parseNonComputedProperty = extra.parseNonComputedProperty;
+            parseObjectProperty = extra.parseObjectProperty;
+            parseObjectPropertyKey = extra.parseObjectPropertyKey;
+            parsePrimaryExpression = extra.parsePrimaryExpression;
+            parsePostfixExpression = extra.parsePostfixExpression;
+            parseProgram = extra.parseProgram;
+            parsePropertyFunction = extra.parsePropertyFunction;
+            parseRelationalExpression = extra.parseRelationalExpression;
+            parseStatement = extra.parseStatement;
+            parseShiftExpression = extra.parseShiftExpression;
+            parseSwitchCase = extra.parseSwitchCase;
+            parseUnaryExpression = extra.parseUnaryExpression;
+            parseVariableDeclaration = extra.parseVariableDeclaration;
+            parseVariableIdentifier = extra.parseVariableIdentifier;
+        }
+
+        if (typeof extra.scanRegExp === 'function') {
+            advance = extra.advance;
+            scanRegExp = extra.scanRegExp;
+        }
+    }
+
+    function stringToArray(str) {
+        var length = str.length,
+            result = [],
+            i;
+        for (i = 0; i < length; ++i) {
+            result[i] = str.charAt(i);
+        }
+        return result;
+    }
+
+    function parse(code, options) {
+        var program, toString;
+
+        toString = String;
+        if (typeof code !== 'string' && !(code instanceof String)) {
+            code = toString(code);
+        }
+
+        source = code;
+        index = 0;
+        lineNumber = (source.length > 0) ? 1 : 0;
+        lineStart = 0;
+        length = source.length;
+        buffer = null;
+        state = {
+            allowIn: true,
+            labelSet: {},
+            lastParenthesized: null,
+            inFunctionBody: false,
+            inIteration: false,
+            inSwitch: false
+        };
+
+        extra = {};
+        if (typeof options !== 'undefined') {
+            extra.range = (typeof options.range === 'boolean') && options.range;
+            extra.loc = (typeof options.loc === 'boolean') && options.loc;
+            extra.raw = (typeof options.raw === 'boolean') && options.raw;
+            if (typeof options.tokens === 'boolean' && options.tokens) {
+                extra.tokens = [];
+            }
+            if (typeof options.comment === 'boolean' && options.comment) {
+                extra.comments = [];
+            }
+            if (typeof options.tolerant === 'boolean' && options.tolerant) {
+                extra.errors = [];
+            }
+        }
+
+        if (length > 0) {
+            if (typeof source[0] === 'undefined') {
+                // Try first to convert to a string. This is good as fast path
+                // for old IE which understands string indexing for string
+                // literals only and not for string object.
+                if (code instanceof String) {
+                    source = code.valueOf();
+                }
+
+                // Force accessing the characters via an array.
+                if (typeof source[0] === 'undefined') {
+                    source = stringToArray(code);
+                }
+            }
+        }
+
+        patch();
+        try {
+            program = parseProgram();
+            if (typeof extra.comments !== 'undefined') {
+                program.comments = extra.comments;
+            }
+            if (typeof extra.tokens !== 'undefined') {
+                program.tokens = extra.tokens;
+            }
+            if (typeof extra.errors !== 'undefined') {
+                program.errors = extra.errors;
+            }
+        } catch (e) {
+            throw e;
+        } finally {
+            unpatch();
+            extra = {};
+        }
+
+        return program;
+    }
+
+    // Sync with package.json.
+    exports.version = '1.0.0-dev';
+
+    exports.parse = parse;
+
+    // Deep copy.
+    exports.Syntax = (function () {
+        var name, types = {};
+
+        if (typeof Object.create === 'function') {
+            types = Object.create(null);
+        }
+
+        for (name in Syntax) {
+            if (Syntax.hasOwnProperty(name)) {
+                types[name] = Syntax[name];
+            }
+        }
+
+        if (typeof Object.freeze === 'function') {
+            Object.freeze(types);
+        }
+
+        return types;
+    }());
+
+}(typeof exports === 'undefined' ? (esprima = {}) : exports));
+/* vim: set sw=4 ts=4 et tw=80 : */
+
+});define('uglifyjs/consolidator', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
+/**
+ * @preserve Copyright 2012 Robert Gust-Bardon <http://robert.gust-bardon.org/>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *     * Redistributions of source code must retain the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer.
+ *
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/**
+ * @fileoverview Enhances <a href="https://github.com/mishoo/UglifyJS/"
+ * >UglifyJS</a> with consolidation of null, Boolean, and String values.
+ * <p>Also known as aliasing, this feature has been deprecated in <a href=
+ * "http://closure-compiler.googlecode.com/">the Closure Compiler</a> since its
+ * initial release, where it is unavailable from the <abbr title=
+ * "command line interface">CLI</a>. The Closure Compiler allows one to log and
+ * influence this process. In contrast, this implementation does not introduce
+ * any variable declarations in global code and derives String values from
+ * identifier names used as property accessors.</p>
+ * <p>Consolidating literals may worsen the data compression ratio when an <a
+ * href="http://tools.ietf.org/html/rfc2616#section-3.5">encoding
+ * transformation</a> is applied. For instance, <a href=
+ * "http://code.jquery.com/jquery-1.7.1.js">jQuery 1.7.1</a> takes 248235 bytes.
+ * Building it with <a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">
+ * UglifyJS v1.2.5</a> results in 93647 bytes (37.73% of the original) which are
+ * then compressed to 33154 bytes (13.36% of the original) using <a href=
+ * "http://linux.die.net/man/1/gzip">gzip(1)</a>. Building it with the same
+ * version of UglifyJS 1.2.5 patched with the implementation of consolidation
+ * results in 80784 bytes (a decrease of 12863 bytes, i.e. 13.74%, in comparison
+ * to the aforementioned 93647 bytes) which are then compressed to 34013 bytes
+ * (an increase of 859 bytes, i.e. 2.59%, in comparison to the aforementioned
+ * 33154 bytes).</p>
+ * <p>Written in <a href="http://es5.github.com/#x4.2.2">the strict variant</a>
+ * of <a href="http://es5.github.com/">ECMA-262 5.1 Edition</a>. Encoded in <a
+ * href="http://tools.ietf.org/html/rfc3629">UTF-8</a>. Follows <a href=
+ * "http://google-styleguide.googlecode.com/svn-history/r76/trunk/javascriptguide.xml"
+ * >Revision 2.28 of the Google JavaScript Style Guide</a> (except for the
+ * discouraged use of the {@code function} tag and the {@code namespace} tag).
+ * 100% typed for the <a href=
+ * "http://closure-compiler.googlecode.com/files/compiler-20120123.tar.gz"
+ * >Closure Compiler Version 1741</a>.</p>
+ * <p>Should you find this software useful, please consider <a href=
+ * "https://paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=JZLW72X8FD4WG"
+ * >a donation</a>.</p>
+ * @author follow.me@RGustBardon (Robert Gust-Bardon)
+ * @supported Tested with:
+ *     <ul>
+ *     <li><a href="http://nodejs.org/dist/v0.6.10/">Node v0.6.10</a>,</li>
+ *     <li><a href="https://github.com/mishoo/UglifyJS/tarball/v1.2.5">UglifyJS
+ *       v1.2.5</a>.</li>
+ *     </ul>
+ */
+
+/*global console:false, exports:true, module:false, require:false */
+/*jshint sub:true */
+/**
+ * Consolidates null, Boolean, and String values found inside an <abbr title=
+ * "abstract syntax tree">AST</abbr>.
+ * @param {!TSyntacticCodeUnit} oAbstractSyntaxTree An array-like object
+ *     representing an <abbr title="abstract syntax tree">AST</abbr>.
+ * @return {!TSyntacticCodeUnit} An array-like object representing an <abbr
+ *     title="abstract syntax tree">AST</abbr> with its null, Boolean, and
+ *     String values consolidated.
+ */
+// TODO(user) Consolidation of mathematical values found in numeric literals.
+// TODO(user) Unconsolidation.
+// TODO(user) Consolidation of ECMA-262 6th Edition programs.
+// TODO(user) Rewrite in ECMA-262 6th Edition.
+exports['ast_consolidate'] = function(oAbstractSyntaxTree) {
+  'use strict';
+  /*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:true,
+        latedef:true, newcap:true, noarge:true, noempty:true, nonew:true,
+        onevar:true, plusplus:true, regexp:true, undef:true, strict:true,
+        sub:false, trailing:true */
+
+  var _,
+      /**
+       * A record consisting of data about one or more source elements.
+       * @constructor
+       * @nosideeffects
+       */
+      TSourceElementsData = function() {
+        /**
+         * The category of the elements.
+         * @type {number}
+         * @see ESourceElementCategories
+         */
+        this.nCategory = ESourceElementCategories.N_OTHER;
+        /**
+         * The number of occurrences (within the elements) of each primitive
+         * value that could be consolidated.
+         * @type {!Array.<!Object.<string, number>>}
+         */
+        this.aCount = [];
+        this.aCount[EPrimaryExpressionCategories.N_IDENTIFIER_NAMES] = {};
+        this.aCount[EPrimaryExpressionCategories.N_STRING_LITERALS] = {};
+        this.aCount[EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS] =
+            {};
+        /**
+         * Identifier names found within the elements.
+         * @type {!Array.<string>}
+         */
+        this.aIdentifiers = [];
+        /**
+         * Prefixed representation Strings of each primitive value that could be
+         * consolidated within the elements.
+         * @type {!Array.<string>}
+         */
+        this.aPrimitiveValues = [];
+      },
+      /**
+       * A record consisting of data about a primitive value that could be
+       * consolidated.
+       * @constructor
+       * @nosideeffects
+       */
+      TPrimitiveValue = function() {
+        /**
+         * The difference in the number of terminal symbols between the original
+         * source text and the one with the primitive value consolidated. If the
+         * difference is positive, the primitive value is considered worthwhile.
+         * @type {number}
+         */
+        this.nSaving = 0;
+        /**
+         * An identifier name of the variable that will be declared and assigned
+         * the primitive value if the primitive value is consolidated.
+         * @type {string}
+         */
+        this.sName = '';
+      },
+      /**
+       * A record consisting of data on what to consolidate within the range of
+       * source elements that is currently being considered.
+       * @constructor
+       * @nosideeffects
+       */
+      TSolution = function() {
+        /**
+         * An object whose keys are prefixed representation Strings of each
+         * primitive value that could be consolidated within the elements and
+         * whose values are corresponding data about those primitive values.
+         * @type {!Object.<string, {nSaving: number, sName: string}>}
+         * @see TPrimitiveValue
+         */
+        this.oPrimitiveValues = {};
+        /**
+         * The difference in the number of terminal symbols between the original
+         * source text and the one with all the worthwhile primitive values
+         * consolidated.
+         * @type {number}
+         * @see TPrimitiveValue#nSaving
+         */
+        this.nSavings = 0;
+      },
+      /**
+       * The processor of <abbr title="abstract syntax tree">AST</abbr>s found
+       * in UglifyJS.
+       * @namespace
+       * @type {!TProcessor}
+       */
+      oProcessor = (/** @type {!TProcessor} */ require('./process')),
+      /**
+       * A record consisting of a number of constants that represent the
+       * difference in the number of terminal symbols between a source text with
+       * a modified syntactic code unit and the original one.
+       * @namespace
+       * @type {!Object.<string, number>}
+       */
+      oWeights = {
+        /**
+         * The difference in the number of punctuators required by the bracket
+         * notation and the dot notation.
+         * <p><code>'[]'.length - '.'.length</code></p>
+         * @const
+         * @type {number}
+         */
+        N_PROPERTY_ACCESSOR: 1,
+        /**
+         * The number of punctuators required by a variable declaration with an
+         * initialiser.
+         * <p><code>':'.length + ';'.length</code></p>
+         * @const
+         * @type {number}
+         */
+        N_VARIABLE_DECLARATION: 2,
+        /**
+         * The number of terminal symbols required to introduce a variable
+         * statement (excluding its variable declaration list).
+         * <p><code>'var '.length</code></p>
+         * @const
+         * @type {number}
+         */
+        N_VARIABLE_STATEMENT_AFFIXATION: 4,
+        /**
+         * The number of terminal symbols needed to enclose source elements
+         * within a function call with no argument values to a function with an
+         * empty parameter list.
+         * <p><code>'(function(){}());'.length</code></p>
+         * @const
+         * @type {number}
+         */
+        N_CLOSURE: 17
+      },
+      /**
+       * Categories of primary expressions from which primitive values that
+       * could be consolidated are derivable.
+       * @namespace
+       * @enum {number}
+       */
+      EPrimaryExpressionCategories = {
+        /**
+         * Identifier names used as property accessors.
+         * @type {number}
+         */
+        N_IDENTIFIER_NAMES: 0,
+        /**
+         * String literals.
+         * @type {number}
+         */
+        N_STRING_LITERALS: 1,
+        /**
+         * Null and Boolean literals.
+         * @type {number}
+         */
+        N_NULL_AND_BOOLEAN_LITERALS: 2
+      },
+      /**
+       * Prefixes of primitive values that could be consolidated.
+       * The String values of the prefixes must have same number of characters.
+       * The prefixes must not be used in any properties defined in any version
+       * of <a href=
+       * "http://www.ecma-international.org/publications/standards/Ecma-262.htm"
+       * >ECMA-262</a>.
+       * @namespace
+       * @enum {string}
+       */
+      EValuePrefixes = {
+        /**
+         * Identifies String values.
+         * @type {string}
+         */
+        S_STRING: '#S',
+        /**
+         * Identifies null and Boolean values.
+         * @type {string}
+         */
+        S_SYMBOLIC: '#O'
+      },
+      /**
+       * Categories of source elements in terms of their appropriateness of
+       * having their primitive values consolidated.
+       * @namespace
+       * @enum {number}
+       */
+      ESourceElementCategories = {
+        /**
+         * Identifies a source element that includes the <a href=
+         * "http://es5.github.com/#x12.10">{@code with}</a> statement.
+         * @type {number}
+         */
+        N_WITH: 0,
+        /**
+         * Identifies a source element that includes the <a href=
+         * "http://es5.github.com/#x15.1.2.1">{@code eval}</a> identifier name.
+         * @type {number}
+         */
+        N_EVAL: 1,
+        /**
+         * Identifies a source element that must be excluded from the process
+         * unless its whole scope is examined.
+         * @type {number}
+         */
+        N_EXCLUDABLE: 2,
+        /**
+         * Identifies source elements not posing any problems.
+         * @type {number}
+         */
+        N_OTHER: 3
+      },
+      /**
+       * The list of literals (other than the String ones) whose primitive
+       * values can be consolidated.
+       * @const
+       * @type {!Array.<string>}
+       */
+      A_OTHER_SUBSTITUTABLE_LITERALS = [
+        'null',   // The null literal.
+        'false',  // The Boolean literal {@code false}.
+        'true'    // The Boolean literal {@code true}.
+      ];
+
+  (/**
+    * Consolidates all worthwhile primitive values in a syntactic code unit.
+    * @param {!TSyntacticCodeUnit} oSyntacticCodeUnit An array-like object
+    *     representing the branch of the abstract syntax tree representing the
+    *     syntactic code unit along with its scope.
+    * @see TPrimitiveValue#nSaving
+    */
+   function fExamineSyntacticCodeUnit(oSyntacticCodeUnit) {
+     var _,
+         /**
+          * Indicates whether the syntactic code unit represents global code.
+          * @type {boolean}
+          */
+         bIsGlobal = 'toplevel' === oSyntacticCodeUnit[0],
+         /**
+          * Indicates whether the whole scope is being examined.
+          * @type {boolean}
+          */
+         bIsWhollyExaminable = !bIsGlobal,
+         /**
+          * An array-like object representing source elements that constitute a
+          * syntactic code unit.
+          * @type {!TSyntacticCodeUnit}
+          */
+         oSourceElements,
+         /**
+          * A record consisting of data about the source element that is
+          * currently being examined.
+          * @type {!TSourceElementsData}
+          */
+         oSourceElementData,
+         /**
+          * The scope of the syntactic code unit.
+          * @type {!TScope}
+          */
+         oScope,
+         /**
+          * An instance of an object that allows the traversal of an <abbr
+          * title="abstract syntax tree">AST</abbr>.
+          * @type {!TWalker}
+          */
+         oWalker,
+         /**
+          * An object encompassing collections of functions used during the
+          * traversal of an <abbr title="abstract syntax tree">AST</abbr>.
+          * @namespace
+          * @type {!Object.<string, !Object.<string, function(...[*])>>}
+          */
+         oWalkers = {
+           /**
+            * A collection of functions used during the surveyance of source
+            * elements.
+            * @namespace
+            * @type {!Object.<string, function(...[*])>}
+            */
+           oSurveySourceElement: {
+             /**#nocode+*/  // JsDoc Toolkit 2.4.0 hides some of the keys.
+             /**
+              * Classifies the source element as excludable if it does not
+              * contain a {@code with} statement or the {@code eval} identifier
+              * name. Adds the identifier of the function and its formal
+              * parameters to the list of identifier names found.
+              * @param {string} sIdentifier The identifier of the function.
+              * @param {!Array.<string>} aFormalParameterList Formal parameters.
+              * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
+              */
+             'defun': function(
+                 sIdentifier,
+                 aFormalParameterList,
+                 oFunctionBody) {
+               fClassifyAsExcludable();
+               fAddIdentifier(sIdentifier);
+               aFormalParameterList.forEach(fAddIdentifier);
+             },
+             /**
+              * Increments the count of the number of occurrences of the String
+              * value that is equivalent to the sequence of terminal symbols
+              * that constitute the encountered identifier name.
+              * @param {!TSyntacticCodeUnit} oExpression The nonterminal
+              *     MemberExpression.
+              * @param {string} sIdentifierName The identifier name used as the
+              *     property accessor.
+              * @return {!Array} The encountered branch of an <abbr title=
+              *     "abstract syntax tree">AST</abbr> with its nonterminal
+              *     MemberExpression traversed.
+              */
+             'dot': function(oExpression, sIdentifierName) {
+               fCountPrimaryExpression(
+                   EPrimaryExpressionCategories.N_IDENTIFIER_NAMES,
+                   EValuePrefixes.S_STRING + sIdentifierName);
+               return ['dot', oWalker.walk(oExpression), sIdentifierName];
+             },
+             /**
+              * Adds the optional identifier of the function and its formal
+              * parameters to the list of identifier names found.
+              * @param {?string} sIdentifier The optional identifier of the
+              *     function.
+              * @param {!Array.<string>} aFormalParameterList Formal parameters.
+              * @param {!TSyntacticCodeUnit} oFunctionBody Function code.
+              */
+             'function': function(
+                 sIdentifier,
+                 aFormalParameterList,
+                 oFunctionBody) {
+               if ('string' === typeof sIdentifier) {
+                 fAddIdentifier(sIdentifier);
+               }
+               aFormalParameterList.forEach(fAddIdentifier);
+             },
+             /**
+              * Either increments the count of the number of occurrences of the
+              * encountered null or Boolean value or classifies a source element
+              * as containing the {@code eval} identifier name.
+              * @param {string} sIdentifier The identifier encountered.
+              */
+             'name': function(sIdentifier) {
+               if (-1 !== A_OTHER_SUBSTITUTABLE_LITERALS.indexOf(sIdentifier)) {
+                 fCountPrimaryExpression(
+                     EPrimaryExpressionCategories.N_NULL_AND_BOOLEAN_LITERALS,
+                     EValuePrefixes.S_SYMBOLIC + sIdentifier);
+               } else {
+                 if ('eval' === sIdentifier) {
+                   oSourceElementData.nCategory =
+                       ESourceElementCategories.N_EVAL;
+                 }
+                 fAddIdentifier(sIdentifier);
+               }
+             },
+             /**
+              * Classifies the source element as excludable if it does not
+              * contain a {@code with} statement or the {@code eval} identifier
+              * name.
+              * @param {TSyntacticCodeUnit} oExpression The expression whose
+              *     value is to be returned.
+              */
+             'return': function(oExpression) {
+               fClassifyAsExcludable();
+             },
+             /**
+              * Increments the count of the number of occurrences of the
+              * encountered String value.
+              * @param {string} sStringValue The String value of the string
+              *     literal encountered.
+              */
+             'string': function(sStringValue) {
+               if (sStringValue.length > 0) {
+                 fCountPrimaryExpression(
+                     EPrimaryExpressionCategories.N_STRING_LITERALS,
+                     EValuePrefixes.S_STRING + sStringValue);
+               }
+             },
+             /**
+              * Adds the identifier reserved for an exception to the list of
+              * identifier names found.
+              * @param {!TSyntacticCodeUnit} oTry A block of code in which an
+              *     exception can occur.
+              * @param {Array} aCatch The identifier reserved for an exception
+              *     and a block of code to handle the exception.
+              * @param {TSyntacticCodeUnit} oFinally An optional block of code
+              *     to be evaluated regardless of whether an exception occurs.
+              */
+             'try': function(oTry, aCatch, oFinally) {
+               if (Array.isArray(aCatch)) {
+                 fAddIdentifier(aCatch[0]);
+               }
+             },
+             /**
+              * Classifies the source element as excludable if it does not
+              * contain a {@code with} statement or the {@code eval} identifier
+              * name. Adds the identifier of each declared variable to the list
+              * of identifier names found.
+              * @param {!Array.<!Array>} aVariableDeclarationList Variable
+              *     declarations.
+              */
+             'var': function(aVariableDeclarationList) {
+               fClassifyAsExcludable();
+               aVariableDeclarationList.forEach(fAddVariable);
+             },
+             /**
+              * Classifies a source element as containing the {@code with}
+              * statement.
+              * @param {!TSyntacticCodeUnit} oExpression An expression whose
+              *     value is to be converted to a value of type Object and
+              *     become the binding object of a new object environment
+              *     record of a new lexical environment in which the statement
+              *     is to be executed.
+              * @param {!TSyntacticCodeUnit} oStatement The statement to be
+              *     executed in the augmented lexical environment.
+              * @return {!Array} An empty array to stop the traversal.
+              */
+             'with': function(oExpression, oStatement) {
+               oSourceElementData.nCategory = ESourceElementCategories.N_WITH;
+               return [];
+             }
+             /**#nocode-*/  // JsDoc Toolkit 2.4.0 hides some of the keys.
+           },
+           /**
+            * A collection of functions used while looking for nested functions.
+            * @namespace
+            * @type {!Object.<string, function(...[*])>}
+            */
+           oExamineFunctions: {
+             /**#nocode+*/  // JsDoc Toolkit 2.4.0 hides some of the keys.
+             /**
+              * Orders an examination of a nested function declaration.
+              * @this {!TSyntacticCodeUnit} An array-like object representing
+              *     the branch of an <abbr title="abstract syntax tree"
+              *     >AST</abbr> representing the syntactic code unit along with
+              *     its scope.
+              * @return {!Array} An empty array to stop the traversal.
+              */
+             'defun': function() {
+               fExamineSyntacticCodeUnit(this);
+               return [];
+             },
+             /**
+              * Orders an examination of a nested function expression.
+              * @this {!TSyntacticCodeUnit} An array-like object representing
+              *     the branch of an <abbr title="abstract syntax tree"
+              *     >AST</abbr> representing the syntactic code unit along with
+              *     its scope.
+              * @return {!Array} An empty array to stop the traversal.
+              */
+             'function': function() {
+               fExamineSyntacticCodeUnit(this);
+               return [];
+             }
+             /**#nocode-*/  // JsDoc Toolkit 2.4.0 hides some of the keys.
+           }
+         },
+         /**
+          * Records containing data about source elements.
+          * @type {Array.<TSourceElementsData>}
+          */
+         aSourceElementsData = [],
+         /**
+          * The index (in the source text order) of the source element
+          * immediately following a <a href="http://es5.github.com/#x14.1"
+          * >Directive Prologue</a>.
+          * @type {number}
+          */
+         nAfterDirectivePrologue = 0,
+         /**
+          * The index (in the source text order) of the source element that is
+          * currently being considered.
+          * @type {number}
+          */
+         nPosition,
+         /**
+          * The index (in the source text order) of the source element that is
+          * the last element of the range of source elements that is currently
+          * being considered.
+          * @type {(undefined|number)}
+          */
+         nTo,
+         /**
+          * Initiates the traversal of a source element.
+          * @param {!TWalker} oWalker An instance of an object that allows the
+          *     traversal of an abstract syntax tree.
+          * @param {!TSyntacticCodeUnit} oSourceElement A source element from
+          *     which the traversal should commence.
+          * @return {function(): !TSyntacticCodeUnit} A function that is able to
+          *     initiate the traversal from a given source element.
+          */
+         cContext = function(oWalker, oSourceElement) {
+           /**
+            * @return {!TSyntacticCodeUnit} A function that is able to
+            *     initiate the traversal from a given source element.
+            */
+           var fLambda = function() {
+             return oWalker.walk(oSourceElement);
+           };
+
+           return fLambda;
+         },
+         /**
+          * Classifies the source element as excludable if it does not
+          * contain a {@code with} statement or the {@code eval} identifier
+          * name.
+          */
+         fClassifyAsExcludable = function() {
+           if (oSourceElementData.nCategory ===
+               ESourceElementCategories.N_OTHER) {
+             oSourceElementData.nCategory =
+                 ESourceElementCategories.N_EXCLUDABLE;
+           }
+         },
+         /**
+          * Adds an identifier to the list of identifier names found.
+          * @param {string} sIdentifier The identifier to be added.
+          */
+         fAddIdentifier = function(sIdentifier) {
+           if (-1 === oSourceElementData.aIdentifiers.indexOf(sIdentifier)) {
+             oSourceElementData.aIdentifiers.push(sIdentifier);
+           }
+         },
+         /**
+          * Adds the identifier of a variable to the list of identifier names
+          * found.
+          * @param {!Array} aVariableDeclaration A variable declaration.
+          */
+         fAddVariable = function(aVariableDeclaration) {
+           fAddIdentifier(/** @type {string} */ aVariableDeclaration[0]);
+         },
+         /**
+          * Increments the count of the number of occurrences of the prefixed
+          * String representation attributed to the primary expression.
+          * @param {number} nCategory The category of the primary expression.
+          * @param {string} sName The prefixed String representation attributed
+          *     to the primary expression.
+          */
+         fCountPrimaryExpression = function(nCategory, sName) {
+           if (!oSourceElementData.aCount[nCategory].hasOwnProperty(sName)) {
+             oSourceElementData.aCount[nCategory][sName] = 0;
+             if (-1 === oSourceElementData.aPrimitiveValues.indexOf(sName)) {
+               oSourceElementData.aPrimitiveValues.push(sName);
+             }
+           }
+           oSourceElementData.aCount[nCategory][sName] += 1;
+         },
+         /**
+          * Consolidates all worthwhile primitive values in a range of source
+          *     elements.
+          * @param {number} nFrom The index (in the source text order) of the
+          *     source element that is the first element of the range.
+          * @param {number} nTo The index (in the source text order) of the
+          *     source element that is the last element of the range.
+          * @param {boolean} bEnclose Indicates whether the range should be
+          *     enclosed within a function call with no argument values to a
+          *     function with an empty parameter list if any primitive values
+          *     are consolidated.
+          * @see TPrimitiveValue#nSaving
+          */
+         fExamineSourceElements = function(nFrom, nTo, bEnclose) {
+           var _,
+               /**
+                * The index of the last mangled name.
+                * @type {number}
+                */
+               nIndex = oScope.cname,
+               /**
+                * The index of the source element that is currently being
+                * considered.
+                * @type {number}
+                */
+               nPosition,
+               /**
+                * A collection of functions used during the consolidation of
+                * primitive values and identifier names used as property
+                * accessors.
+                * @namespace
+                * @type {!Object.<string, function(...[*])>}
+                */
+               oWalkersTransformers = {
+                 /**
+                  * If the String value that is equivalent to the sequence of
+                  * terminal symbols that constitute the encountered identifier
+                  * name is worthwhile, a syntactic conversion from the dot
+                  * notation to the bracket notation ensues with that sequence
+                  * being substituted by an identifier name to which the value
+                  * is assigned.
+                  * Applies to property accessors that use the dot notation.
+                  * @param {!TSyntacticCodeUnit} oExpression The nonterminal
+                  *     MemberExpression.
+                  * @param {string} sIdentifierName The identifier name used as
+                  *     the property accessor.
+                  * @return {!Array} A syntactic code unit that is equivalent to
+                  *     the one encountered.
+                  * @see TPrimitiveValue#nSaving
+                  */
+                 'dot': function(oExpression, sIdentifierName) {
+                   /**
+                    * The prefixed String value that is equivalent to the
+                    * sequence of terminal symbols that constitute the
+                    * encountered identifier name.
+                    * @type {string}
+                    */
+                   var sPrefixed = EValuePrefixes.S_STRING + sIdentifierName;
+
+                   return oSolutionBest.oPrimitiveValues.hasOwnProperty(
+                       sPrefixed) &&
+                       oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
+                       ['sub',
+                        oWalker.walk(oExpression),
+                        ['name',
+                         oSolutionBest.oPrimitiveValues[sPrefixed].sName]] :
+                       ['dot', oWalker.walk(oExpression), sIdentifierName];
+                 },
+                 /**
+                  * If the encountered identifier is a null or Boolean literal
+                  * and its value is worthwhile, the identifier is substituted
+                  * by an identifier name to which that value is assigned.
+                  * Applies to identifier names.
+                  * @param {string} sIdentifier The identifier encountered.
+                  * @return {!Array} A syntactic code unit that is equivalent to
+                  *     the one encountered.
+                  * @see TPrimitiveValue#nSaving
+                  */
+                 'name': function(sIdentifier) {
+                   /**
+                    * The prefixed representation String of the identifier.
+                    * @type {string}
+                    */
+                   var sPrefixed = EValuePrefixes.S_SYMBOLIC + sIdentifier;
+
+                   return [
+                     'name',
+                     oSolutionBest.oPrimitiveValues.hasOwnProperty(sPrefixed) &&
+                     oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
+                     oSolutionBest.oPrimitiveValues[sPrefixed].sName :
+                     sIdentifier
+                   ];
+                 },
+                 /**
+                  * If the encountered String value is worthwhile, it is
+                  * substituted by an identifier name to which that value is
+                  * assigned.
+                  * Applies to String values.
+                  * @param {string} sStringValue The String value of the string
+                  *     literal encountered.
+                  * @return {!Array} A syntactic code unit that is equivalent to
+                  *     the one encountered.
+                  * @see TPrimitiveValue#nSaving
+                  */
+                 'string': function(sStringValue) {
+                   /**
+                    * The prefixed representation String of the primitive value
+                    * of the literal.
+                    * @type {string}
+                    */
+                   var sPrefixed =
+                       EValuePrefixes.S_STRING + sStringValue;
+
+                   return oSolutionBest.oPrimitiveValues.hasOwnProperty(
+                       sPrefixed) &&
+                       oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0 ?
+                       ['name',
+                        oSolutionBest.oPrimitiveValues[sPrefixed].sName] :
+                       ['string', sStringValue];
+                 }
+               },
+               /**
+                * Such data on what to consolidate within the range of source
+                * elements that is currently being considered that lead to the
+                * greatest known reduction of the number of the terminal symbols
+                * in comparison to the original source text.
+                * @type {!TSolution}
+                */
+               oSolutionBest = new TSolution(),
+               /**
+                * Data representing an ongoing attempt to find a better
+                * reduction of the number of the terminal symbols in comparison
+                * to the original source text than the best one that is
+                * currently known.
+                * @type {!TSolution}
+                * @see oSolutionBest
+                */
+               oSolutionCandidate = new TSolution(),
+               /**
+                * A record consisting of data about the range of source elements
+                * that is currently being examined.
+                * @type {!TSourceElementsData}
+                */
+               oSourceElementsData = new TSourceElementsData(),
+               /**
+                * Variable declarations for each primitive value that is to be
+                * consolidated within the elements.
+                * @type {!Array.<!Array>}
+                */
+               aVariableDeclarations = [],
+               /**
+                * Augments a list with a prefixed representation String.
+                * @param {!Array.<string>} aList A list that is to be augmented.
+                * @return {function(string)} A function that augments a list
+                *     with a prefixed representation String.
+                */
+               cAugmentList = function(aList) {
+                 /**
+                  * @param {string} sPrefixed Prefixed representation String of
+                  *     a primitive value that could be consolidated within the
+                  *     elements.
+                  */
+                 var fLambda = function(sPrefixed) {
+                   if (-1 === aList.indexOf(sPrefixed)) {
+                     aList.push(sPrefixed);
+                   }
+                 };
+
+                 return fLambda;
+               },
+               /**
+                * Adds the number of occurrences of a primitive value of a given
+                * category that could be consolidated in the source element with
+                * a given index to the count of occurrences of that primitive
+                * value within the range of source elements that is currently
+                * being considered.
+                * @param {number} nPosition The index (in the source text order)
+                *     of a source element.
+                * @param {number} nCategory The category of the primary
+                *     expression from which the primitive value is derived.
+                * @return {function(string)} A function that performs the
+                *     addition.
+                * @see cAddOccurrencesInCategory
+                */
+               cAddOccurrences = function(nPosition, nCategory) {
+                 /**
+                  * @param {string} sPrefixed The prefixed representation String
+                  *     of a primitive value.
+                  */
+                 var fLambda = function(sPrefixed) {
+                   if (!oSourceElementsData.aCount[nCategory].hasOwnProperty(
+                           sPrefixed)) {
+                     oSourceElementsData.aCount[nCategory][sPrefixed] = 0;
+                   }
+                   oSourceElementsData.aCount[nCategory][sPrefixed] +=
+                       aSourceElementsData[nPosition].aCount[nCategory][
+                           sPrefixed];
+                 };
+
+                 return fLambda;
+               },
+               /**
+                * Adds the number of occurrences of each primitive value of a
+                * given category that could be consolidated in the source
+                * element with a given index to the count of occurrences of that
+                * primitive values within the range of source elements that is
+                * currently being considered.
+                * @param {number} nPosition The index (in the source text order)
+                *     of a source element.
+                * @return {function(number)} A function that performs the
+                *     addition.
+                * @see fAddOccurrences
+                */
+               cAddOccurrencesInCategory = function(nPosition) {
+                 /**
+                  * @param {number} nCategory The category of the primary
+                  *     expression from which the primitive value is derived.
+                  */
+                 var fLambda = function(nCategory) {
+                   Object.keys(
+                       aSourceElementsData[nPosition].aCount[nCategory]
+                   ).forEach(cAddOccurrences(nPosition, nCategory));
+                 };
+
+                 return fLambda;
+               },
+               /**
+                * Adds the number of occurrences of each primitive value that
+                * could be consolidated in the source element with a given index
+                * to the count of occurrences of that primitive values within
+                * the range of source elements that is currently being
+                * considered.
+                * @param {number} nPosition The index (in the source text order)
+                *     of a source element.
+                */
+               fAddOccurrences = function(nPosition) {
+                 Object.keys(aSourceElementsData[nPosition].aCount).forEach(
+                     cAddOccurrencesInCategory(nPosition));
+               },
+               /**
+                * Creates a variable declaration for a primitive value if that
+                * primitive value is to be consolidated within the elements.
+                * @param {string} sPrefixed Prefixed representation String of a
+                *     primitive value that could be consolidated within the
+                *     elements.
+                * @see aVariableDeclarations
+                */
+               cAugmentVariableDeclarations = function(sPrefixed) {
+                 if (oSolutionBest.oPrimitiveValues[sPrefixed].nSaving > 0) {
+                   aVariableDeclarations.push([
+                     oSolutionBest.oPrimitiveValues[sPrefixed].sName,
+                     [0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC) ?
+                      'name' : 'string',
+                      sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length)]
+                   ]);
+                 }
+               },
+               /**
+                * Sorts primitive values with regard to the difference in the
+                * number of terminal symbols between the original source text
+                * and the one with those primitive values consolidated.
+                * @param {string} sPrefixed0 The prefixed representation String
+                *     of the first of the two primitive values that are being
+                *     compared.
+                * @param {string} sPrefixed1 The prefixed representation String
+                *     of the second of the two primitive values that are being
+                *     compared.
+                * @return {number}
+                *     <dl>
+                *         <dt>-1</dt>
+                *         <dd>if the first primitive value must be placed before
+                *              the other one,</dd>
+                *         <dt>0</dt>
+                *         <dd>if the first primitive value may be placed before
+                *              the other one,</dd>
+                *         <dt>1</dt>
+                *         <dd>if the first primitive value must not be placed
+                *              before the other one.</dd>
+                *     </dl>
+                * @see TSolution.oPrimitiveValues
+                */
+               cSortPrimitiveValues = function(sPrefixed0, sPrefixed1) {
+                 /**
+                  * The difference between:
+                  * <ol>
+                  * <li>the difference in the number of terminal symbols
+                  *     between the original source text and the one with the
+                  *     first primitive value consolidated, and</li>
+                  * <li>the difference in the number of terminal symbols
+                  *     between the original source text and the one with the
+                  *     second primitive value consolidated.</li>
+                  * </ol>
+                  * @type {number}
+                  */
+                 var nDifference =
+                     oSolutionCandidate.oPrimitiveValues[sPrefixed0].nSaving -
+                     oSolutionCandidate.oPrimitiveValues[sPrefixed1].nSaving;
+
+                 return nDifference > 0 ? -1 : nDifference < 0 ? 1 : 0;
+               },
+               /**
+                * Assigns an identifier name to a primitive value and calculates
+                * whether instances of that primitive value are worth
+                * consolidating.
+                * @param {string} sPrefixed The prefixed representation String
+                *     of a primitive value that is being evaluated.
+                */
+               fEvaluatePrimitiveValue = function(sPrefixed) {
+                 var _,
+                     /**
+                      * The index of the last mangled name.
+                      * @type {number}
+                      */
+                     nIndex,
+                     /**
+                      * The representation String of the primitive value that is
+                      * being evaluated.
+                      * @type {string}
+                      */
+                     sName =
+                         sPrefixed.substring(EValuePrefixes.S_SYMBOLIC.length),
+                     /**
+                      * The number of source characters taken up by the
+                      * representation String of the primitive value that is
+                      * being evaluated.
+                      * @type {number}
+                      */
+                     nLengthOriginal = sName.length,
+                     /**
+                      * The number of source characters taken up by the
+                      * identifier name that could substitute the primitive
+                      * value that is being evaluated.
+                      * substituted.
+                      * @type {number}
+                      */
+                     nLengthSubstitution,
+                     /**
+                      * The number of source characters taken up by by the
+                      * representation String of the primitive value that is
+                      * being evaluated when it is represented by a string
+                      * literal.
+                      * @type {number}
+                      */
+                     nLengthString = oProcessor.make_string(sName).length;
+
+                 oSolutionCandidate.oPrimitiveValues[sPrefixed] =
+                     new TPrimitiveValue();
+                 do {  // Find an identifier unused in this or any nested scope.
+                   nIndex = oScope.cname;
+                   oSolutionCandidate.oPrimitiveValues[sPrefixed].sName =
+                       oScope.next_mangled();
+                 } while (-1 !== oSourceElementsData.aIdentifiers.indexOf(
+                     oSolutionCandidate.oPrimitiveValues[sPrefixed].sName));
+                 nLengthSubstitution = oSolutionCandidate.oPrimitiveValues[
+                     sPrefixed].sName.length;
+                 if (0 === sPrefixed.indexOf(EValuePrefixes.S_SYMBOLIC)) {
+                   // foo:null, or foo:null;
+                   oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
+                       nLengthSubstitution + nLengthOriginal +
+                       oWeights.N_VARIABLE_DECLARATION;
+                   // null vs foo
+                   oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
+                       oSourceElementsData.aCount[
+                           EPrimaryExpressionCategories.
+                               N_NULL_AND_BOOLEAN_LITERALS][sPrefixed] *
+                       (nLengthOriginal - nLengthSubstitution);
+                 } else {
+                   // foo:'fromCharCode';
+                   oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving -=
+                       nLengthSubstitution + nLengthString +
+                       oWeights.N_VARIABLE_DECLARATION;
+                   // .fromCharCode vs [foo]
+                   if (oSourceElementsData.aCount[
+                           EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
+                       ].hasOwnProperty(sPrefixed)) {
+                     oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
+                         oSourceElementsData.aCount[
+                             EPrimaryExpressionCategories.N_IDENTIFIER_NAMES
+                         ][sPrefixed] *
+                         (nLengthOriginal - nLengthSubstitution -
+                          oWeights.N_PROPERTY_ACCESSOR);
+                   }
+                   // 'fromCharCode' vs foo
+                   if (oSourceElementsData.aCount[
+                           EPrimaryExpressionCategories.N_STRING_LITERALS
+                       ].hasOwnProperty(sPrefixed)) {
+                     oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving +=
+                         oSourceElementsData.aCount[
+                             EPrimaryExpressionCategories.N_STRING_LITERALS
+                         ][sPrefixed] *
+                         (nLengthString - nLengthSubstitution);
+                   }
+                 }
+                 if (oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving >
+                     0) {
+                   oSolutionCandidate.nSavings +=
+                       oSolutionCandidate.oPrimitiveValues[sPrefixed].nSaving;
+                 } else {
+                   oScope.cname = nIndex; // Free the identifier name.
+                 }
+               },
+               /**
+                * Adds a variable declaration to an existing variable statement.
+                * @param {!Array} aVariableDeclaration A variable declaration
+                *     with an initialiser.
+                */
+               cAddVariableDeclaration = function(aVariableDeclaration) {
+                 (/** @type {!Array} */ oSourceElements[nFrom][1]).unshift(
+                     aVariableDeclaration);
+               };
+
+           if (nFrom > nTo) {
+             return;
+           }
+           // If the range is a closure, reuse the closure.
+           if (nFrom === nTo &&
+               'stat' === oSourceElements[nFrom][0] &&
+               'call' === oSourceElements[nFrom][1][0] &&
+               'function' === oSourceElements[nFrom][1][1][0]) {
+             fExamineSyntacticCodeUnit(oSourceElements[nFrom][1][1]);
+             return;
+           }
+           // Create a list of all derived primitive values within the range.
+           for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
+             aSourceElementsData[nPosition].aPrimitiveValues.forEach(
+                 cAugmentList(oSourceElementsData.aPrimitiveValues));
+           }
+           if (0 === oSourceElementsData.aPrimitiveValues.length) {
+             return;
+           }
+           for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
+             // Add the number of occurrences to the total count.
+             fAddOccurrences(nPosition);
+             // Add identifiers of this or any nested scope to the list.
+             aSourceElementsData[nPosition].aIdentifiers.forEach(
+                 cAugmentList(oSourceElementsData.aIdentifiers));
+           }
+           // Distribute identifier names among derived primitive values.
+           do {  // If there was any progress, find a better distribution.
+             oSolutionBest = oSolutionCandidate;
+             if (Object.keys(oSolutionCandidate.oPrimitiveValues).length > 0) {
+               // Sort primitive values descending by their worthwhileness.
+               oSourceElementsData.aPrimitiveValues.sort(cSortPrimitiveValues);
+             }
+             oSolutionCandidate = new TSolution();
+             oSourceElementsData.aPrimitiveValues.forEach(
+                 fEvaluatePrimitiveValue);
+             oScope.cname = nIndex;
+           } while (oSolutionCandidate.nSavings > oSolutionBest.nSavings);
+           // Take the necessity of adding a variable statement into account.
+           if ('var' !== oSourceElements[nFrom][0]) {
+             oSolutionBest.nSavings -= oWeights.N_VARIABLE_STATEMENT_AFFIXATION;
+           }
+           if (bEnclose) {
+             // Take the necessity of forming a closure into account.
+             oSolutionBest.nSavings -= oWeights.N_CLOSURE;
+           }
+           if (oSolutionBest.nSavings > 0) {
+             // Create variable declarations suitable for UglifyJS.
+             Object.keys(oSolutionBest.oPrimitiveValues).forEach(
+                 cAugmentVariableDeclarations);
+             // Rewrite expressions that contain worthwhile primitive values.
+             for (nPosition = nFrom; nPosition <= nTo; nPosition += 1) {
+               oWalker = oProcessor.ast_walker();
+               oSourceElements[nPosition] =
+                   oWalker.with_walkers(
+                       oWalkersTransformers,
+                       cContext(oWalker, oSourceElements[nPosition]));
+             }
+             if ('var' === oSourceElements[nFrom][0]) {  // Reuse the statement.
+               (/** @type {!Array.<!Array>} */ aVariableDeclarations.reverse(
+                   )).forEach(cAddVariableDeclaration);
+             } else {  // Add a variable statement.
+               Array.prototype.splice.call(
+                   oSourceElements,
+                   nFrom,
+                   0,
+                   ['var', aVariableDeclarations]);
+               nTo += 1;
+             }
+             if (bEnclose) {
+               // Add a closure.
+               Array.prototype.splice.call(
+                   oSourceElements,
+                   nFrom,
+                   0,
+                   ['stat', ['call', ['function', null, [], []], []]]);
+               // Copy source elements into the closure.
+               for (nPosition = nTo + 1; nPosition > nFrom; nPosition -= 1) {
+                 Array.prototype.unshift.call(
+                     oSourceElements[nFrom][1][1][3],
+                     oSourceElements[nPosition]);
+               }
+               // Remove source elements outside the closure.
+               Array.prototype.splice.call(
+                   oSourceElements,
+                   nFrom + 1,
+                   nTo - nFrom + 1);
+             }
+           }
+           if (bEnclose) {
+             // Restore the availability of identifier names.
+             oScope.cname = nIndex;
+           }
+         };
+
+     oSourceElements = (/** @type {!TSyntacticCodeUnit} */
+         oSyntacticCodeUnit[bIsGlobal ? 1 : 3]);
+     if (0 === oSourceElements.length) {
+       return;
+     }
+     oScope = bIsGlobal ? oSyntacticCodeUnit.scope : oSourceElements.scope;
+     // Skip a Directive Prologue.
+     while (nAfterDirectivePrologue < oSourceElements.length &&
+            'directive' === oSourceElements[nAfterDirectivePrologue][0]) {
+       nAfterDirectivePrologue += 1;
+       aSourceElementsData.push(null);
+     }
+     if (oSourceElements.length === nAfterDirectivePrologue) {
+       return;
+     }
+     for (nPosition = nAfterDirectivePrologue;
+          nPosition < oSourceElements.length;
+          nPosition += 1) {
+       oSourceElementData = new TSourceElementsData();
+       oWalker = oProcessor.ast_walker();
+       // Classify a source element.
+       // Find its derived primitive values and count their occurrences.
+       // Find all identifiers used (including nested scopes).
+       oWalker.with_walkers(
+           oWalkers.oSurveySourceElement,
+           cContext(oWalker, oSourceElements[nPosition]));
+       // Establish whether the scope is still wholly examinable.
+       bIsWhollyExaminable = bIsWhollyExaminable &&
+           ESourceElementCategories.N_WITH !== oSourceElementData.nCategory &&
+           ESourceElementCategories.N_EVAL !== oSourceElementData.nCategory;
+       aSourceElementsData.push(oSourceElementData);
+     }
+     if (bIsWhollyExaminable) {  // Examine the whole scope.
+       fExamineSourceElements(
+           nAfterDirectivePrologue,
+           oSourceElements.length - 1,
+           false);
+     } else {  // Examine unexcluded ranges of source elements.
+       for (nPosition = oSourceElements.length - 1;
+            nPosition >= nAfterDirectivePrologue;
+            nPosition -= 1) {
+         oSourceElementData = (/** @type {!TSourceElementsData} */
+             aSourceElementsData[nPosition]);
+         if (ESourceElementCategories.N_OTHER ===
+             oSourceElementData.nCategory) {
+           if ('undefined' === typeof nTo) {
+             nTo = nPosition;  // Indicate the end of a range.
+           }
+           // Examine the range if it immediately follows a Directive Prologue.
+           if (nPosition === nAfterDirectivePrologue) {
+             fExamineSourceElements(nPosition, nTo, true);
+           }
+         } else {
+           if ('undefined' !== typeof nTo) {
+             // Examine the range that immediately follows this source element.
+             fExamineSourceElements(nPosition + 1, nTo, true);
+             nTo = void 0;  // Obliterate the range.
+           }
+           // Examine nested functions.
+           oWalker = oProcessor.ast_walker();
+           oWalker.with_walkers(
+               oWalkers.oExamineFunctions,
+               cContext(oWalker, oSourceElements[nPosition]));
+         }
+       }
+     }
+   }(oAbstractSyntaxTree = oProcessor.ast_add_scope(oAbstractSyntaxTree)));
+  return oAbstractSyntaxTree;
+};
+/*jshint sub:false */
+
+/* Local Variables:      */
+/* mode: js              */
+/* coding: utf-8         */
+/* indent-tabs-mode: nil */
+/* tab-width: 2          */
+/* End:                  */
+/* vim: set ft=javascript fenc=utf-8 et ts=2 sts=2 sw=2: */
+/* :mode=javascript:noTabs=true:tabSize=2:indentSize=2:deepIndent=true: */
+});
+define('uglifyjs/parse-js', ["exports"], function(exports) {
 /***********************************************************************
 
   A JavaScript tokenizer / parser / beautifier / compressor.
@@ -3074,6 +8162,7 @@
         "catch",
         "const",
         "continue",
+        "debugger",
         "default",
         "delete",
         "do",
@@ -3102,7 +8191,6 @@
         "byte",
         "char",
         "class",
-        "debugger",
         "double",
         "enum",
         "export",
@@ -3200,7 +8288,7 @@
 
 var WHITESPACE_CHARS = array_to_hash(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
 
-var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:"));
+var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{(,.;:"));
 
 var PUNC_CHARS = array_to_hash(characters("[]{}(),;:"));
 
@@ -3208,12 +8296,11 @@
 
 /* -----[ Tokenizer ]----- */
 
-// regexps adapted from http://xregexp.com/plugins/#unicode
-var UNICODE = {
-        letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
-        non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
-        space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
-        connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
+var UNICODE = {  // Unicode 6.1
+        letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0\\u08A2-\\u08AC\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F0\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA697\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA793\\uA7A0-\\uA7AA\\uA7F8-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA80-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
+        combining_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0859-\\u085B\\u08E4-\\u08FE\\u0900-\\u0903\\u093A-\\u093C\\u093E-\\u094F\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09BC\\u09BE-\\u09C4\\u09C7\\u09C8\\u09CB-\\u09CD\\u09D7\\u09E2\\u09E3\\u0A01-\\u0A03\\u0A3C\\u0A3E-\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81-\\u0A83\\u0ABC\\u0ABE-\\u0AC5\\u0AC7-\\u0AC9\\u0ACB-\\u0ACD\\u0AE2\\u0AE3\\u0B01-\\u0B03\\u0B3C\\u0B3E-\\u0B44\\u0B47\\u0B48\\u0B4B-\\u0B4D\\u0B56\\u0B57\\u0B62\\u0B63\\u0B82\\u0BBE-\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCD\\u0BD7\\u0C01-\\u0C03\\u0C3E-\\u0C44\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0C82\\u0C83\\u0CBC\\u0CBE-\\u0CC4\\u0CC6-\\u0CC8\\u0CCA-\\u0CCD\\u0CD5\\u0CD6\\u0CE2\\u0CE3\\u0D02\\u0D03\\u0D3E-\\u0D44\\u0D46-\\u0D48\\u0D4A-\\u0D4D\\u0D57\\u0D62\\u0D63\\u0D82\\u0D83\\u0DCA\\u0DCF-\\u0DD4\\u0DD6\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F3E\\u0F3F\\u0F71-\\u0F84\\u0F86\\u0F87\\u0F8D-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102B-\\u103E\\u1056-\\u1059\\u105E-\\u1060\\u1062-\\u1064\\u1067-\\u106D\\u1071-\\u1074\\u1082-\\u108D\\u108F\\u109A-\\u109D\\u135D-\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B4-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u192B\\u1930-\\u193B\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A17-\\u1A1B\\u1A55-\\u1A5E\\u1A60-\\u1A7C\\u1A7F\\u1B00-\\u1B04\\u1B34-\\u1B44\\u1B6B-\\u1B73\\u1B80-\\u1B82\\u1BA1-\\u1BAD\\u1BE6-\\u1BF3\\u1C24-\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE8\\u1CED\\u1CF2-\\u1CF4\\u1DC0-\\u1DE6\\u1DFC-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2D7F\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA674-\\uA67D\\uA69F\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA823-\\uA827\\uA880\\uA881\\uA8B4-\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA953\\uA980-\\uA983\\uA9B3-\\uA9C0\\uAA29-\\uAA36\\uAA43\\uAA4C\\uAA4D\\uAA7B\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uAAEB-\\uAAEF\\uAAF5\\uAAF6\\uABE3-\\uABEA\\uABEC\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
+        connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]"),
+        digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]")
 };
 
 function is_letter(ch) {
@@ -3222,15 +8309,19 @@
 
 function is_digit(ch) {
         ch = ch.charCodeAt(0);
-        return ch >= 48 && ch <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
+        return ch >= 48 && ch <= 57;
 };
+
+function is_unicode_digit(ch) {
+        return UNICODE.digit.test(ch);
+}
 
 function is_alphanumeric_char(ch) {
         return is_digit(ch) || is_letter(ch);
 };
 
 function is_unicode_combining_mark(ch) {
-        return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
+        return UNICODE.combining_mark.test(ch);
 };
 
 function is_unicode_connector_punctuation(ch) {
@@ -3244,7 +8335,7 @@
 function is_identifier_char(ch) {
         return is_identifier_start(ch)
                 || is_unicode_combining_mark(ch)
-                || is_digit(ch)
+                || is_unicode_digit(ch)
                 || is_unicode_connector_punctuation(ch)
                 || ch == "\u200c" // zero-width non-joiner <ZWNJ>
                 || ch == "\u200d" // zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
@@ -3263,9 +8354,9 @@
 
 function JS_Parse_Error(message, line, col, pos) {
         this.message = message;
-        this.line = line;
-        this.col = col;
-        this.pos = pos;
+        this.line = line + 1;
+        this.col = col + 1;
+        this.pos = pos + 1;
         this.stack = new Error().stack;
 };
 
@@ -3300,12 +8391,12 @@
 
         function peek() { return S.text.charAt(S.pos); };
 
-        function next(signal_eof) {
+        function next(signal_eof, in_string) {
                 var ch = S.text.charAt(S.pos++);
                 if (signal_eof && !ch)
                         throw EX_EOF;
                 if (ch == "\n") {
-                        S.newline_before = true;
+                        S.newline_before = S.newline_before || !in_string;
                         ++S.line;
                         S.col = 0;
                 } else {
@@ -3335,16 +8426,21 @@
                                    (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) ||
                                    (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value)));
                 var ret = {
-                        type  : type,
-                        value : value,
-                        line  : S.tokline,
-                        col   : S.tokcol,
-                        pos   : S.tokpos,
-                        nlb   : S.newline_before
+                        type   : type,
+                        value  : value,
+                        line   : S.tokline,
+                        col    : S.tokcol,
+                        pos    : S.tokpos,
+                        endpos : S.pos,
+                        nlb    : S.newline_before
                 };
                 if (!is_comment) {
                         ret.comments_before = S.comments_before;
                         S.comments_before = [];
+                        // make note of any newlines in the comments that came before
+                        for (var i = 0, len = ret.comments_before.length; i < len; i++) {
+                                ret.nlb = ret.nlb || ret.comments_before[i].nlb;
+                        }
                 }
                 S.newline_before = false;
                 return ret;
@@ -3386,7 +8482,7 @@
                         if (ch == "+") return after_e;
                         after_e = false;
                         if (ch == ".") {
-                                if (!has_dot && !has_x)
+                                if (!has_dot && !has_x && !has_e)
                                         return has_dot = true;
                                 return false;
                         }
@@ -3402,8 +8498,8 @@
                 }
         };
 
-        function read_escaped_char() {
-                var ch = next(true);
+        function read_escaped_char(in_string) {
+                var ch = next(true, in_string);
                 switch (ch) {
                     case "n" : return "\n";
                     case "r" : return "\r";
@@ -3451,7 +8547,7 @@
                                                 return false;
                                         });
                                         if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
-                                        else ch = read_escaped_char();
+                                        else ch = read_escaped_char(true);
                                 }
                                 else if (ch == quote) break;
                                 ret += ch;
@@ -3477,11 +8573,10 @@
                 next();
                 return with_eof_error("Unterminated multiline comment", function(){
                         var i = find("*/", true),
-                            text = S.text.substring(S.pos, i),
-                            tok = token("comment2", text, true);
+                            text = S.text.substring(S.pos, i);
                         S.pos = i + 2;
                         S.line += text.split("\n").length - 1;
-                        S.newline_before = text.indexOf("\n") >= 0;
+                        S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
 
                         // https://github.com/mishoo/UglifyJS/issues/#issue/100
                         if (/^@cc_on/i.test(text)) {
@@ -3490,15 +8585,15 @@
                                 warn("*** UglifyJS DISCARDS ALL COMMENTS.  This means your code might no longer work properly in Internet Explorer.");
                         }
 
-                        return tok;
+                        return token("comment2", text, true);
                 });
         };
 
         function read_name() {
-                var backslash = false, name = "", ch;
+                var backslash = false, name = "", ch, escaped = false, hex;
                 while ((ch = peek()) != null) {
                         if (!backslash) {
-                                if (ch == "\\") backslash = true, next();
+                                if (ch == "\\") escaped = backslash = true, next();
                                 else if (is_identifier_char(ch)) name += next();
                                 else break;
                         }
@@ -3509,6 +8604,10 @@
                                 name += ch;
                                 backslash = false;
                         }
+                }
+                if (HOP(KEYWORDS, name) && escaped) {
+                        hex = name.charCodeAt(0).toString(16).toUpperCase();
+                        name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1);
                 }
                 return name;
         };
@@ -3689,13 +8788,14 @@
 function parse($TEXT, exigent_mode, embed_tokens) {
 
         var S = {
-                input       : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
-                token       : null,
-                prev        : null,
-                peeked      : null,
-                in_function : 0,
-                in_loop     : 0,
-                labels      : []
+                input         : typeof $TEXT == "string" ? tokenizer($TEXT, true) : $TEXT,
+                token         : null,
+                prev          : null,
+                peeked        : null,
+                in_function   : 0,
+                in_directives : true,
+                in_loop       : 0,
+                labels        : []
         };
 
         S.token = next();
@@ -3714,6 +8814,9 @@
                 } else {
                         S.token = S.input();
                 }
+                S.in_directives = S.in_directives && (
+                        S.token.type == "string" || is("punc", ";")
+                );
                 return S.token;
         };
 
@@ -3790,8 +8893,12 @@
                         S.token = S.input(S.token.value.substr(1)); // force regexp
                 }
                 switch (S.token.type) {
+                    case "string":
+                        var dir = S.in_directives, stat = simple_statement();
+                        if (dir && stat[1][0] == "string" && !is("punc", ","))
+                            return as("directive", stat[1][1]);
+                        return stat;
                     case "num":
-                    case "string":
                     case "regexp":
                     case "operator":
                     case "atom":
@@ -3918,8 +9025,11 @@
                         init = is("keyword", "var")
                                 ? (next(), var_(true))
                                 : expression(true, true);
-                        if (is("operator", "in"))
+                        if (is("operator", "in")) {
+                                if (init[0] == "var" && init[1].length > 1)
+                                        croak("Only one variable declaration allowed in for..in loop");
                                 return for_in(init);
+                        }
                 }
                 return regular_for(init);
         };
@@ -3941,7 +9051,7 @@
                 return as("for-in", init, lhs, obj, in_loop(statement));
         };
 
-        var function_ = maybe_embed_tokens(function(in_statement) {
+        var function_ = function(in_statement) {
                 var name = is("name") ? prog1(S.token.value, next) : null;
                 if (in_statement && !name)
                         unexpected();
@@ -3963,13 +9073,14 @@
                           (function(){
                                   ++S.in_function;
                                   var loop = S.in_loop;
+                                  S.in_directives = true;
                                   S.in_loop = 0;
                                   var a = block_();
                                   --S.in_function;
                                   S.in_loop = loop;
                                   return a;
                           })());
-        });
+        };
 
         function if_() {
                 var cond = parenthesised(), body = statement(), belse;
@@ -4317,7 +9428,7 @@
 
 function member(name, array) {
         for (var i = array.length; --i >= 0;)
-                if (array[i] === name)
+                if (array[i] == name)
                         return true;
         return false;
 };
@@ -4343,12 +9454,17 @@
 exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN;
 exports.OPERATORS = OPERATORS;
 exports.is_alphanumeric_char = is_alphanumeric_char;
+exports.is_identifier_start = is_identifier_start;
+exports.is_identifier_char = is_identifier_char;
 exports.set_logger = function(logger) {
         warn = logger;
 };
 
-});define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
-
+// Local variables:
+// js-indent-level: 8
+// End:
+});
+define('uglifyjs/squeeze-more', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
 var jsp = require("./parse-js"),
     pro = require("./process"),
     slice = jsp.slice,
@@ -4377,21 +9493,44 @@
                 "function": _lambda,
                 "defun": _lambda,
                 "new": function(ctor, args) {
-                        if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) {
-                                if (args.length != 1) {
-                                        return [ "array", args ];
-                                } else {
-                                        return walk([ "call", [ "name", "Array" ], args ]);
+                        if (ctor[0] == "name") {
+                                if (ctor[1] == "Array" && !scope.has("Array")) {
+                                        if (args.length != 1) {
+                                                return [ "array", args ];
+                                        } else {
+                                                return walk([ "call", [ "name", "Array" ], args ]);
+                                        }
+                                } else if (ctor[1] == "Object" && !scope.has("Object")) {
+                                        if (!args.length) {
+                                                return [ "object", [] ];
+                                        } else {
+                                                return walk([ "call", [ "name", "Object" ], args ]);
+                                        }
+                                } else if ((ctor[1] == "RegExp" || ctor[1] == "Function" || ctor[1] == "Error") && !scope.has(ctor[1])) {
+                                        return walk([ "call", [ "name", ctor[1] ], args]);
                                 }
                         }
                 },
                 "call": function(expr, args) {
+                        if (expr[0] == "dot" && expr[1][0] == "string" && args.length == 1
+                            && (args[0][1] > 0 && expr[2] == "substring" || expr[2] == "substr")) {
+                                return [ "call", [ "dot", expr[1], "slice"], args];
+                        }
                         if (expr[0] == "dot" && expr[2] == "toString" && args.length == 0) {
                                 // foo.toString()  ==>  foo+""
+                                if (expr[1][0] == "string") return expr[1];
                                 return [ "binary", "+", expr[1], [ "string", "" ]];
                         }
-                        if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
-                                return [ "array", args ];
+                        if (expr[0] == "name") {
+                                if (expr[1] == "Array" && args.length != 1 && !scope.has("Array")) {
+                                        return [ "array", args ];
+                                }
+                                if (expr[1] == "Object" && !args.length && !scope.has("Object")) {
+                                        return [ "object", [] ];
+                                }
+                                if (expr[1] == "String" && !scope.has("String")) {
+                                        return [ "binary", "+", args[0], [ "string", "" ]];
+                                }
                         }
                 }
         }, function() {
@@ -4401,8 +9540,11 @@
 
 exports.ast_squeeze_more = ast_squeeze_more;
 
-});define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
-
+// Local variables:
+// js-indent-level: 8
+// End:
+});
+define('uglifyjs/process', ["require", "exports", "module", "./parse-js", "./squeeze-more"], function(require, exports, module) {
 /***********************************************************************
 
   A JavaScript tokenizer / parser / beautifier / compressor.
@@ -4464,8 +9606,10 @@
  ***********************************************************************/
 
 var jsp = require("./parse-js"),
+    curry = jsp.curry,
     slice = jsp.slice,
     member = jsp.member,
+    is_identifier_char = jsp.is_identifier_char,
     PRECEDENCE = jsp.PRECEDENCE,
     OPERATORS = jsp.OPERATORS;
 
@@ -4543,6 +9687,9 @@
                 },
                 "function": function(name, args, body) {
                         return [ this[0], name, args.slice(), MAP(body, walk) ];
+                },
+                "debugger": function() {
+                        return [ this[0] ];
                 },
                 "defun": function(name, args, body) {
                         return [ this[0], name, args.slice(), MAP(body, walk) ];
@@ -4604,6 +9751,9 @@
                 },
                 "atom": function(name) {
                         return [ this[0], name ];
+                },
+                "directive": function(dir) {
+                        return [ this[0], dir ];
                 }
         };
 
@@ -4676,6 +9826,7 @@
         this.refs = {};         // names referenced from this scope
         this.uses_with = false; // will become TRUE if with() is detected in this or any subscopes
         this.uses_eval = false; // will become TRUE if eval() is detected in this or any subscopes
+        this.directives = [];   // directives activated from this scope
         this.parent = parent;   // parent scope
         this.children = [];     // sub-scopes
         if (parent) {
@@ -4686,13 +9837,21 @@
         }
 };
 
+function base54_digits() {
+        if (typeof DIGITS_OVERRIDE_FOR_TESTING != "undefined")
+                return DIGITS_OVERRIDE_FOR_TESTING;
+        else
+                return "etnrisouaflchpdvmgybwESxTNCkLAOM_DPHBjFIqRUzWXV$JKQGYZ0516372984";
+}
+
 var base54 = (function(){
-        var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_";
+        var DIGITS = base54_digits();
         return function(num) {
-                var ret = "";
+                var ret = "", base = 54;
                 do {
-                        ret = DIGITS.charAt(num % 54) + ret;
-                        num = Math.floor(num / 54);
+                        ret += DIGITS.charAt(num % base);
+                        num = Math.floor(num / base);
+                        base = 64;
                 } while (num > 0);
                 return ret;
         };
@@ -4777,6 +9936,9 @@
                                 this.names[name] = type || "var";
                         return name;
                 }
+        },
+        active_directive: function(dir) {
+                return member(dir, this.directives) || this.parent && this.parent.active_directive(dir);
         }
 };
 
@@ -4788,6 +9950,7 @@
 
         function with_new_scope(cont) {
                 current_scope = new Scope(current_scope);
+                current_scope.labels = new Scope();
                 var ret = current_scope.body = cont();
                 ret.scope = current_scope;
                 current_scope = current_scope.parent;
@@ -4820,14 +9983,19 @@
                 };
         };
 
+        function _breacont(label) {
+                if (label)
+                        current_scope.labels.refs[label] = true;
+        };
+
         return with_new_scope(function(){
                 // process AST
                 var ret = w.with_walkers({
                         "function": _lambda,
                         "defun": _lambda,
-                        "label": function(name, stat) { define(name, "label") },
-                        "break": function(label) { if (label) reference(label) },
-                        "continue": function(label) { if (label) reference(label) },
+                        "label": function(name, stat) { current_scope.labels.define(name) },
+                        "break": _breacont,
+                        "continue": _breacont,
                         "with": function(expr, block) {
                                 for (var s = current_scope; s; s = s.parent)
                                         s.uses_with = true;
@@ -4890,11 +10058,21 @@
 
 function ast_mangle(ast, options) {
         var w = ast_walker(), walk = w.walk, scope;
-        options = options || {};
+        options = defaults(options, {
+                mangle       : true,
+                toplevel     : false,
+                defines      : null,
+                except       : null,
+                no_functions : false
+        });
 
         function get_mangled(name, newMangle) {
+                if (!options.mangle) return name;
                 if (!options.toplevel && !scope.parent) return name; // don't mangle toplevel
                 if (options.except && member(name, options.except))
+                        return name;
+                if (options.no_functions && HOP(scope.names, name) &&
+                    (scope.names[name] == 'defun' || scope.names[name] == 'lambda'))
                         return name;
                 return scope.get_mangled(name, newMangle);
         };
@@ -4913,15 +10091,18 @@
         };
 
         function _lambda(name, args, body) {
-                var is_defun = this[0] == "defun", extra;
-                if (name) {
-                        if (is_defun) name = get_mangled(name);
-                        else {
-                                extra = {};
-                                if (!(scope.uses_eval || scope.uses_with))
-                                        name = extra[name] = scope.next_mangled();
-                                else
-                                        extra[name] = name;
+                if (!options.no_functions && options.mangle) {
+                        var is_defun = this[0] == "defun", extra;
+                        if (name) {
+                                if (is_defun) name = get_mangled(name);
+                                else if (body.scope.references(name)) {
+                                        extra = {};
+                                        if (!(scope.uses_eval || scope.uses_with))
+                                                name = extra[name] = scope.next_mangled();
+                                        else
+                                                extra[name] = name;
+                                }
+                                else name = null;
                         }
                 }
                 body = with_scope(body.scope, function(){
@@ -4950,6 +10131,10 @@
                 return [ this[0], MAP(defs, function(d){
                         return [ get_mangled(d[0]), walk(d[1]) ];
                 }) ];
+        };
+
+        function _breacont(label) {
+                if (label) return [ this[0], scope.labels.get_mangled(label) ];
         };
 
         return w.with_walkers({
@@ -4966,9 +10151,16 @@
                         }
                         return ast;
                 },
-                "label": function(label, stat) { return [ this[0], get_mangled(label), walk(stat) ] },
-                "break": function(label) { if (label) return [ this[0], get_mangled(label) ] },
-                "continue": function(label) { if (label) return [ this[0], get_mangled(label) ] },
+                "label": function(label, stat) {
+                        if (scope.labels.refs[label]) return [
+                                this[0],
+                                scope.labels.get_mangled(label, true),
+                                walk(stat)
+                        ];
+                        return walk(stat);
+                },
+                "break": _breacont,
+                "continue": _breacont,
                 "var": _vardefs,
                 "const": _vardefs,
                 "name": function(name) {
@@ -4985,6 +10177,9 @@
                         return with_scope(self.scope, function(){
                                 return [ self[0], MAP(body, walk) ];
                         });
+                },
+                "directive": function() {
+                        return MAP.at_top(this);
                 }
         }, function() {
                 return walk(ast_add_scope(ast));
@@ -5126,7 +10321,9 @@
                             case "string": ast =  [ "string", val ]; break;
                             case "number": ast =  [ "num", val ]; break;
                             case "boolean": ast =  [ "name", String(val) ]; break;
-                            default: throw new Error("Can't handle constant of type: " + (typeof val));
+                            default:
+                                if (val === null) { ast = [ "atom", "null" ]; break; }
+                                throw new Error("Can't handle constant of type: " + (typeof val));
                         }
                         return yes.call(expr, ast, val);
                 } catch(ex) {
@@ -5188,24 +10385,22 @@
                         var fi = statements[i];
                         if (fi[0] != "if") continue;
 
-                        if (fi[3] && walk(fi[3])) continue;
-
-                        var t = walk(fi[2]);
+                        if (fi[3]) continue;
+
+                        var t = fi[2];
                         if (!aborts(t)) continue;
 
                         var conditional = walk(fi[1]);
 
-                        var e_body = statements.slice(i + 1);
+                        var e_body = redo_if(statements.slice(i + 1));
                         var e = e_body.length == 1 ? e_body[0] : [ "block", e_body ];
 
-                        var ret = statements.slice(0, i).concat([ [
+                        return statements.slice(0, i).concat([ [
                                 fi[0],          // "if"
                                 conditional,    // conditional
                                 t,              // then
                                 e               // else
                         ] ]);
-
-                        return redo_if(ret);
                 }
 
                 return statements;
@@ -5249,6 +10444,10 @@
         function found(){ return handler.call(this, this, w, stop, restart) };
         function unary(op) {
                 if (op == "++" || op == "--")
+                        return found.apply(this, arguments);
+        };
+        function binary(op) {
+                if (op == "&&" || op == "||")
                         return found.apply(this, arguments);
         };
         return w.with_walkers({
@@ -5269,6 +10468,8 @@
                 "return": found,
                 "unary-prefix": unary,
                 "unary-postfix": unary,
+                "conditional": found,
+                "binary": binary,
                 "defun": found
         }, function(){
                 while (true) try {
@@ -5344,7 +10545,7 @@
                         if (ret == null) ret = d;
                         else ret = [ "seq", d, ret ];
                 }
-                if (ret == null) {
+                if (ret == null && w.parent()[0] != "for") {
                         if (w.parent()[0] == "for-in")
                                 return [ "name", defs[0][0] ];
                         return MAP.skip;
@@ -5375,10 +10576,18 @@
 };
 
 function ast_squeeze(ast, options) {
+        ast = squeeze_1(ast, options);
+        ast = squeeze_2(ast, options);
+        return ast;
+};
+
+function squeeze_1(ast, options) {
         options = defaults(options, {
                 make_seqs   : true,
                 dead_code   : true,
-                no_warnings : false
+                no_warnings : false,
+                keep_comps  : true,
+                unsafe      : false
         });
 
         var w = ast_walker(), walk = w.walk, scope;
@@ -5396,11 +10605,13 @@
                         return best_of(not_c, [ "conditional", c[1], negate(c[2]), negate(c[3]) ]);
                     case "binary":
                         var op = c[1], left = c[2], right = c[3];
-                        switch (op) {
+                        if (!options.keep_comps) switch (op) {
                             case "<="  : return [ "binary", ">", left, right ];
                             case "<"   : return [ "binary", ">=", left, right ];
                             case ">="  : return [ "binary", "<", left, right ];
                             case ">"   : return [ "binary", "<=", left, right ];
+                        }
+                        switch (op) {
                             case "=="  : return [ "binary", "!=", left, right ];
                             case "!="  : return [ "binary", "==", left, right ];
                             case "===" : return [ "binary", "!==", left, right ];
@@ -5431,15 +10642,6 @@
                 }, make_real_conditional);
         };
 
-        function with_scope(s, cont) {
-                var _scope = scope;
-                scope = s;
-                var ret = cont();
-                ret.scope = s;
-                scope = _scope;
-                return ret;
-        };
-
         function rmblock(block) {
                 if (block != null && block[0] == "block" && block[1]) {
                         if (block[1].length == 1)
@@ -5451,14 +10653,7 @@
         };
 
         function _lambda(name, args, body) {
-                var is_defun = this[0] == "defun";
-                body = with_scope(body.scope, function(){
-                        var ret = tighten(body, "lambda");
-                        if (!is_defun && name && !scope.references(name))
-                                name = null;
-                        return ret;
-                });
-                return [ this[0], name, args, body ];
+                return [ this[0], name, args, tighten(body, "lambda") ];
         };
 
         // this function does a few things:
@@ -5583,10 +10778,23 @@
                 });
         };
 
+        function abort_else(c, t, e) {
+                var ret = [ [ "if", negate(c), e ] ];
+                if (t[0] == "block") {
+                        if (t[1]) ret = ret.concat(t[1]);
+                } else {
+                        ret.push(t);
+                }
+                return walk([ "block", ret ]);
+        };
+
         function make_real_if(c, t, e) {
                 c = walk(c);
                 t = walk(t);
                 e = walk(e);
+
+                if (empty(e) && empty(t))
+                        return [ "stat", c ];
 
                 if (empty(t)) {
                         c = negate(c);
@@ -5608,17 +10816,16 @@
                                 }
                         })();
                 }
-                if (empty(e) && empty(t))
-                        return [ "stat", c ];
                 var ret = [ "if", c, t, e ];
                 if (t[0] == "if" && empty(t[3]) && empty(e)) {
                         ret = best_of(ret, walk([ "if", [ "binary", "&&", c, t[1] ], t[2] ]));
                 }
                 else if (t[0] == "stat") {
                         if (e) {
-                                if (e[0] == "stat") {
+                                if (e[0] == "stat")
                                         ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]);
-                                }
+                                else if (aborts(e))
+                                        ret = abort_else(c, t, e);
                         }
                         else {
                                 ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]);
@@ -5638,13 +10845,7 @@
                         ret = walk([ "block", ret ]);
                 }
                 else if (t && aborts(e)) {
-                        ret = [ [ "if", negate(c), e ] ];
-                        if (t[0] == "block") {
-                                if (t[1]) ret = ret.concat(t[1]);
-                        } else {
-                                ret.push(t);
-                        }
-                        ret = walk([ "block", ret ]);
+                        ret = abort_else(c, t, e);
                 }
                 return ret;
         };
@@ -5672,9 +10873,7 @@
                 },
                 "if": make_if,
                 "toplevel": function(body) {
-                        return [ "toplevel", with_scope(this.scope, function(){
-                                return tighten(body);
-                        }) ];
+                        return [ "toplevel", tighten(body) ];
                 },
                 "switch": function(expr, body) {
                         var last = body.length - 1;
@@ -5745,14 +10944,53 @@
                                 return [ this[0], rvalue[1], lvalue, rvalue[3] ]
                         }
                         return [ this[0], op, lvalue, rvalue ];
+                },
+                "call": function(expr, args) {
+                        expr = walk(expr);
+                        if (options.unsafe && expr[0] == "dot" && expr[1][0] == "string" && expr[2] == "toString") {
+                                return expr[1];
+                        }
+                        return [ this[0], expr,  MAP(args, walk) ];
+                },
+                "num": function (num) {
+                        if (!isFinite(num))
+                                return [ "binary", "/", num === 1 / 0
+                                         ? [ "num", 1 ] : num === -1 / 0
+                                         ? [ "unary-prefix", "-", [ "num", 1 ] ]
+                                         : [ "num", 0 ], [ "num", 0 ] ];
+
+                        return [ this[0], num ];
                 }
         }, function() {
-                for (var i = 0; i < 2; ++i) {
-                        ast = prepare_ifs(ast);
-                        ast = ast_add_scope(ast);
-                        ast = walk(ast);
-                }
-                return ast;
+                return walk(prepare_ifs(walk(prepare_ifs(ast))));
+        });
+};
+
+function squeeze_2(ast, options) {
+        var w = ast_walker(), walk = w.walk, scope;
+        function with_scope(s, cont) {
+                var save = scope, ret;
+                scope = s;
+                ret = cont();
+                scope = save;
+                return ret;
+        };
+        function lambda(name, args, body) {
+                return [ this[0], name, args, with_scope(body.scope, curry(MAP, body, walk)) ];
+        };
+        return w.with_walkers({
+                "directive": function(dir) {
+                        if (scope.active_directive(dir))
+                                return [ "block" ];
+                        scope.directives.push(dir);
+                },
+                "toplevel": function(body) {
+                        return [ this[0], with_scope(this.scope, curry(MAP, body, walk)) ];
+                },
+                "function": lambda,
+                "defun": lambda
+        }, function(){
+                return walk(ast_add_scope(ast));
         });
 };
 
@@ -5766,7 +11004,8 @@
         "dot",
         "sub",
         "call",
-        "regexp"
+        "regexp",
+        "defun"
 ]);
 
 function make_string(str, ascii_only) {
@@ -5778,7 +11017,6 @@
                     case "\f": return "\\f";
                     case "\n": return "\\n";
                     case "\r": return "\\r";
-                    case "\t": return "\\t";
                     case "\u2028": return "\\u2028";
                     case "\u2029": return "\\u2029";
                     case '"': ++dq; return '"';
@@ -5820,7 +11058,7 @@
         function encode_string(str) {
                 var ret = make_string(str, options.ascii_only);
                 if (options.inline_script)
-                        ret = ret.replace(/<\x2fscript([>/\t\n\f\r ])/gi, "<\\/script$1");
+                        ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
                 return ret;
         };
 
@@ -5844,6 +11082,15 @@
                 indentation += incr;
                 try { return cont.apply(null, slice(arguments, 1)); }
                 finally { indentation -= incr; }
+        };
+
+        function last_char(str) {
+                str = str.toString();
+                return str.charAt(str.length - 1);
+        };
+
+        function first_char(str) {
+                return str.toString().charAt(0);
         };
 
         function add_spaces(a) {
@@ -5854,7 +11101,8 @@
                         var next = a[i + 1];
                         b.push(a[i]);
                         if (next &&
-                            ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) ||
+                            ((is_identifier_char(last_char(a[i])) && (is_identifier_char(first_char(next))
+                                                                      || first_char(next) == "\\")) ||
                              (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) {
                                 b.push(" ");
                         }
@@ -5914,7 +11162,7 @@
         };
 
         function make_num(num) {
-                var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m;
+                var str = num.toString(10), a = [ str.replace(/^0\./, ".").replace('e+', 'e') ], m;
                 if (Math.floor(num) === num) {
                         if (num >= 0) {
                                 a.push("0x" + num.toString(16).toLowerCase(), // probably pointless
@@ -5939,6 +11187,7 @@
                 "string": encode_string,
                 "num": make_num,
                 "name": make_name,
+                "debugger": function(){ return "debugger;" },
                 "toplevel": function(statements) {
                         return make_block_statements(statements)
                                 .join(newline + newline);
@@ -6020,9 +11269,9 @@
                 "dot": function(expr) {
                         var out = make(expr), i = 1;
                         if (expr[0] == "num") {
-                                if (!/\./.test(expr[1]))
+                                if (!/[a-f.]/i.test(out))
                                         out += ".";
-                        } else if (needs_parens(expr))
+                        } else if (expr[0] != "function" && needs_parens(expr))
                                 out = "(" + out + ")";
                         while (i < arguments.length)
                                 out += "." + make_name(arguments[i++]);
@@ -6030,7 +11279,7 @@
                 },
                 "call": function(func, args) {
                         var f = make(func);
-                        if (needs_parens(func))
+                        if (f.charAt(0) != "(" && needs_parens(func))
                                 f = "(" + f + ")";
                         return f + "(" + add_commas(MAP(args, function(expr){
                                 return parenthesize(expr, "seq");
@@ -6120,7 +11369,7 @@
                                         if (p.length == 3) {
                                                 // getter/setter.  The name is in p[0], the arg.list in p[1][2], the
                                                 // body in p[1][3] and type ("get" / "set") in p[2].
-                                                return indent(make_function(p[0], p[1][2], p[1][3], p[2]));
+                                                return indent(make_function(p[0], p[1][2], p[1][3], p[2], true));
                                         }
                                         var key = p[0], val = parenthesize(p[1], "seq");
                                         if (options.quote_keys) {
@@ -6139,6 +11388,7 @@
                         return obj_needs_parens ? "(" + out + ")" : out;
                 },
                 "regexp": function(rx, mods) {
+                        if (options.ascii_only) rx = to_ascii(rx);
                         return "/" + rx + "/" + mods;
                 },
                 "array": function(elements) {
@@ -6149,7 +11399,9 @@
                         })), "]" ]);
                 },
                 "stat": function(stmt) {
-                        return make(stmt).replace(/;*\s*$/, ";");
+                        return stmt != null
+                                ? make(stmt).replace(/;*\s*$/, ";")
+                                : ";";
                 },
                 "seq": function() {
                         return add_commas(MAP(slice(arguments), make));
@@ -6162,6 +11414,9 @@
                 },
                 "atom": function(name) {
                         return make_name(name);
+                },
+                "directive": function(dir) {
+                        return make_string(dir) + ";";
                 }
         }, function(){ return make(ast) });
 
@@ -6197,23 +11452,24 @@
                 return make(th);
         };
 
-        function make_function(name, args, body, keyword) {
+        function make_function(name, args, body, keyword, no_parens) {
                 var out = keyword || "function";
                 if (name) {
                         out += " " + make_name(name);
                 }
                 out += "(" + add_commas(MAP(args, make_name)) + ")";
-                return add_spaces([ out, make_block(body) ]);
+                out = add_spaces([ out, make_block(body) ]);
+                return (!no_parens && needs_parens(this)) ? "(" + out + ")" : out;
         };
 
         function must_has_semicolon(node) {
                 switch (node[0]) {
                     case "with":
                     case "while":
-                        return empty(node[2]); // `with' or `while' with empty body?
+                        return empty(node[2]) || must_has_semicolon(node[2]);
                     case "for":
                     case "for-in":
-                        return empty(node[4]); // `for' with empty body?
+                        return empty(node[4]) || must_has_semicolon(node[4]);
                     case "if":
                         if (empty(node[2]) && !node[3]) return true; // `if' with empty `then' and no `else'
                         if (node[3]) {
@@ -6221,6 +11477,8 @@
                                 return must_has_semicolon(node[3]); // dive into the `else' branch
                         }
                         return must_has_semicolon(node[2]); // dive into the `then' branch
+                    case "directive":
+                        return true;
                 }
         };
 
@@ -6400,8 +11658,11 @@
 // keep this last!
 exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more;
 
-});define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process"], function(require, exports, module) {
-
+// Local variables:
+// js-indent-level: 8
+// End:
+});
+define('uglifyjs/index', ["require", "exports", "module", "./parse-js", "./process", "./consolidator"], function(require, exports, module) {
 //convienence function(src, [options]);
 function uglify(orig_code, options){
   options || (options = {});
@@ -6417,160 +11678,83 @@
 
 uglify.parser = require("./parse-js");
 uglify.uglify = require("./process");
+uglify.consolidator = require("./consolidator");
 
 module.exports = uglify
-
 });/**
  * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint plusplus: false, strict: false */
+/*jslint plusplus: true */
 /*global define: false */
 
-define('parse', ['uglifyjs/index'], function (uglify) {
-    var parser = uglify.parser,
-        processor = uglify.uglify,
-        ostring = Object.prototype.toString,
-        isArray;
-
-    if (Array.isArray) {
-        isArray = Array.isArray;
-    } else {
-        isArray = function (it) {
-            return ostring.call(it) === "[object Array]";
-        };
-    }
+define('parse', ['./esprima'], function (esprima) {
+    'use strict';
+
+    var ostring = Object.prototype.toString,
+        //This string is saved off because JSLint complains
+        //about obj.arguments use, as 'reserved word'
+        argPropName = 'arguments';
+
+    //From an esprima example for traversing its ast.
+    function traverse(object, visitor) {
+        var key, child;
+
+        if (!object) {
+            return;
+        }
+
+        if (visitor.call(null, object) === false) {
+            return false;
+        }
+        for (key in object) {
+            if (object.hasOwnProperty(key)) {
+                child = object[key];
+                if (typeof child === 'object' && child !== null) {
+                    if (traverse(child, visitor) === false) {
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+
 
     /**
-     * Determines if the AST node is an array literal
-     */
-    function isArrayLiteral(node) {
-        return node[0] === 'array';
-    }
-
-    /**
-     * Determines if the AST node is an object literal
-     */
-    function isObjectLiteral(node) {
-        return node[0] === 'object';
-    }
-
-    /**
-     * Converts a regular JS array of strings to an AST node that
-     * represents that array.
-     * @param {Array} ary
-     * @param {Node} an AST node that represents an array of strings.
-     */
-    function toAstArray(ary) {
-        var output = [
-            'array',
-            []
-        ],
-        i, item;
-
-        for (i = 0; (item = ary[i]); i++) {
-            output[1].push([
-                'string',
-                item
-            ]);
-        }
-
-        return output;
-    }
-
-    /**
-     * Validates a node as being an object literal (like for i18n bundles)
-     * or an array literal with just string members. If an array literal,
-     * only return array members that are full strings. So the caller of
-     * this function should use the return value as the new value for the
-     * node.
-     *
-     * This function does not need to worry about comments, they are not
-     * present in this AST.
+     * Pulls out dependencies from an array literal with just string members.
+     * If string literals, will just return those string values in an array,
+     * skipping other items in the array.
      *
      * @param {Node} node an AST node.
      *
-     * @returns {Node} an AST node to use for the valid dependencies.
+     * @returns {Array} an array of strings.
      * If null is returned, then it means the input node was not a valid
      * dependency.
      */
-    function validateDeps(node) {
-        var newDeps = ['array', []],
-            arrayArgs, i, dep;
-
-        if (!node) {
-            return null;
-        }
-
-        if (isObjectLiteral(node) || node[0] === 'function') {
-            return node;
-        }
-
-        //Dependencies can be an object literal or an array.
-        if (!isArrayLiteral(node)) {
-            return null;
-        }
-
-        arrayArgs = node[1];
-
-        for (i = 0; i < arrayArgs.length; i++) {
-            dep = arrayArgs[i];
-            if (dep[0] === 'string') {
-                newDeps[1].push(dep);
-            }
-        }
-        return newDeps[1].length ? newDeps : null;
+    function getValidDeps(node) {
+        if (!node || node.type !== 'ArrayExpression' || !node.elements) {
+            return;
+        }
+
+        var deps = [];
+
+        node.elements.some(function (elem) {
+            if (elem.type === 'Literal') {
+                deps.push(elem.value);
+            }
+        });
+
+        return deps.length ? deps : undefined;
     }
 
     /**
-     * Gets dependencies from a node, but only if it is an array literal,
-     * and only if the dependency is a string literal.
-     *
-     * This function does not need to worry about comments, they are not
-     * present in this AST.
-     *
-     * @param {Node} node an AST node.
-     *
-     * @returns {Array} of valid dependencies.
-     * If null is returned, then it means the input node was not a valid
-     * array literal, or did not have any string literals..
-     */
-    function getValidDeps(node) {
-        var newDeps = [],
-            arrayArgs, i, dep;
-
-        if (!node) {
-            return null;
-        }
-
-        if (isObjectLiteral(node) || node[0] === 'function') {
-            return null;
-        }
-
-        //Dependencies can be an object literal or an array.
-        if (!isArrayLiteral(node)) {
-            return null;
-        }
-
-        arrayArgs = node[1];
-
-        for (i = 0; i < arrayArgs.length; i++) {
-            dep = arrayArgs[i];
-            if (dep[0] === 'string') {
-                newDeps.push(dep[1]);
-            }
-        }
-        return newDeps.length ? newDeps : null;
-    }
-
-    /**
-     * Main parse function. Returns a string of any valid require or define/require.def
-     * calls as part of one JavaScript source string.
+     * Main parse function. Returns a string of any valid require or
+     * define/require.def calls as part of one JavaScript source string.
      * @param {String} moduleName the module name that represents this file.
-     * It is used to create a default define if there is not one already for the file.
-     * This allows properly tracing dependencies for builds. Otherwise, if
+     * It is used to create a default define if there is not one already for the
+     * file. This allows properly tracing dependencies for builds. Otherwise, if
      * the file just has a require() call, the file dependencies will not be
      * properly reflected: the file will come before its dependencies.
      * @param {String} moduleName
@@ -6578,39 +11762,23 @@
      * @param {String} fileContents
      * @param {Object} options optional options. insertNeedsDefine: true will
      * add calls to require.needsDefine() if appropriate.
-     * @returns {String} JS source string or null, if no require or define/require.def
-     * calls are found.
+     * @returns {String} JS source string or null, if no require or
+     * define/require.def calls are found.
      */
     function parse(moduleName, fileName, fileContents, options) {
         options = options || {};
 
         //Set up source input
-        var moduleDeps = [],
+        var i, moduleCall, depString,
+            moduleDeps = [],
             result = '',
             moduleList = [],
             needsDefine = true,
-            astRoot = parser.parse(fileContents),
-            i, moduleCall, depString;
+            astRoot = esprima.parse(fileContents);
 
         parse.recurse(astRoot, function (callName, config, name, deps) {
-            //If name is an array, it means it is an anonymous module,
-            //so adjust args appropriately. An anonymous module could
-            //have a FUNCTION as the name type, but just ignore those
-            //since we just want to find dependencies.
-            if (name && isArrayLiteral(name)) {
-                deps = name;
-                name = null;
-            }
-
-            if (!(deps = getValidDeps(deps))) {
+            if (!deps) {
                 deps = [];
-            }
-
-            //Get the name as a string literal, if it is available.
-            if (name && name[0] === 'string') {
-                name = name[1];
-            } else {
-                name = null;
             }
 
             if (callName === 'define' && (!name || name === moduleName)) {
@@ -6627,64 +11795,113 @@
                     deps: deps
                 });
             }
-        });
+
+            //If define was found, no need to dive deeper, unless
+            //the config explicitly wants to dig deeper.
+            return !!options.findNestedDependencies;
+        }, options);
 
         if (options.insertNeedsDefine && needsDefine) {
             result += 'require.needsDefine("' + moduleName + '");';
         }
 
         if (moduleDeps.length || moduleList.length) {
-            for (i = 0; (moduleCall = moduleList[i]); i++) {
+            for (i = 0; i < moduleList.length; i++) {
+                moduleCall = moduleList[i];
                 if (result) {
                     result += '\n';
                 }
-                depString = moduleCall.deps.length ? '["' + moduleCall.deps.join('","') + '"]' : '[]';
-                result += 'define("' + moduleCall.name + '",' + depString + ');';
+
+                //If this is the main module for this file, combine any
+                //"anonymous" dependencies (could come from a nested require
+                //call) with this module.
+                if (moduleCall.name === moduleName) {
+                    moduleCall.deps = moduleCall.deps.concat(moduleDeps);
+                    moduleDeps = [];
+                }
+
+                depString = moduleCall.deps.length ? '["' +
+                            moduleCall.deps.join('","') + '"]' : '[]';
+                result += 'define("' + moduleCall.name + '",' +
+                          depString + ');';
             }
             if (moduleDeps.length) {
                 if (result) {
                     result += '\n';
                 }
-                depString = moduleDeps.length ? '["' + moduleDeps.join('","') + '"]' : '[]';
+                depString = moduleDeps.length ? '["' + moduleDeps.join('","') +
+                            '"]' : '[]';
                 result += 'define("' + moduleName + '",' + depString + ');';
             }
         }
 
-        return result ? result : null;
-    }
-
-    //Add some private methods to object for use in derived objects.
-    parse.isArray = isArray;
-    parse.isObjectLiteral = isObjectLiteral;
-    parse.isArrayLiteral = isArrayLiteral;
+        return result || null;
+    }
 
     /**
      * Handles parsing a file recursively for require calls.
      * @param {Array} parentNode the AST node to start with.
      * @param {Function} onMatch function to call on a parse match.
+     * @param {Object} [options] This is normally the build config options if
+     * it is passed.
      */
-    parse.recurse = function (parentNode, onMatch) {
-        var i, node;
-        if (isArray(parentNode)) {
-            for (i = 0; i < parentNode.length; i++) {
-                node = parentNode[i];
-                if (isArray(node)) {
-                    this.parseNode(node, onMatch);
-                    this.recurse(node, onMatch);
+    parse.recurse = function (object, onMatch, options) {
+        //Like traverse, but skips if branches that would not be processed
+        //after has application that results in tests of true or false boolean
+        //literal values.
+        var key, child,
+            hasHas = options && options.has;
+
+        if (!object) {
+            return;
+        }
+
+        //If has replacement has resulted in if(true){} or if(false){}, take
+        //the appropriate branch and skip the other one.
+        if (hasHas && object.type === 'IfStatement' && object.test.type &&
+                object.test.type === 'Literal') {
+            if (object.test.value) {
+                //Take the if branch
+                this.recurse(object.consequent, onMatch, options);
+            } else {
+                //Take the else branch
+                this.recurse(object.alternate, onMatch, options);
+            }
+        } else {
+            if (this.parseNode(object, onMatch) === false) {
+                return;
+            }
+            for (key in object) {
+                if (object.hasOwnProperty(key)) {
+                    child = object[key];
+                    if (typeof child === 'object' && child !== null) {
+                        this.recurse(child, onMatch, options);
+                    }
                 }
             }
         }
     };
 
     /**
-     * Determines if the file defines require().
+     * Determines if the file defines the require/define module API.
+     * Specifically, it looks for the `define.amd = ` expression.
      * @param {String} fileName
      * @param {String} fileContents
      * @returns {Boolean}
      */
     parse.definesRequire = function (fileName, fileContents) {
-        var astRoot = parser.parse(fileContents);
-        return this.nodeHasRequire(astRoot);
+        var found = false;
+
+        traverse(esprima.parse(fileContents), function (node) {
+            if (parse.hasDefineAmd(node)) {
+                found = true;
+
+                //Stop traversal
+                return false;
+            }
+        });
+
+        return found;
     };
 
     /**
@@ -6698,7 +11915,7 @@
      * returns an array, but could be of length zero.
      */
     parse.getAnonDeps = function (fileName, fileContents) {
-        var astRoot = parser.parse(fileContents),
+        var astRoot = esprima.parse(fileContents),
             defFunc = this.findAnonDefineFactory(astRoot);
 
         return parse.getAnonDepsFromNode(defFunc);
@@ -6717,11 +11934,11 @@
         if (node) {
             this.findRequireDepNames(node, deps);
 
-            //If no deps, still add the standard CommonJS require, exports, module,
-            //in that order, to the deps, but only if specified as function args.
-            //In particular, if exports is used, it is favored over the return
-            //value of the function, so only add it if asked.
-            funcArgLength = node[2] && node[2].length;
+            //If no deps, still add the standard CommonJS require, exports,
+            //module, in that order, to the deps, but only if specified as
+            //function args. In particular, if exports is used, it is favored
+            //over the return value of the function, so only add it if asked.
+            funcArgLength = node.params && node.params.length;
             if (funcArgLength) {
                 deps = (funcArgLength > 1 ? ["require", "exports", "module"] :
                         ["require"]).concat(deps);
@@ -6736,36 +11953,77 @@
      * @returns {Boolean}
      */
     parse.findAnonDefineFactory = function (node) {
-        var callback, i, n, call, args;
-
-        if (isArray(node)) {
-            if (node[0] === 'call') {
-                call = node[1];
-                args = node[2];
-                if ((call[0] === 'name' && call[1] === 'define') ||
-                           (call[0] === 'dot' && call[1][1] === 'require' && call[2] === 'def')) {
-
-                    //There should only be one argument and it should be a function,
-                    //or a named module with function as second arg
-                    if (args.length === 1 && args[0][0] === 'function') {
-                        return args[0];
-                    } else if (args.length === 2 && args[0][0] === 'string' &&
-                               args[1][0] === 'function') {
-                        return args[1];
-                    }
-                }
-            }
-
-            //Check child nodes
-            for (i = 0; i < node.length; i++) {
-                n = node[i];
-                if ((callback = this.findAnonDefineFactory(n))) {
-                    return callback;
-                }
-            }
-        }
-
-        return null;
+        var match;
+
+        traverse(node, function (node) {
+            var arg0, arg1;
+
+            if (node && node.type === 'CallExpression' &&
+                    node.callee && node.callee.type === 'Identifier' &&
+                    node.callee.name === 'define' && node[argPropName]) {
+
+                //Just the factory function passed to define
+                arg0 = node[argPropName][0];
+                if (arg0 && arg0.type === 'FunctionExpression') {
+                    match = arg0;
+                    return false;
+                }
+
+                //A string literal module ID followed by the factory function.
+                arg1 = node[argPropName][1];
+                if (arg0.type === 'Literal' &&
+                        arg1 && arg1.type === 'FunctionExpression') {
+                    match = arg1;
+                    return false;
+                }
+            }
+        });
+
+        return match;
+    };
+
+    /**
+     * Finds any config that is passed to requirejs. That includes calls to
+     * require/requirejs.config(), as well as require({}, ...) and
+     * requirejs({}, ...)
+     * @param {String} fileName
+     * @param {String} fileContents
+     *
+     * @returns {Object} a config object. Will be null if no config.
+     * Can throw an error if the config in the file cannot be evaluated in
+     * a build context to valid JavaScript.
+     */
+    parse.findConfig = function (fileName, fileContents) {
+        /*jslint evil: true */
+        var jsConfig,
+            foundConfig = null,
+            astRoot = esprima.parse(fileContents, {
+                range: true
+            });
+
+        traverse(astRoot, function (node) {
+            var arg,
+                c = node && node.callee,
+                requireType = parse.hasRequire(node);
+
+            if (requireType && (requireType === 'require' ||
+                    requireType === 'requirejs' ||
+                    requireType === 'requireConfig' ||
+                    requireType === 'requirejsConfig')) {
+
+                arg = node[argPropName] && node[argPropName][0];
+
+                if (arg && arg.type === 'ObjectExpression') {
+                    jsConfig = parse.nodeToString(fileContents, arg);
+                    foundConfig = eval('(' + jsConfig + ')');
+                    return false;
+                }
+            }
+
+
+        });
+
+        return foundConfig;
     };
 
     /**
@@ -6777,102 +12035,207 @@
      * @returns {Array} an array of dependency strings. The dependencies
      * have not been normalized, they may be relative IDs.
      */
-    parse.findDependencies = function (fileName, fileContents) {
-        //This is a litle bit inefficient, it ends up with two uglifyjs parser
-        //calls. Can revisit later, but trying to build out larger functional
-        //pieces first.
-        var dependencies = parse.getAnonDeps(fileName, fileContents),
-            astRoot = parser.parse(fileContents);
+    parse.findDependencies = function (fileName, fileContents, options) {
+        var dependencies = [],
+            astRoot = esprima.parse(fileContents);
 
         parse.recurse(astRoot, function (callName, config, name, deps) {
-            //Normalize the input args.
-            if (name && isArrayLiteral(name)) {
-                deps = name;
-                name = null;
-            }
-
-            if ((deps = getValidDeps(deps))) {
+            if (deps) {
                 dependencies = dependencies.concat(deps);
             }
-        });
+        }, options);
 
         return dependencies;
     };
 
+    /**
+     * Finds only CJS dependencies, ones that are the form
+     * require('stringLiteral')
+     */
+    parse.findCjsDependencies = function (fileName, fileContents, options) {
+        var dependencies = [];
+
+        traverse(esprima.parse(fileContents), function (node) {
+            var arg;
+
+            if (node && node.type === 'CallExpression' && node.callee &&
+                    node.callee.type === 'Identifier' &&
+                    node.callee.name === 'require' && node[argPropName] &&
+                    node[argPropName].length === 1) {
+                arg = node[argPropName][0];
+                if (arg.type === 'Literal') {
+                    dependencies.push(arg.value);
+                }
+            }
+        });
+
+        return dependencies;
+    };
+
+    //function define() {}
+    parse.hasDefDefine = function (node) {
+        return node.type === 'FunctionDeclaration' && node.id &&
+                    node.id.type === 'Identifier' && node.id.name === 'define';
+    };
+
+    //define.amd = ...
+    parse.hasDefineAmd = function (node) {
+        return node && node.type === 'AssignmentExpression' &&
+            node.left && node.left.type === 'MemberExpression' &&
+            node.left.object && node.left.object.name === 'define' &&
+            node.left.property && node.left.property.name === 'amd';
+    };
+
+    //require(), requirejs(), require.config() and requirejs.config()
+    parse.hasRequire = function (node) {
+        var callName,
+            c = node && node.callee;
+
+        if (node && node.type === 'CallExpression' && c) {
+            if (c.type === 'Identifier' &&
+                    (c.name === 'require' ||
+                    c.name === 'requirejs')) {
+                //A require/requirejs({}, ...) call
+                callName = c.name;
+            } else if (c.type === 'MemberExpression' &&
+                    c.object &&
+                    c.object.type === 'Identifier' &&
+                    (c.object.name === 'require' ||
+                        c.object.name === 'requirejs') &&
+                    c.property && c.property.name === 'config') {
+                // require/requirejs.config({}) call
+                callName = c.object.name + 'Config';
+            }
+        }
+
+        return callName;
+    };
+
+    //define()
+    parse.hasDefine = function (node) {
+        return node && node.type === 'CallExpression' && node.callee &&
+            node.callee.type === 'Identifier' &&
+            node.callee.name === 'define';
+    };
+
+    /**
+     * Determines if define(), require({}|[]) or requirejs was called in the
+     * file. Also finds out if define() is declared and if define.amd is called.
+     */
+    parse.usesAmdOrRequireJs = function (fileName, fileContents, options) {
+        var uses;
+
+        traverse(esprima.parse(fileContents), function (node) {
+            var type, callName, arg;
+
+            if (parse.hasDefDefine(node)) {
+                //function define() {}
+                type = 'declaresDefine';
+            } else if (parse.hasDefineAmd(node)) {
+                type = 'defineAmd';
+            } else {
+                callName = parse.hasRequire(node);
+                if (callName) {
+                    arg = node[argPropName] && node[argPropName][0];
+                    if (arg && (arg.type === 'ObjectExpression' ||
+                            arg.type === 'ArrayExpression')) {
+                        type = callName;
+                    }
+                } else if (parse.hasDefine(node)) {
+                    type = 'define';
+                }
+            }
+
+            if (type) {
+                if (!uses) {
+                    uses = {};
+                }
+                uses[type] = true;
+            }
+        });
+
+        return uses;
+    };
+
+    /**
+     * Determines if require(''), exports.x =, module.exports =,
+     * __dirname, __filename are used. So, not strictly traditional CommonJS,
+     * also checks for Node variants.
+     */
+    parse.usesCommonJs = function (fileName, fileContents, options) {
+        var uses = null,
+            assignsExports = false;
+
+
+        traverse(esprima.parse(fileContents), function (node) {
+            var type,
+                exp = node.expression;
+
+            if (node.type === 'Identifier' &&
+                    (node.name === '__dirname' || node.name === '__filename')) {
+                type = node.name.substring(2);
+            } else if (node.type === 'VariableDeclarator' && node.id &&
+                    node.id.type === 'Identifier' &&
+                        node.id.name === 'exports') {
+                //Hmm, a variable assignment for exports, so does not use cjs
+                //exports.
+                type = 'varExports';
+            } else if (exp && exp.type === 'AssignmentExpression' && exp.left &&
+                    exp.left.type === 'MemberExpression' && exp.left.object) {
+                if (exp.left.object.name === 'module' && exp.left.property &&
+                        exp.left.property.name === 'exports') {
+                    type = 'moduleExports';
+                } else if (exp.left.object.name === 'exports' &&
+                        exp.left.property) {
+                    type = 'exports';
+                }
+
+            } else if (node && node.type === 'CallExpression' && node.callee &&
+                    node.callee.type === 'Identifier' &&
+                    node.callee.name === 'require' && node[argPropName] &&
+                    node[argPropName].length === 1 &&
+                    node[argPropName][0].type === 'Literal') {
+                type = 'require';
+            }
+
+            if (type) {
+                if (type === 'varExports') {
+                    assignsExports = true;
+                } else if (type !== 'exports' || !assignsExports) {
+                    if (!uses) {
+                        uses = {};
+                    }
+                    uses[type] = true;
+                }
+            }
+        });
+
+        return uses;
+    };
+
+
     parse.findRequireDepNames = function (node, deps) {
         var moduleName, i, n, call, args;
 
-        if (isArray(node)) {
-            if (node[0] === 'call') {
-                call = node[1];
-                args = node[2];
-
-                if (call && call[0] === 'name' && call[1] === 'require') {
-                    moduleName = args[0];
-                    if (moduleName[0] === 'string') {
-                        deps.push(moduleName[1]);
-                    }
-                }
-
-
-            }
-
-            //Check child nodes
-            for (i = 0; i < node.length; i++) {
-                n = node[i];
-                this.findRequireDepNames(n, deps);
-            }
-        }
+        traverse(node, function (node) {
+            var arg;
+
+            if (node && node.type === 'CallExpression' && node.callee &&
+                    node.callee.type === 'Identifier' &&
+                    node.callee.name === 'require' &&
+                    node[argPropName] && node[argPropName].length === 1) {
+
+                arg = node[argPropName][0];
+                if (arg.type === 'Literal') {
+                    deps.push(arg.value);
+                }
+            }
+        });
     };
 
     /**
-     * Determines if a given node contains a require() definition.
-     * @param {Array} node
-     * @returns {Boolean}
-     */
-    parse.nodeHasRequire = function (node) {
-        if (this.isDefineNode(node)) {
-            return true;
-        }
-
-        if (isArray(node)) {
-            for (var i = 0, n; i < node.length; i++) {
-                n = node[i];
-                if (this.nodeHasRequire(n)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    };
-
-    /**
-     * Is the given node the actual definition of define(). Actually uses
-     * the definition of define.amd to find require.
-     * @param {Array} node
-     * @returns {Boolean}
-     */
-    parse.isDefineNode = function (node) {
-        //Actually look for the define.amd = assignment, since
-        //that is more indicative of RequireJS vs a plain require definition.
-        var assign;
-        if (!node) {
-            return null;
-        }
-
-        if (node[0] === 'assign' && node[1] === true) {
-            assign = node[2];
-            if (assign[0] === 'dot' && assign[1][0] === 'name' &&
-                assign[1][1] === 'define' && assign[2] === 'amd') {
-                return true;
-            }
-        }
-        return false;
-    };
-
-    /**
-     * Determines if a specific node is a valid require or define/require.def call.
+     * Determines if a specific node is a valid require or define/require.def
+     * call.
      * @param {Array} node
      * @param {Function} onMatch a function to call when a match is found.
      * It is passed the match name, and the config, name, deps possible args.
@@ -6882,102 +12245,468 @@
      * Otherwise null.
      */
     parse.parseNode = function (node, onMatch) {
-        var call, name, config, deps, args, cjsDeps;
-
-        if (!isArray(node)) {
-            return null;
-        }
-
-        if (node[0] === 'call') {
-            call = node[1];
-            args = node[2];
-
-            if (call) {
-                if (call[0] === 'name' && call[1] === 'require') {
-
-                    //It is a plain require() call.
-                    config = args[0];
-                    deps = args[1];
-                    if (isArrayLiteral(config)) {
-                        deps = config;
-                        config = null;
-                    }
-
-                    if (!(deps = validateDeps(deps))) {
-                        return null;
-                    }
-
-                    return onMatch("require", null, null, deps);
-
-                } else if (call[0] === 'name' && call[1] === 'define') {
-
-                    //A define call
-                    name = args[0];
-                    deps = args[1];
-                    //Only allow define calls that match what is expected
-                    //in an AMD call:
-                    //* first arg should be string, array, function or object
-                    //* second arg optional, or array, function or object.
-                    //This helps weed out calls to a non-AMD define, but it is
-                    //not completely robust. Someone could create a define
-                    //function that still matches this shape, but this is the
-                    //best that is possible, and at least allows UglifyJS,
-                    //which does create its own internal define in one file,
-                    //to be inlined.
-                    if (((name[0] === 'string' || isArrayLiteral(name) ||
-                          name[0] === 'function' || isObjectLiteral(name))) &&
-                        (!deps || isArrayLiteral(deps) ||
-                         deps[0] === 'function' || isObjectLiteral(deps) ||
-                         // allow define(['dep'], factory) pattern
-                         (isArrayLiteral(name) && deps[0] === 'name' && args.length === 2))) {
-
-                        //If first arg is a function, could be a commonjs wrapper,
-                        //look inside for commonjs dependencies.
-                        //Also, if deps is a function look for commonjs deps.
-                        if (name && name[0] === 'function') {
-                            cjsDeps = parse.getAnonDepsFromNode(name);
-                            if (cjsDeps.length) {
-                                name = toAstArray(cjsDeps);
-                            }
-                        } else if (deps && deps[0] === 'function') {
-                            cjsDeps = parse.getAnonDepsFromNode(deps);
-                            if (cjsDeps.length) {
-                                deps = toAstArray(cjsDeps);
+        var name, deps, cjsDeps, arg, factory,
+            args = node && node[argPropName],
+            callName = parse.hasRequire(node);
+
+        if (callName === 'require' || callName === 'requirejs') {
+            //A plain require/requirejs call
+            arg = node[argPropName] && node[argPropName][0];
+            if (arg.type !== 'ArrayExpression') {
+                if (arg.type === 'ObjectExpression') {
+                    //A config call, try the second arg.
+                    arg = node[argPropName][1];
+                }
+            }
+
+            deps = getValidDeps(arg);
+            if (!deps) {
+                return;
+            }
+
+            return onMatch("require", null, null, deps);
+        } else if (parse.hasDefine(node) && args && args.length) {
+            name = args[0];
+            deps = args[1];
+            factory = args[2];
+
+            if (name.type === 'ArrayExpression') {
+                //No name, adjust args
+                factory = deps;
+                deps = name;
+                name = null;
+            } else if (name.type === 'FunctionExpression') {
+                //Just the factory, no name or deps
+                factory = name;
+                name = deps = null;
+            } else if (name.type !== 'Literal') {
+                 //An object literal, just null out
+                name = deps = factory = null;
+            }
+
+            if (name && name.type === 'Literal' && deps) {
+                if (deps.type === 'FunctionExpression') {
+                    //deps is the factory
+                    factory = deps;
+                    deps = null;
+                } else if (deps.type === 'ObjectExpression') {
+                    //deps is object literal, null out
+                    deps = factory = null;
+                }
+            }
+
+            if (deps && deps.type === 'ArrayExpression') {
+                deps = getValidDeps(deps);
+            } else if (factory && factory.type === 'FunctionExpression') {
+                //If no deps and a factory function, could be a commonjs sugar
+                //wrapper, scan the function for dependencies.
+                cjsDeps = parse.getAnonDepsFromNode(factory);
+                if (cjsDeps.length) {
+                    deps = cjsDeps;
+                }
+            } else if (deps || factory) {
+                //Does not match the shape of an AMD call.
+                return;
+            }
+
+            //Just save off the name as a string instead of an AST object.
+            if (name && name.type === 'Literal') {
+                name = name.value;
+            }
+
+            return onMatch("define", null, name, deps);
+        }
+    };
+
+    /**
+     * Converts an AST node into a JS source string by extracting
+     * the node's location from the given contents string. Assumes
+     * esprima.parse() with ranges was done.
+     * @param {String} contents
+     * @param {Object} node
+     * @returns {String} a JS source string.
+     */
+    parse.nodeToString = function (contents, node) {
+        var range = node.range;
+        return contents.substring(range[0], range[1]);
+    };
+
+    /**
+     * Extracts license comments from JS text.
+     * @param {String} fileName
+     * @param {String} contents
+     * @returns {String} a string of license comments.
+     */
+    parse.getLicenseComments = function (fileName, contents) {
+        var commentNode, refNode, subNode, value, i, j,
+            ast = esprima.parse(contents, {
+                comment: true
+            }),
+            result = '',
+            existsMap = {},
+            lineEnd = contents.indexOf('\r') === -1 ? '\n' : '\r\n';
+
+        if (ast.comments) {
+            for (i = 0; i < ast.comments.length; i++) {
+                commentNode = ast.comments[i];
+
+                if (commentNode.type === 'Line') {
+                    value = '//' + commentNode.value + lineEnd;
+                    refNode = commentNode;
+
+                    if (i + 1 >= ast.comments.length) {
+                        value += lineEnd;
+                    } else {
+                        //Look for immediately adjacent single line comments
+                        //since it could from a multiple line comment made out
+                        //of single line comments. Like this comment.
+                        for (j = i + 1; j < ast.comments.length; j++) {
+                            subNode = ast.comments[j];
+                            if (subNode.type === 'Line' &&
+                                    subNode.range[0] === refNode.range[1]) {
+                                //Adjacent single line comment. Collect it.
+                                value += '//' + subNode.value + lineEnd;
+                                refNode = subNode;
+                            } else {
+                                //No more single line comment blocks. Break out
+                                //and continue outer looping.
+                                value += lineEnd;
+                                i = j - 1;
+                                break;
                             }
                         }
-
-                        return onMatch("define", null, name, deps);
                     }
-                }
-            }
-        }
-
-        return null;
-    };
-
-    /**
-     * Converts an AST node into a JS source string. Does not maintain formatting
-     * or even comments from original source, just returns valid JS source.
-     * @param {Array} node
-     * @returns {String} a JS source string.
-     */
-    parse.nodeToString = function (node) {
-        return processor.gen_code(node, true);
+                } else {
+                    value = '/*' + commentNode.value + '*/' + lineEnd + lineEnd;
+                }
+
+                if (!existsMap[value] && (value.indexOf('license') !== -1 ||
+                        (commentNode.type === 'Block' &&
+                            value.indexOf('/*!') === 0) ||
+                        value.indexOf('opyright') !== -1 ||
+                        value.indexOf('(c)') !== -1)) {
+
+                    result += value;
+                    existsMap[value] = true;
+                }
+
+            }
+        }
+
+        return result;
     };
 
     return parse;
 });
 /**
+ * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved.
+ * Available via the MIT or new BSD license.
+ * see: http://github.com/jrburke/requirejs for details
+ */
+
+/*jslint */
+/*global define */
+
+define('transform', [ './esprima', './parse', 'logger', 'lang'], function (esprima, parse, logger, lang) {
+    'use strict';
+    var transform;
+
+    return (transform = {
+        toTransport: function (namespace, moduleName, path, contents, onFound, options) {
+            options = options || {};
+
+            var tokens, foundAnon, deps, lastRange, parenCount, inDefine,
+                defineRanges = [],
+                contentInsertion = '',
+                depString = '';
+
+            try {
+                tokens = esprima.parse(contents, {
+                    tokens: true,
+                    range: true
+                }).tokens;
+            } catch (e) {
+                logger.trace('toTransport skipping ' + path + ': ' +
+                             e.toString());
+                return contents;
+            }
+
+            //Find the define calls and their position in the files.
+            tokens.forEach(function (token, i) {
+                var prev, prev2, next, next2, next3, next4,
+                    needsId, depAction, nameCommaRange, foundId,
+                    sourceUrlData,
+                    namespaceExists = false;
+
+                if (inDefine && token.type === 'Punctuator') {
+                    //Looking for the end of the define call.
+                    if (token.value === '(') {
+                        parenCount += 1;
+                    } else if (token.value === ')') {
+                        parenCount -= 1;
+                    }
+
+                    if (parenCount === 0) {
+                        inDefine = false;
+
+                        //Found the end of the define call. Hold onto
+                        //it.
+                        lastRange = defineRanges.length &&
+                            defineRanges[defineRanges.length - 1];
+                        if (lastRange) {
+                            lastRange.defineEndRange = token.range;
+                        }
+                    }
+                }
+
+                if (token.type === 'Identifier' && token.value === 'define') {
+                    //Possible match. Do not want something.define calls
+                    //though, and only defines follow by a paren
+                    prev = tokens[i - 1];
+                    next = tokens[i + 1];
+
+                    if (prev && prev.type === 'Punctuator' &&
+                            prev.value === '.') {
+                        //a define on a sub-object, not a top level
+                        //define() call. If the sub object is the
+                        //namespace, then it is ok.
+                        prev2 = tokens[i - 2];
+                        if (!prev2) {
+                            return;
+                        }
+
+                        //If the prev2 does not match namespace, then bail.
+                        if (!namespace || prev2.type !== 'Identifier' ||
+                                prev2.value !== namespace) {
+                            return;
+                        } else if (namespace) {
+                            namespaceExists = true;
+                        }
+                    }
+
+                    if (!next || next.type !== 'Punctuator' ||
+                            next.value !== '(') {
+                       //Not a define() function call. Bail.
+                        return;
+                    }
+
+                    next2 = tokens[i + 2];
+                    if (!next2) {
+                        return;
+                    }
+
+                    //Figure out if this needs a named define call.
+                    if (next2.type === 'Punctuator' && next2.value === '[') {
+                        //Dependency array
+                        needsId = true;
+                        depAction = 'skip';
+                    } else if (next2.type === 'Punctuator' &&
+                            next2.value === '{') {
+                        //Object literal
+                        needsId = true;
+                        depAction = 'skip';
+                    } else if (next2.type === 'Keyword' &&
+                               next2.value === 'function') {
+                        //function
+                        needsId = true;
+                        depAction = 'scan';
+                    } else if (next2.type === 'String') {
+                        //Named module
+                        needsId = false;
+
+                        //The value includes the quotes around the string,
+                        //so remove them.
+                        foundId = next2.value.substring(1,
+                                                        next2.value.length - 1);
+
+                        //assumed it does not need dependencies injected
+
+                        //If next argument is a function it means we need
+                        //dependency scanning.
+                        next3 = tokens[i + 3];
+                        next4 = tokens[i + 4];
+                        if (!next3 || !next4) {
+                            return;
+                        }
+
+                        if (next3.type === 'Punctuator' &&
+                                next3.value === ',' &&
+                                next4.type === 'Keyword' &&
+                                next4.value === 'function') {
+                            depAction = 'scan';
+                            nameCommaRange = next3.range;
+                        } else {
+                            depAction = 'skip';
+                        }
+                    } else if (next2.type === 'Identifier') {
+                        //May be the define(factory); type.
+                        next3 = tokens[i + 3];
+                        if (!next3) {
+                            return;
+                        }
+                        if (next3.type === 'Punctuator' &&
+                                next3.value === ')') {
+                            needsId = true;
+                            depAction = 'empty';
+                        } else {
+                            return;
+                        }
+                    } else if (next2.type === 'Numeric') {
+                        //May be the define(12345); type.
+                        next3 = tokens[i + 3];
+                        if (!next3) {
+                            return;
+                        }
+                        if (next3.type === 'Punctuator' &&
+                                next3.value === ')') {
+                            needsId = true;
+                            depAction = 'skip';
+                        } else {
+                            return;
+                        }
+                    } else if (next2.type === 'Punctuator' &&
+                               next2.value === '-') {
+                        //May be the define(-12345); type.
+                        next3 = tokens[i + 3];
+                        if (!next3) {
+                            return;
+                        }
+                        if (next3.type === 'Numeric') {
+                            next4 = tokens[i + 4];
+                            if (!next4) {
+                                return;
+                            }
+                            if (next4.type === 'Punctuator' &&
+                                    next4.value === ')') {
+                                needsId = true;
+                                depAction = 'skip';
+                            } else {
+                                return;
+                            }
+                        } else {
+                            return;
+                        }
+                    } else {
+                        //Not a match, skip it.
+                        return;
+                    }
+
+                    //A valid define call. Need to find the end, start counting
+                    //parentheses.
+                    inDefine = true;
+                    parenCount = 0;
+
+                    defineRanges.push({
+                        foundId: foundId,
+                        needsId: needsId,
+                        depAction: depAction,
+                        namespaceExists: namespaceExists,
+                        defineRange: token.range,
+                        parenRange: next.range,
+                        nameCommaRange: nameCommaRange,
+                        sourceUrlData: sourceUrlData
+                    });
+                }
+            });
+
+            if (!defineRanges.length) {
+                return contents;
+            }
+
+            //Find the first anon define, then any that need dependency
+            //scanning.
+            defineRanges = defineRanges.filter(function (range) {
+                if (!foundAnon && range.needsId) {
+                    foundAnon = true;
+                    return true;
+                } else if (range.depAction === 'scan') {
+                    return true;
+                }
+            });
+
+            //Reverse the matches, need to start from the bottom of
+            //the file to modify it, so that the ranges are still true
+            //further up.
+            defineRanges.reverse();
+
+            defineRanges.forEach(function (info) {
+                //Do the modifications "backwards", in other words, start with the
+                //one that is farthest down and work up, so that the ranges in the
+                //defineRanges still apply. So that means deps, id, then namespace.
+
+                if (info.needsId && moduleName) {
+                    contentInsertion += "'" + moduleName + "',";
+                }
+
+                if (info.depAction === 'scan') {
+                    deps = parse.getAnonDeps(path, contents.substring(info.defineRange[0], info.defineEndRange[1]));
+
+                    if (deps.length) {
+                        depString = '[' + deps.map(function (dep) {
+                            return "'" + dep + "'";
+                        }) + ']';
+                    } else {
+                        depString = '[]';
+                    }
+                    depString +=  ',';
+
+                    if (info.nameCommaRange) {
+                        //Already have a named module, need to insert the
+                        //dependencies after the name.
+                        contents = contents.substring(0, info.nameCommaRange[1]) +
+                                   depString +
+                                   contents.substring(info.nameCommaRange[1],
+                                                  contents.length);
+                    } else {
+                        contentInsertion +=  depString;
+                    }
+                } else if (info.depAction === 'empty') {
+                    contentInsertion += '[],';
+                }
+
+                if (contentInsertion) {
+                    contents = contents.substring(0, info.parenRange[1]) +
+                               contentInsertion +
+                               contents.substring(info.parenRange[1],
+                                                  contents.length);
+                }
+
+                //Do namespace last so that ui does not mess upthe parenRange
+                //used above.
+                if (namespace && !info.namespaceExists) {
+                    contents = contents.substring(0, info.defineRange[0]) +
+                               namespace + '.' +
+                               contents.substring(info.defineRange[0],
+                                                  contents.length);
+                }
+
+                //Notify any listener for the found info
+                if (onFound) {
+                    onFound(info);
+                }
+            });
+
+            if (options.useSourceUrl) {
+                contents = 'eval("' + lang.jsEscape(contents) +
+                    '\\n//@ sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') +
+                    path +
+                    '");\n';
+            }
+
+            return contents;
+        }
+    });
+});/**
  * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint regexp: false, strict: false, plusplus: false  */
+/*jslint regexp: true, plusplus: true  */
 /*global define: false */
 
 define('pragma', ['parse', 'logger'], function (parse, logger) {
-
+    'use strict';
     function Temp() {}
 
     function create(obj, mixin) {
@@ -6989,7 +12718,7 @@
 
         if (mixin) {
             for (prop in mixin) {
-                if (mixin.hasOwnProperty(prop) && !(prop in temp)) {
+                if (mixin.hasOwnProperty(prop) && !temp.hasOwnProperty(prop)) {
                     temp[prop] = mixin[prop];
                 }
             }
@@ -7002,12 +12731,15 @@
         conditionalRegExp: /(exclude|include)Start\s*\(\s*["'](\w+)["']\s*,(.*)\)/,
         useStrictRegExp: /['"]use strict['"];/g,
         hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
-        nsRegExp: /(^|[^\.])(requirejs|require|define)\s*\(/,
+        nsRegExp: /(^|[^\.])(requirejs|require|define)(\.config)?\s*\(/g,
         nsWrapRegExp: /\/\*requirejs namespace: true \*\//,
         apiDefRegExp: /var requirejs, require, define;/,
         defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g,
+        defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g,
         defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g,
+        defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g,
         defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/,
+        amdefineRegExp: /if\s*\(\s*typeof define\s*\!==\s*'function'\s*\)\s*\{\s*[^\{\}]+amdefine[^\{\}]+\}/g,
 
         removeStrict: function (contents, config) {
             return config.useStrict ? contents : contents.replace(pragma.useStrictRegExp, '');
@@ -7016,8 +12748,7 @@
         namespace: function (fileContents, ns, onLifecycleName) {
             if (ns) {
                 //Namespace require/define calls
-                fileContents = fileContents.replace(pragma.nsRegExp, '$1' + ns + '.$2(');
-
+                fileContents = fileContents.replace(pragma.nsRegExp, '$1' + ns + '.$2$3(');
 
                 //Namespace define ternary use:
                 fileContents = fileContents.replace(pragma.defineTernaryRegExp,
@@ -7025,13 +12756,19 @@
 
                 //Namespace define jquery use:
                 fileContents = fileContents.replace(pragma.defineJQueryRegExp,
-                                                    "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.jQuery");
+                                                    "typeof " + ns + ".define === 'function' && " + ns + ".define.amd && " + ns + ".define.amd.jQuery");
+
+                //Namespace has.js define use:
+                fileContents = fileContents.replace(pragma.defineHasRegExp,
+                                                    "typeof " + ns + ".define === 'function' && typeof " + ns + ".define.amd === 'object' && " + ns + ".define.amd");
 
                 //Namespace define checks.
-                //Do this one last, since it is a subset of the more specific
+                //Do these ones last, since they are a subset of the more specific
                 //checks above.
                 fileContents = fileContents.replace(pragma.defineCheckRegExp,
                                                     "typeof " + ns + ".define === 'function' && " + ns + ".define.amd");
+                fileContents = fileContents.replace(pragma.defineTypeFirstCheckRegExp,
+                                                    "'function' === typeof " + ns + ".define && " + ns + ".define.amd");
 
                 //Check for require.js with the require/define definitions
                 if (pragma.apiDefRegExp.test(fileContents) &&
@@ -7062,7 +12799,7 @@
                                    'requirejs = ' + ns + '.requirejs,' +
                                    'define = ' + ns + '.define;\n' +
                                    fileContents +
-                                   '\n}());'
+                                   '\n}());';
                 }
             }
 
@@ -7077,7 +12814,7 @@
             var foundIndex = -1, startIndex = 0, lineEndIndex, conditionLine,
                 matches, type, marker, condition, isTrue, endRegExp, endMatches,
                 endMarkerIndex, shouldInclude, startLength, lifecycleHas, deps,
-                i, dep, moduleName,
+                i, dep, moduleName, collectorMod,
                 lifecyclePragmas, pragmas = config.pragmas, hasConfig = config.has,
                 //Legacy arg defined to help in dojo conversion script. Remove later
                 //when dojo no longer needs conversion:
@@ -7103,7 +12840,7 @@
             //Replace has references if desired
             if (hasConfig) {
                 fileContents = fileContents.replace(pragma.hasRegExp, function (match, test) {
-                    if (test in hasConfig) {
+                    if (hasConfig.hasOwnProperty(test)) {
                         return !!hasConfig[test];
                     }
                     return match;
@@ -7185,10 +12922,15 @@
                 try {
                     deps = parse.findDependencies(fileName, fileContents);
                     if (deps.length) {
-                        for (i = 0; (dep = deps[i]); i++) {
+                        for (i = 0; i < deps.length; i++) {
+                            dep = deps[i];
                             if (dep.indexOf('!') !== -1) {
-                                (pluginCollector[moduleName] ||
-                                 (pluginCollector[moduleName] = [])).push(dep);
+                                moduleName = dep.split('!')[0];
+                                collectorMod = pluginCollector[moduleName];
+                                if (!collectorMod) {
+                                 collectorMod = pluginCollector[moduleName] = [];
+                                }
+                                collectorMod.push(dep);
                             }
                         }
                     }
@@ -7197,6 +12939,9 @@
                                  fileName + ', skipping.');
                 }
             }
+
+            //Strip amdefine use for node-shared modules.
+            fileContents = fileContents.replace(pragma.amdefineRegExp, '');
 
             //Do namespacing
             if (onLifecycleName === 'OnSave' && config.namespace) {
@@ -7332,16 +13077,18 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint plusplus: false, nomen: false, regexp: false, strict: false */
+/*jslint plusplus: true, nomen: true, regexp: true */
 /*global define: false */
 
 define('optimize', [ 'lang', 'logger', 'env!env/optimize', 'env!env/file', 'parse',
          'pragma', 'uglifyjs/index'],
 function (lang,   logger,   envOptimize,        file,           parse,
           pragma, uglify) {
+    'use strict';
 
     var optimize,
         cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/g,
+        cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g,
         cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g;
 
     /**
@@ -7365,26 +13112,34 @@
 
     /**
      * Inlines nested stylesheets that have @import calls in them.
-     * @param {String} fileName
-     * @param {String} fileContents
-     * @param {String} [cssImportIgnore]
+     * @param {String} fileName the file name
+     * @param {String} fileContents the file contents
+     * @param {String} cssImportIgnore comma delimited string of files to ignore
+     * @param {Object} included an object used to track the files already imported
      */
-    function flattenCss(fileName, fileContents, cssImportIgnore) {
+    function flattenCss(fileName, fileContents, cssImportIgnore, included) {
         //Find the last slash in the name.
         fileName = fileName.replace(lang.backSlashRegExp, "/");
         var endIndex = fileName.lastIndexOf("/"),
             //Make a file path based on the last slash.
             //If no slash, so must be just a file name. Use empty string then.
-            filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "";
+            filePath = (endIndex !== -1) ? fileName.substring(0, endIndex + 1) : "",
+            //store a list of merged files
+            importList = [],
+            skippedList = [];
+
+        //First make a pass by removing an commented out @import calls.
+        fileContents = fileContents.replace(cssCommentImportRegExp, '');
 
         //Make sure we have a delimited ignore list to make matching faster
         if (cssImportIgnore && cssImportIgnore.charAt(cssImportIgnore.length - 1) !== ",") {
             cssImportIgnore += ",";
         }
 
-        return fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) {
+        fileContents = fileContents.replace(cssImportRegExp, function (fullMatch, urlStart, importFileName, urlEnd, mediaTypes) {
             //Only process media type "all" or empty media type rules.
             if (mediaTypes && ((mediaTypes.replace(/^\s\s*/, '').replace(/\s\s*$/, '')) !== "all")) {
+                skippedList.push(fileName);
                 return fullMatch;
             }
 
@@ -7404,10 +13159,24 @@
                 //and we will just skip that import.
                 var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName,
                     importContents = file.readFile(fullImportFileName), i,
-                    importEndIndex, importPath, fixedUrlMatch, colonIndex, parts;
+                    importEndIndex, importPath, fixedUrlMatch, colonIndex, parts, flat;
+
+                //Skip the file if it has already been included.
+                if (included[fullImportFileName]) {
+                    return '';
+                }
+                included[fullImportFileName] = true;
 
                 //Make sure to flatten any nested imports.
-                importContents = flattenCss(fullImportFileName, importContents);
+                flat = flattenCss(fullImportFileName, importContents, cssImportIgnore, included);
+                importContents = flat.fileContents;
+
+                if (flat.importList.length) {
+                    importList.push.apply(importList, flat.importList);
+                }
+                if (flat.skippedList.length) {
+                    skippedList.push.apply(skippedList, flat.skippedList);
+                }
 
                 //Make the full import path
                 importEndIndex = importFileName.lastIndexOf("/");
@@ -7415,6 +13184,9 @@
                 //Make a file path based on the last slash.
                 //If no slash, so must be just a file name. Use empty string then.
                 importPath = (importEndIndex !== -1) ? importFileName.substring(0, importEndIndex + 1) : "";
+
+                //fix url() on relative import (#5)
+                importPath = importPath.replace(/^\.\//, '');
 
                 //Modify URL paths to match the path represented by this file.
                 importContents = importContents.replace(cssUrlRegExp, function (fullMatch, urlMatch) {
@@ -7447,39 +13219,66 @@
                     return "url(" + parts.join("/") + ")";
                 });
 
+                importList.push(fullImportFileName);
                 return importContents;
             } catch (e) {
-                logger.trace(fileName + "\n  Cannot inline css import, skipping: " + importFileName);
+                logger.warn(fileName + "\n  Cannot inline css import, skipping: " + importFileName);
                 return fullMatch;
             }
         });
+
+        return {
+            importList : importList,
+            skippedList: skippedList,
+            fileContents : fileContents
+        };
     }
 
     optimize = {
-        licenseCommentRegExp: /\/\*[\s\S]*?\*\//g,
-
         /**
          * Optimizes a file that contains JavaScript content. Optionally collects
          * plugin resources mentioned in a file, and then passes the content
          * through an minifier if one is specified via config.optimize.
          *
          * @param {String} fileName the name of the file to optimize
+         * @param {String} fileContents the contents to optimize. If this is
+         * a null value, then fileName will be used to read the fileContents.
          * @param {String} outFileName the name of the file to use for the
          * saved optimized content.
          * @param {Object} config the build config object.
-         * @param {String} [moduleName] the module name to use for the file.
-         * Used for plugin resource collection.
          * @param {Array} [pluginCollector] storage for any plugin resources
          * found.
          */
-        jsFile: function (fileName, outFileName, config, moduleName, pluginCollector) {
-            var parts = (config.optimize + "").split('.'),
+        jsFile: function (fileName, fileContents, outFileName, config, pluginCollector) {
+            if (!fileContents) {
+                fileContents = file.readFile(fileName);
+            }
+
+            fileContents = optimize.js(fileName, fileContents, config, pluginCollector);
+
+            file.saveUtf8File(outFileName, fileContents);
+        },
+
+        /**
+         * Optimizes a file that contains JavaScript content. Optionally collects
+         * plugin resources mentioned in a file, and then passes the content
+         * through an minifier if one is specified via config.optimize.
+         *
+         * @param {String} fileName the name of the file that matches the
+         * fileContents.
+         * @param {String} fileContents the string of JS to optimize.
+         * @param {Object} [config] the build config object.
+         * @param {Array} [pluginCollector] storage for any plugin resources
+         * found.
+         */
+        js: function (fileName, fileContents, config, pluginCollector) {
+            var parts = (String(config.optimize)).split('.'),
                 optimizerName = parts[0],
                 keepLines = parts[1] === 'keepLines',
                 licenseContents = '',
-                fileContents, optFunc, match, comment;
-
-            fileContents = file.readFile(fileName);
+                optFunc;
+
+            config = config || {};
 
             //Apply pragmas/namespace renaming
             fileContents = pragma.process(fileName, fileContents, config, 'OnSave', pluginCollector);
@@ -7493,14 +13292,12 @@
                                     '" not found for this environment');
                 }
 
-                //Pull out any license comments for prepending after optimization.
-                optimize.licenseCommentRegExp.lastIndex = 0;
-                while ((match = optimize.licenseCommentRegExp.exec(fileContents))) {
-                    comment = match[0];
-                    //Only keep the comments if they are license comments.
-                    if (comment.indexOf('@license') !== -1 ||
-                        comment.indexOf('/*!') === 0) {
-                        licenseContents += comment + '\n';
+                if (config.preserveLicenseComments) {
+                    //Pull out any license comments for prepending after optimization.
+                    try {
+                        licenseContents = parse.getLicenseComments(fileName, fileContents);
+                    } catch (e) {
+                        logger.error('Cannot parse file: ' + fileName + ' for comments. Skipping it. Error is:\n' + e.toString());
                     }
                 }
 
@@ -7508,7 +13305,7 @@
                                         config[optimizerName]);
             }
 
-            file.saveUtf8File(outFileName, fileContents);
+            return fileContents;
         },
 
         /**
@@ -7520,21 +13317,43 @@
          * cssImportIgnore options.
          */
         cssFile: function (fileName, outFileName, config) {
+
             //Read in the file. Make sure we have a JS string.
             var originalFileContents = file.readFile(fileName),
-                fileContents = flattenCss(fileName, originalFileContents, config.cssImportIgnore),
-                startIndex, endIndex;
+                flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, {}),
+                //Do not use the flattened CSS if there was one that was skipped.
+                fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents,
+                startIndex, endIndex, buildText, comment;
+
+            if (flat.skippedList.length) {
+                logger.warn('Cannot inline @imports for ' + fileName +
+                            ',\nthe following files had media queries in them:\n' +
+                            flat.skippedList.join('\n'));
+            }
 
             //Do comment removal.
             try {
-                startIndex = -1;
-                //Get rid of comments.
-                while ((startIndex = fileContents.indexOf("/*")) !== -1) {
-                    endIndex = fileContents.indexOf("*/", startIndex + 2);
-                    if (endIndex === -1) {
-                        throw "Improper comment in CSS file: " + fileName;
+                if (config.optimizeCss.indexOf(".keepComments") === -1) {
+                    startIndex = 0;
+                    //Get rid of comments.
+                    while ((startIndex = fileContents.indexOf("/*", startIndex)) !== -1) {
+                        endIndex = fileContents.indexOf("*/", startIndex + 2);
+                        if (endIndex === -1) {
+                            throw "Improper comment in CSS file: " + fileName;
+                        }
+                        comment = fileContents.substring(startIndex, endIndex);
+
+                        if (config.preserveLicenseComments &&
+                            (comment.indexOf('license') !== -1 ||
+                             comment.indexOf('opyright') !== -1 ||
+                             comment.indexOf('(c)') !== -1)) {
+                            //Keep the comment, just increment the startIndex
+                            startIndex = endIndex;
+                        } else {
+                            fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length);
+                            startIndex = 0;
+                        }
                     }
-                    fileContents = fileContents.substring(0, startIndex) + fileContents.substring(endIndex + 2, fileContents.length);
                 }
                 //Get rid of newlines.
                 if (config.optimizeCss.indexOf(".keepLines") === -1) {
@@ -7553,6 +13372,14 @@
             }
 
             file.saveUtf8File(outFileName, fileContents);
+
+            //text output to stdout and/or written to build.txt file
+            buildText = "\n"+ outFileName.replace(config.dir, "") +"\n----------------\n";
+            flat.importList.push(fileName);
+            buildText += flat.importList.map(function(path){
+                return path.replace(config.dir, "");
+            }).join("\n");
+            return buildText +"\n";
         },
 
         /**
@@ -7563,38 +13390,50 @@
          * cssImportIgnore options.
          */
         css: function (startDir, config) {
+            var buildText = "",
+                i, fileName, fileList;
             if (config.optimizeCss.indexOf("standard") !== -1) {
-                var i, fileName,
-                    fileList = file.getFilteredFileList(startDir, /\.css$/, true);
+                fileList = file.getFilteredFileList(startDir, /\.css$/, true);
                 if (fileList) {
                     for (i = 0; i < fileList.length; i++) {
                         fileName = fileList[i];
                         logger.trace("Optimizing (" + config.optimizeCss + ") CSS file: " + fileName);
-                        optimize.cssFile(fileName, fileName, config);
+                        buildText += optimize.cssFile(fileName, fileName, config);
                     }
                 }
             }
+            return buildText;
         },
 
         optimizers: {
             uglify: function (fileName, fileContents, keepLines, config) {
                 var parser = uglify.parser,
                     processor = uglify.uglify,
-                    ast, genCodeConfig;
+                    ast, errMessage, errMatch;
 
                 config = config || {};
-                genCodeConfig = config.gen_codeOptions || keepLines;
 
                 logger.trace("Uglifying file: " + fileName);
 
                 try {
                     ast = parser.parse(fileContents, config.strict_semicolons);
-                    ast = processor.ast_mangle(ast, config.do_toplevel);
-                    ast = processor.ast_squeeze(ast, config.ast_squeezeOptions);
-
-                    fileContents = processor.gen_code(ast, genCodeConfig);
+                    if (config.no_mangle !== true) {
+                        ast = processor.ast_mangle(ast, config);
+                    }
+                    ast = processor.ast_squeeze(ast, config);
+
+                    fileContents = processor.gen_code(ast, config);
+
+                    if (config.max_line_length) {
+                        fileContents = processor.split_lines(fileContents, config.max_line_length);
+                    }
                 } catch (e) {
-                    logger.error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + e.toString());
+                    errMessage = e.toString();
+                    errMatch = /\nError(\r)?\n/.exec(errMessage);
+                    if (errMatch) {
+                        errMessage = errMessage.substring(0, errMatch.index);
+                    }
+                    logger.error('Cannot uglify file: ' + fileName + '. Skipping it. Error is:\n' + errMessage);
                 }
                 return fileContents;
             }
@@ -7602,7 +13441,8 @@
     };
 
     return optimize;
-});/**
+});
+/**
  * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
  * Available via the MIT or new BSD license.
  * see: http://github.com/jrburke/requirejs for details
@@ -7611,13 +13451,16 @@
  * This file patches require.js to communicate with the build system.
  */
 
-/*jslint nomen: false, plusplus: false, regexp: false, strict: false */
-/*global require: false, define: true */
+//Using sloppy since this uses eval for some code like plugins,
+//which may not be strict mode compliant. So if use strict is used
+//below they will have strict rules applied and may cause an error.
+/*jslint sloppy: true, nomen: true, plusplus: true, regexp: true */
+/*global require, define: true */
 
 //NOT asking for require as a dependency since the goal is to modify the
 //global require below
-define('requirePatch', [ 'env!env/file', 'pragma', 'parse'],
-function (file,           pragma,   parse) {
+define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs'],
+function (file,           pragma,   parse,   lang,   logger,   commonJs) {
 
     var allowRun = true;
 
@@ -7630,32 +13473,317 @@
 
         var layer,
             pluginBuilderRegExp = /(["']?)pluginBuilder(["']?)\s*[=\:]\s*["']([^'"\s]+)["']/,
+            oldNewContext = require.s.newContext,
             oldDef,
-            cachedFileContents = {};
-
-
-        /** Print out some extrs info about the module tree that caused the error. **/
-        require.onError = function (err) {
-
-            var msg = '\nIn module tree:\n',
-                standardIndent = '  ',
-                tree = err.moduleTree,
-                i, j, mod;
-
-            if (tree && tree.length > 0) {
-                for (i = tree.length - 1; i > -1 && (mod = tree[i]); i--) {
-                    for (j = tree.length - i; j > -1; j--) {
-                        msg += standardIndent;
+
+            //create local undefined values for module and exports,
+            //so that when files are evaled in this function they do not
+            //see the node values used for r.js
+            exports,
+            module;
+
+        //Stored cached file contents for reuse in other layers.
+        require._cachedFileContents = {};
+
+        /**
+         * Makes sure the URL is something that can be supported by the
+         * optimization tool.
+         * @param {String} url
+         * @returns {Boolean}
+         */
+        require._isSupportedBuildUrl = function (url) {
+            //Ignore URLs with protocols, hosts or question marks, means either network
+            //access is needed to fetch it or it is too dynamic. Note that
+            //on Windows, full paths are used for some urls, which include
+            //the drive, like c:/something, so need to test for something other
+            //than just a colon.
+            if (url.indexOf("://") === -1 && url.indexOf("?") === -1 &&
+                   url.indexOf('empty:') !== 0 && url.indexOf('//') !== 0) {
+                return true;
+            } else {
+                if (!layer.ignoredUrls[url]) {
+                    if (url.indexOf('empty:') === -1) {
+                        logger.info('Cannot optimize network URL, skipping: ' + url);
                     }
-                    msg += mod + '\n';
-                }
-
-                err = new Error(err.toString() + msg);
-            }
-
-            throw err;
-        };
-
+                    layer.ignoredUrls[url] = true;
+                }
+                return false;
+            }
+        };
+
+        function normalizeUrlWithBase(context, moduleName, url) {
+            //Adjust the URL if it was not transformed to use baseUrl.
+            if (require.jsExtRegExp.test(moduleName)) {
+                url = (context.config.dir || context.config.dirBaseUrl) + url;
+            }
+            return url;
+        }
+
+        //Overrides the new context call to add existing tracking features.
+        require.s.newContext = function (name) {
+            var context = oldNewContext(name),
+                oldEnable = context.enable,
+                moduleProto = context.Module.prototype,
+                oldInit = moduleProto.init,
+                oldCallPlugin = moduleProto.callPlugin;
+
+            //Only do this for the context used for building.
+            if (name === '_') {
+                context.needFullExec = {};
+                context.fullExec = {};
+                context.plugins = {};
+                context.buildShimExports = {};
+
+                //Override the shim exports function generator to just
+                //spit out strings that can be used in the stringified
+                //build output.
+                context.makeShimExports = function (exports) {
+                    var result;
+                    if (typeof exports === 'string') {
+                        result = function () {
+                            return '(function (global) {\n' +
+                            '    return function () {\n' +
+                            '        return global.' + exports + ';\n' +
+                            '    }\n' +
+                            '}(this))';
+                        };
+                        result.exports = exports;
+                    } else {
+                        result = function () {
+                            return '(function (global) {\n' +
+                            '    return function () {\n' +
+                            '        var func = ' + exports.toString() + ';\n' +
+                            '        return func.apply(global, arguments);\n' +
+                            '    }\n' +
+                            '}(this))';
+                        };
+                    }
+
+                    //Mark the result has being tranformed by the build already.
+                    result.__buildReady = true;
+                    return result;
+                };
+
+                context.enable = function (depMap, parent) {
+                    var id = depMap.id,
+                        parentId = parent && parent.map.id,
+                        needFullExec = context.needFullExec,
+                        fullExec = context.fullExec,
+                        mod = context.registry[id];
+
+                    if (mod && !mod.defined) {
+                        if (parentId && needFullExec[parentId]) {
+                            needFullExec[id] = true;
+                        }
+                    } else if ((needFullExec[id] && !fullExec[id]) ||
+                               (parentId && needFullExec[parentId] && !fullExec[id])) {
+                        context.undef(id);
+                    }
+
+                    return oldEnable.apply(context, arguments);
+                };
+
+                //Override load so that the file paths can be collected.
+                context.load = function (moduleName, url) {
+                    /*jslint evil: true */
+                    var contents, pluginBuilderMatch, builderName,
+                        shim, shimExports;
+
+                    //Do not mark the url as fetched if it is
+                    //not an empty: URL, used by the optimizer.
+                    //In that case we need to be sure to call
+                    //load() for each module that is mapped to
+                    //empty: so that dependencies are satisfied
+                    //correctly.
+                    if (url.indexOf('empty:') === 0) {
+                        delete context.urlFetched[url];
+                    }
+
+                    //Only handle urls that can be inlined, so that means avoiding some
+                    //URLs like ones that require network access or may be too dynamic,
+                    //like JSONP
+                    if (require._isSupportedBuildUrl(url)) {
+                        //Adjust the URL if it was not transformed to use baseUrl.
+                        url = normalizeUrlWithBase(context, moduleName, url);
+
+                        //Save the module name to path  and path to module name mappings.
+                        layer.buildPathMap[moduleName] = url;
+                        layer.buildFileToModule[url] = moduleName;
+
+                        if (context.plugins.hasOwnProperty(moduleName)) {
+                            //plugins need to have their source evaled as-is.
+                            context.needFullExec[moduleName] = true;
+                        }
+
+                        try {
+                            if (require._cachedFileContents.hasOwnProperty(url) &&
+                                (!context.needFullExec[moduleName] || context.fullExec[moduleName])) {
+                                contents = require._cachedFileContents[url];
+                            } else {
+                                //Load the file contents, process for conditionals, then
+                                //evaluate it.
+                                contents = file.readFile(url);
+
+                                if (context.config.cjsTranslate) {
+                                    contents = commonJs.convert(url, contents);
+                                }
+
+                                //If there is a read filter, run it now.
+                                if (context.config.onBuildRead) {
+                                    contents = context.config.onBuildRead(moduleName, url, contents);
+                                }
+
+                                contents = pragma.process(url, contents, context.config, 'OnExecute');
+
+                                //Find out if the file contains a require() definition. Need to know
+                                //this so we can inject plugins right after it, but before they are needed,
+                                //and to make sure this file is first, so that define calls work.
+                                //This situation mainly occurs when the build is done on top of the output
+                                //of another build, where the first build may include require somewhere in it.
+                                try {
+                                    if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
+                                        layer.existingRequireUrl = url;
+                                    }
+                                } catch (e1) {
+                                    throw new Error('Parse error using esprima ' +
+                                                    'for file: ' + url + '\n' + e1);
+                                }
+
+                                if (context.plugins.hasOwnProperty(moduleName)) {
+                                    //This is a loader plugin, check to see if it has a build extension,
+                                    //otherwise the plugin will act as the plugin builder too.
+                                    pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
+                                    if (pluginBuilderMatch) {
+                                        //Load the plugin builder for the plugin contents.
+                                        builderName = context.makeModuleMap(pluginBuilderMatch[3],
+                                                                            context.makeModuleMap(moduleName),
+                                                                            null,
+                                                                            true).id;
+                                        contents = file.readFile(context.nameToUrl(builderName));
+                                    }
+                                }
+
+                                //Parse out the require and define calls.
+                                //Do this even for plugins in case they have their own
+                                //dependencies that may be separate to how the pluginBuilder works.
+                                try {
+                                    if (!context.needFullExec[moduleName]) {
+                                        contents = parse(moduleName, url, contents, {
+                                            insertNeedsDefine: true,
+                                            has: context.config.has,
+                                            findNestedDependencies: context.config.findNestedDependencies
+                                        });
+                                    }
+                                } catch (e2) {
+                                    throw new Error('Parse error using esprima ' +
+                                                    'for file: ' + url + '\n' + e2);
+                                }
+
+                                require._cachedFileContents[url] = contents;
+                            }
+
+                            if (contents) {
+                                eval(contents);
+                            }
+
+                            try {
+                                //If have a string shim config, and this is
+                                //a fully executed module, try to see if
+                                //it created a variable in this eval scope
+                                if (context.needFullExec[moduleName]) {
+                                    shim = context.config.shim[moduleName];
+                                    if (shim && shim.exports && shim.exports.exports) {
+                                        shimExports = eval(shim.exports.exports);
+                                        if (typeof shimExports !== 'undefined') {
+                                            context.buildShimExports[moduleName] = shimExports;
+                                        }
+                                    }
+                                }
+
+                                //Need to close out completion of this module
+                                //so that listeners will get notified that it is available.
+                                context.completeLoad(moduleName);
+                            } catch (e) {
+                                //Track which module could not complete loading.
+                                if (!e.moduleTree) {
+                                    e.moduleTree = [];
+                                }
+                                e.moduleTree.push(moduleName);
+                                throw e;
+                            }
+
+                        } catch (eOuter) {
+                            if (!eOuter.fileName) {
+                                eOuter.fileName = url;
+                            }
+                            throw eOuter;
+                        }
+                    } else {
+                        //With unsupported URLs still need to call completeLoad to
+                        //finish loading.
+                        context.completeLoad(moduleName);
+                    }
+                };
+
+                //Marks module has having a name, and optionally executes the
+                //callback, but only if it meets certain criteria.
+                context.execCb = function (name, cb, args, exports) {
+                    var buildShimExports = layer.context.buildShimExports[name];
+
+                    if (!layer.needsDefine[name] && !buildShimExports) {
+                        layer.modulesWithNames[name] = true;
+                    }
+
+                    if (buildShimExports) {
+                        return buildShimExports;
+                    } else if (cb.__requireJsBuild || layer.context.needFullExec[name]) {
+                        return cb.apply(exports, args);
+                    }
+                    return undefined;
+                };
+
+                moduleProto.init = function(depMaps) {
+                    if (context.needFullExec[this.map.id]) {
+                        lang.each(depMaps, lang.bind(this, function (depMap) {
+                            if (typeof depMap === 'string') {
+                                depMap = context.makeModuleMap(depMap,
+                                               (this.map.isDefine ? this.map : this.map.parentMap));
+                            }
+
+                            if (!context.fullExec[depMap.id]) {
+                                context.undef(depMap.id);
+                            }
+                        }));
+                    }
+
+                    return oldInit.apply(this, arguments);
+                };
+
+                moduleProto.callPlugin = function () {
+                    var map = this.map,
+                        pluginMap = context.makeModuleMap(map.prefix),
+                        pluginId = pluginMap.id,
+                        pluginMod = context.registry[pluginId];
+
+                    context.plugins[pluginId] = true;
+                    context.needFullExec[pluginId] = true;
+
+                    //If the module is not waiting to finish being defined,
+                    //undef it and start over, to get full execution.
+                    if (!context.fullExec[pluginId] && (!pluginMod || pluginMod.defined)) {
+                        context.undef(pluginMap.id);
+                    }
+
+                    return oldCallPlugin.apply(this, arguments);
+                };
+            }
+
+            return context;
+        };
+
+        //Clear up the existing context so that the newContext modifications
+        //above will be active.
+        delete require.s.contexts._;
 
         /** Reset state for each build layer pass. */
         require._buildReset = function () {
@@ -7675,6 +13803,7 @@
                 modulesWithNames: {},
                 needsDefine: {},
                 existingRequireUrl: "",
+                ignoredUrls: {},
                 context: require.s.contexts._
             };
 
@@ -7685,31 +13814,15 @@
 
         require._buildReset();
 
-        /**
-         * Makes sure the URL is something that can be supported by the
-         * optimization tool.
-         * @param {String} url
-         * @returns {Boolean}
-         */
-        require._isSupportedBuildUrl = function (url) {
-            //Ignore URLs with protocols or question marks, means either network
-            //access is needed to fetch it or it is too dynamic. Note that
-            //on Windows, full paths are used for some urls, which include
-            //the drive, like c:/something, so need to test for something other
-            //than just a colon.
-            return url.indexOf("://") === -1 && url.indexOf("?") === -1 &&
-                   url.indexOf('empty:') !== 0;
-        };
-
         //Override define() to catch modules that just define an object, so that
         //a dummy define call is not put in the build file for them. They do
-        //not end up getting defined via require.execCb, so we need to catch them
+        //not end up getting defined via context.execCb, so we need to catch them
         //at the define call.
         oldDef = define;
 
         //This function signature does not have to be exact, just match what we
         //are looking for.
-        define = function (name, obj) {
+        define = function (name) {
             if (typeof name === "string" && !layer.needsDefine[name]) {
                 layer.modulesWithNames[name] = true;
             }
@@ -7724,139 +13837,37 @@
             return file.exists(path);
         };
 
-        function normalizeUrlWithBase(context, moduleName, url) {
-            //Adjust the URL if it was not transformed to use baseUrl.
-            if (require.jsExtRegExp.test(moduleName)) {
-                url = (context.config.dir || context.config.dirBaseUrl) + url;
-            }
-            return url;
-        }
-
-        //Override load so that the file paths can be collected.
-        require.load = function (context, moduleName, url) {
-            /*jslint evil: true */
-            var contents, pluginBuilderMatch, builderName;
-
-            //Adjust the URL if it was not transformed to use baseUrl.
-            url = normalizeUrlWithBase(context, moduleName, url);
-
-            context.scriptCount += 1;
-
-            //Only handle urls that can be inlined, so that means avoiding some
-            //URLs like ones that require network access or may be too dynamic,
-            //like JSONP
-            if (require._isSupportedBuildUrl(url)) {
-                //Save the module name to path  and path to module name mappings.
-                layer.buildPathMap[moduleName] = url;
-                layer.buildFileToModule[url] = moduleName;
-
-                if (moduleName in context.plugins) {
-                    //plugins need to have their source evaled as-is.
-                    context.needFullExec[moduleName] = true;
-                }
-
-                try {
-                    if (url in cachedFileContents &&
-                        (!context.needFullExec[moduleName] || context.fullExec[moduleName])) {
-                        contents = cachedFileContents[url];
-                    } else {
-                        //Load the file contents, process for conditionals, then
-                        //evaluate it.
-                        contents = file.readFile(url);
-                        contents = pragma.process(url, contents, context.config, 'OnExecute');
-
-                        //Find out if the file contains a require() definition. Need to know
-                        //this so we can inject plugins right after it, but before they are needed,
-                        //and to make sure this file is first, so that define calls work.
-                        //This situation mainly occurs when the build is done on top of the output
-                        //of another build, where the first build may include require somewhere in it.
-                        if (!layer.existingRequireUrl && parse.definesRequire(url, contents)) {
-                            layer.existingRequireUrl = url;
-                        }
-
-                        if (moduleName in context.plugins) {
-                            //This is a loader plugin, check to see if it has a build extension,
-                            //otherwise the plugin will act as the plugin builder too.
-                            pluginBuilderMatch = pluginBuilderRegExp.exec(contents);
-                            if (pluginBuilderMatch) {
-                                //Load the plugin builder for the plugin contents.
-                                builderName = context.normalize(pluginBuilderMatch[3], moduleName);
-                                contents = file.readFile(context.nameToUrl(builderName));
-                            }
-                        }
-
-                        //Parse out the require and define calls.
-                        //Do this even for plugins in case they have their own
-                        //dependencies that may be separate to how the pluginBuilder works.
-                        if (!context.needFullExec[moduleName]) {
-                            contents = parse(moduleName, url, contents, {
-                                insertNeedsDefine: true
-                            });
-                        }
-
-                        cachedFileContents[url] = contents;
-                    }
-
-                    if (contents) {
-                        eval(contents);
-                    }
-
-                    //Need to close out completion of this module
-                    //so that listeners will get notified that it is available.
-                    try {
-                        context.completeLoad(moduleName);
-                    } catch (e) {
-                        //Track which module could not complete loading.
-                        (e.moduleTree || (e.moduleTree = [])).push(moduleName);
-                        throw e;
-                    }
-
-                } catch (eOuter) {
-                    if (!eOuter.fileName) {
-                        eOuter.fileName = url;
-                    }
-                    throw eOuter;
-                }
-            } else {
-                //With unsupported URLs still need to call completeLoad to
-                //finish loading.
-                context.completeLoad(moduleName);
-            }
-
-            //Mark the module loaded.
-            context.loaded[moduleName] = true;
-        };
-
-
         //Called when execManager runs for a dependency. Used to figure out
         //what order of execution.
         require.onResourceLoad = function (context, map) {
-            var fullName = map.fullName,
+            var id = map.id,
                 url;
 
-            //Ignore "fake" modules, usually generated by plugin code, since
-            //they do not map back to a real file to include in the optimizer,
-            //or it will be included, but in a different form.
-            if (context.fake[fullName]) {
-                return;
+            //If build needed a full execution, indicate it
+            //has been done now. But only do it if the context is tracking
+            //that. Only valid for the context used in a build, not for
+            //other contexts being run, like for useLib, plain requirejs
+            //use in node/rhino.
+            if (context.needFullExec && context.needFullExec[id]) {
+                context.fullExec[id] = true;
             }
 
             //A plugin.
             if (map.prefix) {
-                if (!layer.pathAdded[fullName]) {
-                    layer.buildFilePaths.push(fullName);
+                if (!layer.pathAdded[id]) {
+                    layer.buildFilePaths.push(id);
                     //For plugins the real path is not knowable, use the name
                     //for both module to file and file to module mappings.
-                    layer.buildPathMap[fullName] = fullName;
-                    layer.buildFileToModule[fullName] = fullName;
-                    layer.modulesWithNames[fullName] = true;
-                    layer.pathAdded[fullName] = true;
+                    layer.buildPathMap[id] = id;
+                    layer.buildFileToModule[id] = id;
+                    layer.modulesWithNames[id] = true;
+                    layer.pathAdded[id] = true;
                 }
             } else if (map.url && require._isSupportedBuildUrl(map.url)) {
                 //If the url has not been added to the layer yet, and it
                 //is from an actual file that was loaded, add it now.
-                if (!layer.pathAdded[url] && layer.buildPathMap[fullName]) {
-                    url = normalizeUrlWithBase(context, map.fullName, map.url);
+                url = normalizeUrlWithBase(context, id, map.url);
+                if (!layer.pathAdded[url] && layer.buildPathMap[id]) {
                     //Remember the list of dependencies for this layer.
                     layer.buildFilePaths.push(url);
                     layer.pathAdded[url] = true;
@@ -7870,18 +13881,6 @@
         //ordering works correctly.
         require.needsDefine = function (moduleName) {
             layer.needsDefine[moduleName] = true;
-        };
-
-        //Marks module has having a name, and optionally executes the
-        //callback, but only if it meets certain criteria.
-        require.execCb = function (name, cb, args, exports) {
-            if (!layer.needsDefine[name]) {
-                layer.modulesWithNames[name] = true;
-            }
-            if (cb.__requireJsBuild || layer.context.needFullExec[name]) {
-                return cb.apply(exports, args);
-            }
-            return undefined;
         };
     };
 });
@@ -7891,19 +13890,12 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint plusplus: false, regexp: false, strict: false */
+/*jslint */
 /*global define: false, console: false */
 
-define('commonJs', ['env!env/file', 'uglifyjs/index'], function (file, uglify) {
+define('commonJs', ['env!env/file', 'parse'], function (file, parse) {
+    'use strict';
     var commonJs = {
-        depRegExp: /require\s*\(\s*["']([\w-_\.\/]+)["']\s*\)/g,
-
-        //Set this to false in non-rhino environments. If rhino, then it uses
-        //rhino's decompiler to remove comments before looking for require() calls,
-        //otherwise, it will use a crude regexp approach to remove comments. The
-        //rhino way is more robust, but he regexp is more portable across environments.
-        useRhino: true,
-
         //Set to false if you do not want this file to log. Useful in environments
         //like node where you want the work to happen without noise.
         useLog: true,
@@ -7937,7 +13929,8 @@
                     }
                 }
             } else {
-                for (i = 0; (fileName = fileList[i]); i++) {
+                for (i = 0; i < fileList.length; i++) {
+                    fileName = fileList[i];
                     convertedFileName = fileName.replace(commonJsPath, savePath);
 
                     //Handle JS files.
@@ -7954,80 +13947,38 @@
         },
 
         /**
-         * Removes the comments from a string.
-         *
-         * @param {String} fileContents
-         * @param {String} fileName mostly used for informative reasons if an error.
-         *
-         * @returns {String} a string of JS with comments removed.
-         */
-        removeComments: function (fileContents, fileName) {
-            //Uglify's ast generation removes comments, so just convert to ast,
-            //then back to source code to get rid of comments.
-            return uglify.uglify.gen_code(uglify.parser.parse(fileContents), true);
-        },
-
-        /**
-         * Regexp for testing if there is already a require.def call in the file,
-         * in which case do not try to convert it.
-         */
-        defRegExp: /define\s*\(\s*("|'|\[|function)/,
-
-        /**
-         * Regexp for testing if there is a require([]) or require(function(){})
-         * call, indicating the file is already in requirejs syntax.
-         */
-        rjsRegExp: /require\s*\(\s*(\[|function)/,
-
-        /**
          * Does the actual file conversion.
          *
          * @param {String} fileName the name of the file.
          *
          * @param {String} fileContents the contents of a file :)
          *
-         * @param {Boolean} skipDeps if true, require("") dependencies
-         * will not be searched, but the contents will just be wrapped in the
-         * standard require, exports, module dependencies. Only usable in sync
-         * environments like Node where the require("") calls can be resolved on
-         * the fly.
-         *
          * @returns {String} the converted contents
          */
-        convert: function (fileName, fileContents, skipDeps) {
+        convert: function (fileName, fileContents) {
             //Strip out comments.
             try {
-                var deps = [], depName, match,
-                    //Remove comments
-                    tempContents = commonJs.removeComments(fileContents, fileName);
+                var preamble = '',
+                    commonJsProps = parse.usesCommonJs(fileName, fileContents);
 
                 //First see if the module is not already RequireJS-formatted.
-                if (commonJs.defRegExp.test(tempContents) || commonJs.rjsRegExp.test(tempContents)) {
+                if (parse.usesAmdOrRequireJs(fileName, fileContents) || !commonJsProps) {
                     return fileContents;
                 }
 
-                //Reset the regexp to start at beginning of file. Do this
-                //since the regexp is reused across files.
-                commonJs.depRegExp.lastIndex = 0;
-
-                if (!skipDeps) {
-                    //Find dependencies in the code that was not in comments.
-                    while ((match = commonJs.depRegExp.exec(tempContents))) {
-                        depName = match[1];
-                        if (depName) {
-                            deps.push('"' + depName + '"');
-                        }
-                    }
+                if (commonJsProps.dirname || commonJsProps.filename) {
+                    preamble = 'var __filename = module.uri || "", ' +
+                               '__dirname = __filename.substring(0, __filename.lastIndexOf("/") + 1);\n';
                 }
 
                 //Construct the wrapper boilerplate.
-                fileContents = 'define(["require", "exports", "module"' +
-                       (deps.length ? ', ' + deps.join(",") : '') + '], ' +
-                       'function(require, exports, module) {\n' +
-                       fileContents +
-                       '\n});\n';
+                fileContents = 'define(function (require, exports, module) {\n' +
+                    preamble +
+                    fileContents +
+                    '\n});\n';
+
             } catch (e) {
-                console.log("COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e);
+                console.log("commonJs.convert: COULD NOT CONVERT: " + fileName + ", so skipping it. Error was: " + e);
                 return fileContents;
             }
 
@@ -8043,14 +13994,18 @@
  * see: http://github.com/jrburke/requirejs for details
  */
 
-/*jslint regexp: false, plusplus: false, nomen: false, strict: false  */
-/*global define: false, require: false */
+/*jslint plusplus: true, nomen: true, regexp: true  */
+/*global define, require */
 
 
 define('build', [ 'lang', 'logger', 'env!env/file', 'parse', 'optimize', 'pragma',
-         'env!env/load', 'requirePatch'],
+         'transform', 'env!env/load', 'requirePatch', 'env!env/quit',
+         'commonJs'],
 function (lang,   logger,   file,          parse,    optimize,   pragma,
-          load,           requirePatch) {
+          transform,   load,           requirePatch,   quit,
+          commonJs) {
+    'use strict';
+
     var build, buildBaseConfig,
         endsWithSemiColonRegExp = /;\s*$/;
 
@@ -8063,6 +14018,8 @@
             inlineText: true,
             isBuild: true,
             optimizeAllPluginResources: false,
+            findNestedDependencies: false,
+            preserveLicenseComments: true,
             //By default, all files/directories are copied, unless
             //they match this regexp, by default just excludes .folders
             dirExclusionRegExp: file.dirExclusionRegExp
@@ -8081,33 +14038,16 @@
         }
     }
 
-    /**
-     * If the path looks like an URL, throw an error. This is to prevent
-     * people from using URLs with protocols in the build config, since
-     * the optimizer is not set up to do network access. However, be
-     * sure to allow absolute paths on Windows, like C:\directory.
-     */
-    function disallowUrls(path) {
-        if (path.indexOf('://') !== -1 && path !== 'empty:') {
-            throw new Error('Path is not supported: ' + path +
-                            '\nOptimizer can only handle' +
-                            ' local paths. Download the locally if necessary' +
-                            ' and update the config to use a local path.\n' +
-                            'http://requirejs.org/docs/errors.html#pathnotsupported');
-        }
-    }
-
     function endsWithSlash(dirName) {
         if (dirName.charAt(dirName.length - 1) !== "/") {
             dirName += "/";
         }
-        disallowUrls(dirName);
         return dirName;
     }
 
     //Method used by plugin writeFile calls, defined up here to avoid
     //jslint warning about "making a function in a loop".
-    function makeWriteFile(anonDefRegExp, namespaceWithDot, layer) {
+    function makeWriteFile(namespace, layer) {
         function writeFile(name, contents) {
             logger.trace('Saving plugin-optimized file: ' + name);
             file.saveUtf8File(name, contents);
@@ -8115,7 +14055,7 @@
 
         writeFile.asModule = function (moduleName, fileName, contents) {
             writeFile(fileName,
-                build.toTransport(anonDefRegExp, namespaceWithDot, moduleName, fileName, contents, layer));
+                build.toTransport(namespace, moduleName, fileName, contents, layer));
         };
 
         return writeFile;
@@ -8138,31 +14078,83 @@
      * there is a problem completing the build.
      */
     build = function (args) {
-        var buildFile, cmdConfig;
-
-        if (!args || lang.isArray(args)) {
-            if (!args || args.length < 1) {
-                logger.error("build.js buildProfile.js\n" +
-                      "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file).");
-                return undefined;
-            }
-
-            //Next args can include a build file path as well as other build args.
-            //build file path comes first. If it does not contain an = then it is
-            //a build file path. Otherwise, just all build args.
-            if (args[0].indexOf("=") === -1) {
-                buildFile = args[0];
-                args.splice(0, 1);
-            }
-
-            //Remaining args are options to the build
-            cmdConfig = build.convertArrayToObject(args);
-            cmdConfig.buildFile = buildFile;
-        } else {
-            cmdConfig = args;
-        }
-
-        return build._run(cmdConfig);
+        var stackRegExp = /( {4}at[^\n]+)\n/,
+            standardIndent = '  ',
+            buildFile, cmdConfig, errorMsg, errorStack, stackMatch, errorTree,
+            i, j, errorMod;
+
+        try {
+            if (!args || lang.isArray(args)) {
+                if (!args || args.length < 1) {
+                    logger.error("build.js buildProfile.js\n" +
+                          "where buildProfile.js is the name of the build file (see example.build.js for hints on how to make a build file).");
+                    return undefined;
+                }
+
+                //Next args can include a build file path as well as other build args.
+                //build file path comes first. If it does not contain an = then it is
+                //a build file path. Otherwise, just all build args.
+                if (args[0].indexOf("=") === -1) {
+                    buildFile = args[0];
+                    args.splice(0, 1);
+                }
+
+                //Remaining args are options to the build
+                cmdConfig = build.convertArrayToObject(args);
+                cmdConfig.buildFile = buildFile;
+            } else {
+                cmdConfig = args;
+            }
+
+            return build._run(cmdConfig);
+        } catch (e) {
+            errorMsg = e.toString();
+            errorTree = e.moduleTree;
+            stackMatch = stackRegExp.exec(errorMsg);
+
+            if (stackMatch) {
+                errorMsg += errorMsg.substring(0, stackMatch.index + stackMatch[0].length + 1);
+            }
+
+            //If a module tree that shows what module triggered the error,
+            //print it out.
+            if (errorTree && errorTree.length > 0) {
+                errorMsg += '\nIn module tree:\n';
+
+                for (i = errorTree.length - 1; i > -1; i--) {
+                    errorMod = errorTree[i];
+                    if (errorMod) {
+                        for (j = errorTree.length - i; j > -1; j--) {
+                            errorMsg += standardIndent;
+                        }
+                        errorMsg += errorMod + '\n';
+                    }
+                }
+
+                logger.error(errorMsg);
+            }
+
+            errorStack = e.stack;
+
+            if (typeof args === 'string' && args.indexOf('stacktrace=true') !== -1) {
+                errorMsg += '\n' + errorStack;
+            } else {
+                if (!stackMatch && errorStack) {
+                    //Just trim out the first "at" in the stack.
+                    stackMatch = stackRegExp.exec(errorStack);
+                    if (stackMatch) {
+                        errorMsg += '\n' + stackMatch[0] || '';
+                    }
+                }
+            }
+
+            if (logger.level > logger.ERROR) {
+                throw new Error(errorMsg);
+            } else {
+                logger.error(errorMsg);
+                quit(1);
+            }
+        }
     };
 
     build._run = function (cmdConfig) {
@@ -8173,7 +14165,7 @@
             baseConfig, config,
             modules, builtModule, srcPath, buildContext,
             destPath, moduleName, moduleMap, parentModuleMap, context,
-            resources, resource, pluginProcessed = {}, plugin;
+            resources, resource, pluginProcessed = {}, plugin, fileContents;
 
         //Can now run the patches to require.js to allow it to be used for
         //build generation. Do it here instead of at the top of the module
@@ -8188,6 +14180,12 @@
             logger.logLevel(config.logLevel);
         }
 
+        //Remove the previous build dir, in case it contains source transforms,
+        //like the ones done with onBuildRead and onBuildWrite.
+        if (config.dir && !config.keepBuildDir && file.exists(config.dir)) {
+            file.deleteFile(config.dir);
+        }
+
         if (!config.out && !config.cssIn) {
             //This is not just a one-off file build but a full build profile, with
             //lots of files to process.
@@ -8198,35 +14196,45 @@
             //Adjust baseUrl if config.appDir is in play, and set up build output paths.
             buildPaths = {};
             if (config.appDir) {
-                //All the paths should be inside the appDir
-                buildPaths = paths;
+                //All the paths should be inside the appDir, so just adjust
+                //the paths to use the dirBaseUrl
+                for (prop in paths) {
+                    if (paths.hasOwnProperty(prop)) {
+                        buildPaths[prop] = paths[prop].replace(config.appDir, config.dir);
+                    }
+                }
             } else {
                 //If no appDir, then make sure to copy the other paths to this directory.
                 for (prop in paths) {
                     if (paths.hasOwnProperty(prop)) {
-                        //Set up build path for each path prefix.
-                        buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop.replace(/\./g, "/");
-
-                        //Make sure source path is fully formed with baseUrl,
-                        //if it is a relative URL.
-                        srcPath = paths[prop];
-                        if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
-                            srcPath = config.baseUrl + srcPath;
-                        }
-
-                        destPath = config.dirBaseUrl + buildPaths[prop];
-
-                        //Skip empty: paths
-                        if (srcPath !== 'empty:') {
-                            //If the srcPath is a directory, copy the whole directory.
-                            if (file.exists(srcPath) && file.isDirectory(srcPath)) {
-                                //Copy files to build area. Copy all files (the /\w/ regexp)
-                                file.copyDir(srcPath, destPath, /\w/, true);
-                            } else {
-                                //Try a .js extension
-                                srcPath += '.js';
-                                destPath += '.js';
-                                file.copyFile(srcPath, destPath);
+                        //Set up build path for each path prefix, but only do so
+                        //if the path falls out of the current baseUrl
+                        if (paths[prop].indexOf(config.baseUrl) === 0) {
+                            buildPaths[prop] = paths[prop].replace(config.baseUrl, config.dirBaseUrl);
+                        } else {
+                            buildPaths[prop] = paths[prop] === 'empty:' ? 'empty:' : prop.replace(/\./g, "/");
+
+                            //Make sure source path is fully formed with baseUrl,
+                            //if it is a relative URL.
+                            srcPath = paths[prop];
+                            if (srcPath.indexOf('/') !== 0 && srcPath.indexOf(':') === -1) {
+                                srcPath = config.baseUrl + srcPath;
+                            }
+
+                            destPath = config.dirBaseUrl + buildPaths[prop];
+
+                            //Skip empty: paths
+                            if (srcPath !== 'empty:') {
+                                //If the srcPath is a directory, copy the whole directory.
+                                if (file.exists(srcPath) && file.isDirectory(srcPath)) {
+                                    //Copy files to build area. Copy all files (the /\w/ regexp)
+                                    file.copyDir(srcPath, destPath, /\w/, true);
+                                } else {
+                                    //Try a .js extension
+                                    srcPath += '.js';
+                                    destPath += '.js';
+                                    file.copyFile(srcPath, destPath);
+                                }
                             }
                         }
                     }
@@ -8268,7 +14276,8 @@
             //Just set up the _buildPath for the module layer.
             require(config);
             if (!config.cssIn) {
-                config.modules[0]._buildPath = config.out;
+                config.modules[0]._buildPath = typeof config.out === 'function' ?
+                                               'FUNCTION' : config.out;
             }
         } else if (!config.cssIn) {
             //Now set up the config for require to use the build area, and calculate the
@@ -8297,7 +14306,7 @@
         //things like text loader plugins loading CSS to get the optimized
         //CSS.
         if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) {
-            optimize.css(config.dir, config);
+            buildFileContents += optimize.css(config.dir, config);
         }
 
         if (modules) {
@@ -8349,27 +14358,91 @@
 
                 //Flatten them and collect the build output for each module.
                 builtModule = build.flattenModule(module, module.layer, config);
-                file.saveUtf8File(module._buildPath, builtModule.text);
+
+                //Save it to a temp file for now, in case there are other layers that
+                //contain optimized content that should not be included in later
+                //layer optimizations. See issue #56.
+                if (module._buildPath === 'FUNCTION') {
+                    module._buildText = builtModule.text;
+                } else {
+                    file.saveUtf8File(module._buildPath + '-temp', builtModule.text);
+                }
                 buildFileContents += builtModule.buildText;
             });
+
+            //Now move the build layers to their final position.
+            modules.forEach(function (module) {
+                var finalPath = module._buildPath;
+                if (finalPath !== 'FUNCTION') {
+                    if (file.exists(finalPath)) {
+                        file.deleteFile(finalPath);
+                    }
+                    file.renameFile(finalPath + '-temp', finalPath);
+
+                    //And finally, if removeCombined is specified, remove
+                    //any of the files that were used in this layer.
+                    //Be sure not to remove other build layers.
+                    if (config.removeCombined) {
+                        module.layer.buildFilePaths.forEach(function (path) {
+                            if (file.exists(path) && !modules.some(function (mod) {
+                                return mod._buildPath === path;
+                            })) {
+                                file.deleteFile(path);
+                            }
+                        });
+                    }
+                }
+            });
+        }
+
+        //If removeCombined in play, remove any empty directories that
+        //may now exist because of its use
+        if (config.removeCombined && !config.out && config.dir) {
+            file.deleteEmptyDirs(config.dir);
         }
 
         //Do other optimizations.
         if (config.out && !config.cssIn) {
             //Just need to worry about one JS file.
             fileName = config.modules[0]._buildPath;
-            optimize.jsFile(fileName, fileName, config);
+            if (fileName === 'FUNCTION') {
+                config.modules[0]._buildText = optimize.js(fileName,
+                                                           config.modules[0]._buildText,
+                                                           config);
+            } else {
+                optimize.jsFile(fileName, null, fileName, config);
+            }
         } else if (!config.cssIn) {
             //Normal optimizations across modules.
 
             //JS optimizations.
             fileNames = file.getFilteredFileList(config.dir, /\.js$/, true);
-            for (i = 0; (fileName = fileNames[i]); i++) {
+            for (i = 0; i < fileNames.length; i++) {
+                fileName = fileNames[i];
+
                 //Generate the module name from the config.dir root.
                 moduleName = fileName.replace(config.dir, '');
                 //Get rid of the extension
                 moduleName = moduleName.substring(0, moduleName.length - 3);
-                optimize.jsFile(fileName, fileName, config, moduleName, pluginCollector);
+
+                //Convert the file to transport format, but without a name
+                //inserted (by passing null for moduleName) since the files are
+                //standalone, one module per file.
+                fileContents = file.readFile(fileName);
+
+                //For builds, if wanting cjs translation, do it now, so that
+                //the individual modules can be loaded cross domain via
+                //plain script tags.
+                if (config.cjsTranslate) {
+                    fileContents = commonJs.convert(fileName, fileContents);
+                }
+
+                fileContents = build.toTransport(config.namespace,
+                                                 null,
+                                                 fileName,
+                                                 fileContents);
+
+                optimize.jsFile(fileName, fileContents, fileName, config, pluginCollector);
             }
 
             //Normalize all the plugin resources.
@@ -8379,7 +14452,8 @@
                 if (pluginCollector.hasOwnProperty(moduleName)) {
                     parentModuleMap = context.makeModuleMap(moduleName);
                     resources = pluginCollector[moduleName];
-                    for (i = 0; (resource = resources[i]); i++) {
+                    for (i = 0; i < resources.length; i++) {
+                        resource = resources[i];
                         moduleMap = context.makeModuleMap(resource, parentModuleMap);
                         if (!context.plugins[moduleMap.prefix]) {
                             //Set the value in context.plugins so it
@@ -8403,7 +14477,7 @@
                         //Only bother with plugin resources that can be handled
                         //processed by the plugin, via support of the writeFile
                         //method.
-                        if (!pluginProcessed[moduleMap.fullName]) {
+                        if (!pluginProcessed[moduleMap.id]) {
                             //Only do the work if the plugin was really loaded.
                             //Using an internal access because the file may
                             //not really be loaded.
@@ -8414,14 +14488,13 @@
                                     moduleMap.name,
                                     require,
                                     makeWriteFile(
-                                        config.anonDefRegExp,
-                                        config.namespaceWithDot
+                                        config.namespace
                                     ),
                                     context.config
                                 );
                             }
 
-                            pluginProcessed[moduleMap.fullName] = true;
+                            pluginProcessed[moduleMap.id] = true;
                         }
                     }
 
@@ -8437,7 +14510,11 @@
 
         //If just have one CSS file to optimize, do that here.
         if (config.cssIn) {
-            optimize.cssFile(config.cssIn, config.out, config);
+            buildFileContents += optimize.cssFile(config.cssIn, config.out, config);
+        }
+
+        if (typeof config.out === 'function') {
+            config.out(config.modules[0]._buildText);
         }
 
         //Print out what was built into which layers.
@@ -8455,13 +14532,43 @@
      * name = paths.foo and value = ../some/path, so it assumes the
      * name=value splitting has already happened.
      */
-    function stringDotToObj(result, prop, name, value) {
-        if (!result[prop]) {
-            result[prop] = {};
-        }
-        name = name.substring((prop + '.').length, name.length);
-        result[prop][name] = value;
-    }
+    function stringDotToObj(result, name, value) {
+        var parts = name.split('.'),
+            prop = parts[0];
+
+        parts.forEach(function (prop, i) {
+            if (i === parts.length - 1) {
+                result[prop] = value;
+            } else {
+                if (!result[prop]) {
+                    result[prop] = {};
+                }
+                result = result[prop];
+            }
+
+        });
+    }
+
+    //Used by convertArrayToObject to convert some things from prop.name=value
+    //to a prop: { name: value}
+    build.dotProps = [
+        'paths.',
+        'wrap.',
+        'pragmas.',
+        'pragmasOnSave.',
+        'has.',
+        'hasOnSave.',
+        'wrap.',
+        'uglify.',
+        'closure.',
+        'map.'
+    ];
+
+    build.hasDotPropMatch = function (prop) {
+        return build.dotProps.some(function (dotProp) {
+            return prop.indexOf(dotProp) === 0;
+        });
+    };
 
     /**
      * Converts an array that has String members of "name=value"
@@ -8476,7 +14583,8 @@
             needArray = {
                 "include": true,
                 "exclude": true,
-                "excludeShallow": true
+                "excludeShallow": true,
+                "insertRequire": true
             };
 
         for (i = 0; i < ary.length; i++) {
@@ -8499,8 +14607,8 @@
                 value = value.split(",");
             }
 
-            if (prop.indexOf("paths.") === 0 || prop.indexOf("wrap.") === 0) {
-                stringDotToObj(result, prop.split('.')[0], prop, value);
+            if (build.hasDotPropMatch(prop)) {
+                stringDotToObj(result, prop, value);
             } else {
                 result[prop] = value;
             }
@@ -8519,6 +14627,87 @@
         }
         return path.replace(lang.backSlashRegExp, '/');
     };
+
+    build.makeAbsObject = function (props, obj, absFilePath) {
+        var i, prop;
+        if (obj) {
+            for (i = 0; i < props.length; i++) {
+                prop = props[i];
+                if (obj.hasOwnProperty(prop) && typeof obj[prop] === 'string') {
+                    obj[prop] = build.makeAbsPath(obj[prop], absFilePath);
+                }
+            }
+        }
+    };
+
+    /**
+     * For any path in a possible config, make it absolute relative
+     * to the absFilePath passed in.
+     */
+    build.makeAbsConfig = function (config, absFilePath) {
+        var props, prop, i;
+
+        props = ["appDir", "dir", "baseUrl"];
+        for (i = 0; i < props.length; i++) {
+            prop = props[i];
+
+            if (config[prop]) {
+                //Add abspath if necessary, make sure these paths end in
+                //slashes
+                if (prop === "baseUrl") {
+                    config.originalBaseUrl = config.baseUrl;
+                    if (config.appDir) {
+                        //If baseUrl with an appDir, the baseUrl is relative to
+                        //the appDir, *not* the absFilePath. appDir and dir are
+                        //made absolute before baseUrl, so this will work.
+                        config.baseUrl = build.makeAbsPath(config.originalBaseUrl, config.appDir);
+                    } else {
+                        //The dir output baseUrl is same as regular baseUrl, both
+                        //relative to the absFilePath.
+                        config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
+                    }
+                } else {
+                    config[prop] = build.makeAbsPath(config[prop], absFilePath);
+                }
+
+                config[prop] = endsWithSlash(config[prop]);
+            }
+        }
+
+        build.makeAbsObject(["out", "cssIn"], config, absFilePath);
+        build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath);
+    };
+
+    build.nestedMix = {
+        paths: true,
+        has: true,
+        hasOnSave: true,
+        pragmas: true,
+        pragmasOnSave: true
+    };
+
+    /**
+     * Mixes additional source config into target config, and merges some
+     * nested config, like paths, correctly.
+     */
+    function mixConfig(target, source) {
+        var prop, value;
+
+        for (prop in source) {
+            if (source.hasOwnProperty(prop)) {
+                //If the value of the property is a plain object, then
+                //allow a one-level-deep mixing of it.
+                value = source[prop];
+                if (typeof value === 'object' && value &&
+                    !lang.isArray(value) && !lang.isFunction(value) &&
+                    !lang.isRegExp(value)) {
+                    target[prop] = lang.mixin({}, target[prop], value, true);
+                } else {
+                    target[prop] = value;
+                }
+            }
+        }
+    }
 
     /**
      * Creates a config object for an optimization build.
@@ -8533,13 +14722,16 @@
      */
     build.createConfig = function (cfg) {
         /*jslint evil: true */
-        var config = {}, buildFileContents, buildFileConfig,
-            paths, props, i, prop, buildFile, absFilePath, originalBaseUrl;
+        var config = {}, buildFileContents, buildFileConfig, mainConfig,
+            mainConfigFile, mainConfigPath, prop, buildFile, absFilePath;
+
+        //Make sure all paths are relative to current directory.
+        absFilePath = file.absPath('.');
+        build.makeAbsConfig(cfg, absFilePath);
+        build.makeAbsConfig(buildBaseConfig, absFilePath);
 
         lang.mixin(config, buildBaseConfig);
         lang.mixin(config, cfg, true);
-
-        absFilePath = file.absPath('.');
 
         if (config.buildFile) {
             //A build file exists, load it to get more config.
@@ -8552,45 +14744,162 @@
             }
 
             absFilePath = config.baseUrl = file.absPath(file.parent(buildFile));
-            config.dir = config.baseUrl + "/build/";
 
             //Load build file options.
             buildFileContents = file.readFile(buildFile);
             try {
                 buildFileConfig = eval("(" + buildFileContents + ")");
+                build.makeAbsConfig(buildFileConfig, absFilePath);
+
+                //Mix in the config now so that items in mainConfigFile can
+                //be resolved relative to them if necessary, like if appDir
+                //is set here, but the baseUrl is in mainConfigFile. Will
+                //re-mix in the same build config later after mainConfigFile
+                //is processed, since build config should take priority.
+                mixConfig(config, buildFileConfig);
             } catch (e) {
                 throw new Error("Build file " + buildFile + " is malformed: " + e);
             }
-            lang.mixin(config, buildFileConfig, true);
-
-            //Re-apply the override config values, things like command line
-            //args should take precedence over build file values.
-            lang.mixin(config, cfg, true);
-        } else if (config.cssIn) {
-            if (!config.out) {
-                throw new Error("ERROR: 'out' option missing.");
+        }
+
+        mainConfigFile = config.mainConfigFile || (buildFileConfig && buildFileConfig.mainConfigFile);
+        if (mainConfigFile) {
+            mainConfigFile = build.makeAbsPath(mainConfigFile, absFilePath);
+            if (!file.exists(mainConfigFile)) {
+                throw new Error(mainConfigFile + ' does not exist.');
+            }
+            try {
+                mainConfig = parse.findConfig(mainConfigFile, file.readFile(mainConfigFile));
+            } catch (configError) {
+                throw new Error('The config in mainConfigFile ' +
+                        mainConfigFile +
+                        ' cannot be used because it cannot be evaluated' +
+                        ' correctly while running in the optimizer. Try only' +
+                        ' using a config that is also valid JSON, or do not use' +
+                        ' mainConfigFile and instead copy the config values needed' +
+                        ' into a build file or command line arguments given to the optimizer.');
+            }
+            if (mainConfig) {
+                mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/'));
+
+                //Add in some existing config, like appDir, since they can be
+                //used inside the mainConfigFile -- paths and baseUrl are
+                //relative to them.
+                if (config.appDir && !mainConfig.appDir) {
+                    mainConfig.appDir = config.appDir;
+                }
+
+                //If no baseUrl, then use the directory holding the main config.
+                if (!mainConfig.baseUrl) {
+                    mainConfig.baseUrl = mainConfigPath;
+                }
+
+                build.makeAbsConfig(mainConfig, mainConfigPath);
+                mixConfig(config, mainConfig);
+            }
+        }
+
+        //Mix in build file config, but only after mainConfig has been mixed in.
+        if (buildFileConfig) {
+            mixConfig(config, buildFileConfig);
+        }
+
+        //Re-apply the override config values. Command line
+        //args should take precedence over build file values.
+        mixConfig(config, cfg);
+
+        //Fix paths to full paths so that they can be adjusted consistently
+        //lately to be in the output area.
+        lang.eachProp(config.paths, function (value, prop) {
+            if (lang.isArray(value)) {
+                throw new Error('paths fallback not supported in optimizer. ' +
+                                'Please provide a build config path override ' +
+                                'for ' + prop);
+            }
+            config.paths[prop] = build.makeAbsPath(value, config.baseUrl);
+        });
+
+        //Set final output dir
+        if (config.hasOwnProperty("baseUrl")) {
+            if (config.appDir) {
+                config.dirBaseUrl = build.makeAbsPath(config.originalBaseUrl, config.dir);
             } else {
-                config.out = config.out.replace(lang.backSlashRegExp, "/");
-            }
-        }
-
+                config.dirBaseUrl = config.dir || config.baseUrl;
+            }
+            //Make sure dirBaseUrl ends in a slash, since it is
+            //concatenated with other strings.
+            config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
+        }
+
+        //Check for errors in config
+        if (config.main) {
+            throw new Error('"main" passed as an option, but the ' +
+                            'supported option is called "name".');
+        }
+        if (!config.name && !config.modules && !config.include && !config.cssIn) {
+            throw new Error('Missing either a "name", "include" or "modules" ' +
+                            'option');
+        }
+        if (config.cssIn && !config.out) {
+            throw new Error("ERROR: 'out' option missing.");
+        }
         if (!config.cssIn && !config.baseUrl) {
-            throw new Error("ERROR: 'baseUrl' option missing.");
-        }
-
-        if (config.out && !config.cssIn) {
-            //Just one file to optimize.
-
-            //Set up dummy module layer to build.
+            //Just use the current directory as the baseUrl
+            config.baseUrl = './';
+        }
+        if (!config.out && !config.dir) {
+            throw new Error('Missing either an "out" or "dir" config value. ' +
+                            'If using "appDir" for a full project optimization, ' +
+                            'use "dir". If you want to optimize to one file, ' +
+                            'use "out".');
+        }
+        if (config.appDir && config.out) {
+            throw new Error('"appDir" is not compatible with "out". Use "dir" ' +
+                            'instead. appDir is used to copy whole projects, ' +
+                            'where "out" is used to just optimize to one file.');
+        }
+        if (config.out && config.dir) {
+            throw new Error('The "out" and "dir" options are incompatible.' +
+                            ' Use "out" if you are targeting a single file for' +
+                            ' for optimization, and "dir" if you want the appDir' +
+                            ' or baseUrl directories optimized.');
+        }
+
+        if (config.insertRequire && !lang.isArray(config.insertRequire)) {
+            throw new Error('insertRequire should be a list of module IDs' +
+                            ' to insert in to a require([]) call.');
+        }
+
+        if ((config.name || config.include) && !config.modules) {
+            //Just need to build one file, but may be part of a whole appDir/
+            //baseUrl copy, but specified on the command line, so cannot do
+            //the modules array setup. So create a modules section in that
+            //case.
             config.modules = [
                 {
                     name: config.name,
                     out: config.out,
+                    create: config.create,
                     include: config.include,
                     exclude: config.exclude,
-                    excludeShallow: config.excludeShallow
+                    excludeShallow: config.excludeShallow,
+                    insertRequire: config.insertRequire
                 }
             ];
+        } else if (config.modules && config.out) {
+            throw new Error('If the "modules" option is used, then there ' +
+                            'should be a "dir" option set and "out" should ' +
+                            'not be used since "out" is only for single file ' +
+                            'optimization output.');
+        } else if (config.modules && config.name) {
+            throw new Error('"name" and "modules" options are incompatible. ' +
+                            'Either use "name" if doing a single file ' +
+                            'optimization, or "modules" if you want to target ' +
+                            'more than one file for optimization.');
+        }
+
+        if (config.out && !config.cssIn) {
+            //Just one file to optimize.
 
             //Does not have a build file, so set up some defaults.
             //Optimizing CSS should not be allowed, unless explicitly
@@ -8601,58 +14910,13 @@
             }
         }
 
-        //Adjust the path properties as appropriate.
-        //First make sure build paths use front slashes and end in a slash,
-        //and make sure they are aboslute paths.
-        props = ["appDir", "dir", "baseUrl"];
-        for (i = 0; (prop = props[i]); i++) {
-            if (config[prop]) {
-                config[prop] = config[prop].replace(lang.backSlashRegExp, "/");
-
-                //Add abspath if necessary.
-                if (prop === "baseUrl") {
-                    originalBaseUrl = config.baseUrl;
-                    if (config.appDir) {
-                        //If baseUrl with an appDir, the baseUrl is relative to
-                        //the appDir, *not* the absFilePath. appDir and dir are
-                        //made absolute before baseUrl, so this will work.
-                        config.baseUrl = build.makeAbsPath(originalBaseUrl, config.appDir);
-                        //Set up dir output baseUrl.
-                        config.dirBaseUrl = build.makeAbsPath(originalBaseUrl, config.dir);
-                    } else {
-                        //The dir output baseUrl is same as regular baseUrl, both
-                        //relative to the absFilePath.
-                        config.baseUrl = build.makeAbsPath(config[prop], absFilePath);
-                        config.dirBaseUrl = config.dir || config.baseUrl;
-                    }
-
-                    //Make sure dirBaseUrl ends in a slash, since it is
-                    //concatenated with other strings.
-                    config.dirBaseUrl = endsWithSlash(config.dirBaseUrl);
-                } else {
-                    config[prop] = build.makeAbsPath(config[prop], absFilePath);
-                }
-
-                config[prop] = endsWithSlash(config[prop]);
-            }
-        }
-
-        //Do not allow URLs for paths resources.
-        if (config.paths) {
-            for (prop in config.paths) {
-                if (config.paths.hasOwnProperty(prop)) {
-                    config.paths[prop] = config.paths[prop].replace(lang.backSlashRegExp, "/");
-                    disallowUrls(config.paths[prop]);
-                }
-            }
-        }
-
-        //Make sure some other paths are absolute.
-        props = ["out", "cssIn"];
-        for (i = 0; (prop = props[i]); i++) {
-            if (config[prop]) {
-                config[prop] = build.makeAbsPath(config[prop], absFilePath);
-            }
+        //Create a hash lookup for the stubModules config to make lookup
+        //cheaper later.
+        if (config.stubModules) {
+            config.stubModules._byName = {};
+            config.stubModules.forEach(function (id) {
+                config.stubModules._byName[id] = true;
+            });
         }
 
         //Get any wrap text.
@@ -8676,12 +14940,6 @@
                             'startFile/endFile: ' + wrapError.toString());
         }
 
-
-        //Set up proper info for namespaces and using namespaces in transport
-        //wrappings.
-        config.namespaceWithDot = config.namespace ? config.namespace + '.' : '';
-        config.anonDefRegExp = build.makeAnonDefRegExp(config.namespaceWithDot);
-
         //Do final input verification
         if (config.context) {
             throw new Error('The build argument "context" is not supported' +
@@ -8690,14 +14948,23 @@
         }
 
         //Set file.fileExclusionRegExp if desired
-        if ('fileExclusionRegExp' in config) {
-            file.exclusionRegExp = config.fileExclusionRegExp;
-        } else if ('dirExclusionRegExp' in config) {
+        if (config.hasOwnProperty('fileExclusionRegExp')) {
+            if (typeof config.fileExclusionRegExp === "string") {
+                file.exclusionRegExp = new RegExp(config.fileExclusionRegExp);
+            } else {
+                file.exclusionRegExp = config.fileExclusionRegExp;
+            }
+        } else if (config.hasOwnProperty('dirExclusionRegExp')) {
             //Set file.dirExclusionRegExp if desired, this is the old
             //name for fileExclusionRegExp before 1.0.2. Support for backwards
             //compatibility
             file.exclusionRegExp = config.dirExclusionRegExp;
         }
+
+        //Remove things that may cause problems in the build.
+        delete config.jQuery;
+        delete config.enforceDefine;
+        delete config.urlArgs;
 
         return config;
     };
@@ -8711,7 +14978,8 @@
      */
     build.findBuildModule = function (moduleName, modules) {
         var i, module;
-        for (i = 0; (module = modules[i]); i++) {
+        for (i = 0; i < modules.length; i++) {
+            module = modules[i];
             if (module.name === moduleName) {
                 return module;
             }
@@ -8731,10 +14999,6 @@
         if (index !== -1) {
             layer.buildFilePaths.splice(index, 1);
         }
-
-        //Take it out of the specified modules. Specified modules are mostly
-        //used to find require modifiers.
-        delete layer.specified[module];
     };
 
     /**
@@ -8748,7 +15012,16 @@
      * be in the flattened module.
      */
     build.traceDependencies = function (module, config) {
-        var include, override, layer, context, baseConfig, oldContext;
+        var include, override, layer, context, baseConfig, oldContext,
+            registry, id, idParts, pluginId,
+            errMessage = '',
+            failedPluginMap = {},
+            failedPluginIds = [],
+            errIds = [],
+            errUrlMap = {},
+            errUrlConflicts = {},
+            hasErrUrl = false,
+            errUrl, prop;
 
         //Reset some state set up in requirePatch.js, and clean up require's
         //current context.
@@ -8764,7 +15037,7 @@
         //WARNING: probably not robust for paths and packages/packagePaths,
         //since those property's objects can be modified. But for basic
         //config clone it works out.
-        require(lang.delegate(baseConfig));
+        require(lang.mixin({}, baseConfig, true));
 
         logger.trace("\nTracing dependencies for: " + (module.name || module.out));
         include = module.name && !module.create ? [module.name] : [];
@@ -8774,20 +15047,75 @@
 
         //If there are overrides to basic config, set that up now.;
         if (module.override) {
-            override = lang.delegate(baseConfig);
+            override = lang.mixin({}, baseConfig, true);
             lang.mixin(override, module.override, true);
             require(override);
         }
 
         //Figure out module layer dependencies by calling require to do the work.
         require(include);
-
-        //Pull out the layer dependencies.
-        layer.specified = context.specified;
 
         //Reset config
         if (module.override) {
             require(baseConfig);
+        }
+
+        //Check to see if it all loaded. If not, then stop, and give
+        //a message on what is left.
+        registry = context.registry;
+        for (id in registry) {
+            if (registry.hasOwnProperty(id) && id.indexOf('_@r') !== 0) {
+                if (id.indexOf('_unnormalized') === -1 && registry[id].enabled) {
+                    errIds.push(id);
+                    errUrl = registry[id].map.url;
+
+                    if (errUrlMap[errUrl]) {
+                        hasErrUrl = true;
+                        //This error module has the same URL as another
+                        //error module, could be misconfiguration.
+                        if (!errUrlConflicts[errUrl]) {
+                            errUrlConflicts[errUrl] = [];
+                            //Store the original module that had the same URL.
+                            errUrlConflicts[errUrl].push(errUrlMap[errUrl]);
+                        }
+                        errUrlConflicts[errUrl].push(id);
+                    } else {
+                        errUrlMap[errUrl] = id;
+                    }
+                }
+
+                //Look for plugins that did not call load()
+                idParts = id.split('!');
+                pluginId = idParts[0];
+                if (idParts.length > 1 && !failedPluginMap.hasOwnProperty(pluginId)) {
+                    failedPluginIds.push(pluginId);
+                    failedPluginMap[pluginId] = true;
+                }
+            }
+        }
+
+        if (errIds.length || failedPluginIds.length) {
+            if (failedPluginIds.length) {
+                errMessage += 'Loader plugin' +
+                (failedPluginIds.length === 1 ? '' : 's') +
+                ' did not call ' +
+                'the load callback in the build: ' +
+                failedPluginIds.join(', ') + '\n';
+            }
+            errMessage += 'Module loading did not complete for: ' + errIds.join(', ');
+
+            if (hasErrUrl) {
+                errMessage += '\nThe following modules share the same URL. This ' +
+                              'could be a misconfiguration if that URL only has ' +
+                              'one anonymous module in it:';
+                for (prop in errUrlConflicts) {
+                    if (errUrlConflicts.hasOwnProperty(prop)) {
+                        errMessage += '\n' + prop + ': ' +
+                                      errUrlConflicts[prop].join(', ');
+                    }
+                }
+            }
+            throw new Error(errMessage);
         }
 
         return layer;
@@ -8808,19 +15136,22 @@
      * included in the flattened module text.
      */
     build.flattenModule = function (module, layer, config) {
+
+        //Use override settings, particularly for pragmas
+        //Do this before the var readings since it reads config values.
+        if (module.override) {
+            config = lang.mixin({}, config, true);
+            lang.mixin(config, module.override, true);
+        }
+
         var buildFileContents = "",
-            namespace = config.namespace ? config.namespace + '.' : '',
+            namespace = config.namespace || '',
+            namespaceWithDot = namespace ? namespace + '.' : '',
+            stubModulesByName = (config.stubModules && config.stubModules._byName) || {},
             context = layer.context,
-            anonDefRegExp = config.anonDefRegExp,
             path, reqIndex, fileContents, currContents,
-            i, moduleName,
+            i, moduleName, shim, packageConfig,
             parts, builder, writeApi;
-
-        //Use override settings, particularly for pragmas
-        if (module.override) {
-            config = lang.delegate(config);
-            lang.mixin(config, module.override, true);
-        }
 
         //Start build output for the module.
         buildFileContents += "\n" +
@@ -8838,8 +15169,17 @@
 
         //Write the built module to disk, and build up the build output.
         fileContents = "";
-        for (i = 0; (path = layer.buildFilePaths[i]); i++) {
+        for (i = 0; i < layer.buildFilePaths.length; i++) {
+            path = layer.buildFilePaths[i];
             moduleName = layer.buildFileToModule[path];
+
+            //If the moduleName is for a package main, then update it to the
+            //real main value.
+            packageConfig = layer.context.config.pkgs &&
+                            layer.context.config.pkgs[moduleName];
+            if (packageConfig) {
+                moduleName += '/' + packageConfig.main;
+            }
 
             //Figure out if the module is a result of a build plugin, and if so,
             //then delegate to that plugin.
@@ -8849,22 +15189,64 @@
                 if (builder.write) {
                     writeApi = function (input) {
                         fileContents += "\n" + addSemiColon(input);
+                        if (config.onBuildWrite) {
+                            fileContents = config.onBuildWrite(moduleName, path, fileContents);
+                        }
                     };
                     writeApi.asModule = function (moduleName, input) {
                         fileContents += "\n" +
                                         addSemiColon(
-                                            build.toTransport(anonDefRegExp, namespace, moduleName, path, input, layer));
+                                            build.toTransport(namespace, moduleName, path, input, layer, {
+                                                useSourceUrl: layer.context.config.useSourceUrl
+                                            }));
+                        if (config.onBuildWrite) {
+                            fileContents = config.onBuildWrite(moduleName, path, fileContents);
+                        }
                     };
                     builder.write(parts.prefix, parts.name, writeApi);
                 }
             } else {
-                currContents = file.readFile(path);
-
-                if (config.namespace) {
-                    currContents = pragma.namespace(currContents, config.namespace);
-                }
-
-                currContents = build.toTransport(anonDefRegExp, namespace, moduleName, path, currContents, layer);
+                if (stubModulesByName.hasOwnProperty(moduleName)) {
+                    //Just want to insert a simple module definition instead
+                    //of the source module. Useful for plugins that inline
+                    //all their resources.
+                    if (layer.context.plugins.hasOwnProperty(moduleName)) {
+                        //Slightly different content for plugins, to indicate
+                        //that dynamic loading will not work.
+                        currContents = 'define({load: function(id){throw new Error("Dynamic load not allowed: " + id);}});';
+                    } else {
+                        currContents = 'define({});';
+                    }
+                } else {
+                    currContents = file.readFile(path);
+                }
+
+                if (config.cjsTranslate) {
+                    currContents = commonJs.convert(path, currContents);
+                }
+
+                if (config.onBuildRead) {
+                    currContents = config.onBuildRead(moduleName, path, currContents);
+                }
+
+                if (namespace) {
+                    currContents = pragma.namespace(currContents, namespace);
+                }
+
+                currContents = build.toTransport(namespace, moduleName, path, currContents, layer, {
+                                    useSourceUrl: config.useSourceUrl
+                                });
+
+                if (packageConfig) {
+                    currContents = addSemiColon(currContents) + '\n';
+                    currContents += namespaceWithDot + "define('" +
+                                    packageConfig.name + "', ['" + moduleName +
+                                    "'], function (main) { return main; });\n";
+                }
+
+                if (config.onBuildWrite) {
+                    currContents = config.onBuildWrite(moduleName, path, currContents);
+                }
 
                 //Semicolon is for files that are not well formed when
                 //concatenated with other content.
@@ -8877,20 +15259,24 @@
             //after the module is processed.
             //If we have a name, but no defined module, then add in the placeholder.
             if (moduleName && !layer.modulesWithNames[moduleName] && !config.skipModuleInsertion) {
-                //If including jquery, register the module correctly, otherwise
-                //register an empty function. For jquery, make sure jQuery is
-                //a real object, and perhaps not some other file mapping, like
-                //to zepto.
-                if (moduleName === 'jquery') {
-                    fileContents += '\n(function () {\n' +
-                                   'var jq = typeof jQuery !== "undefined" && jQuery;\n' +
-                                   namespace +
-                                   'define("jquery", [], function () { return jq; });\n' +
-                                   '}());\n';
+                shim = config.shim && config.shim[moduleName];
+                if (shim) {
+                    fileContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", ' +
+                                     (shim.deps && shim.deps.length ?
+                                            build.makeJsArrayString(shim.deps) + ', ' : '') +
+                                     (shim.exports ? shim.exports() : 'function(){}') +
+                                     ');\n';
                 } else {
-                    fileContents += '\n' + namespace + 'define("' + moduleName + '", function(){});\n';
-                }
-            }
+                    fileContents += '\n' + namespaceWithDot + 'define("' + moduleName + '", function(){});\n';
+                }
+            }
+        }
+
+        //Add a require at the end to kick start module execution, if that
+        //was desired. Usually this is only specified when using small shim
+        //loaders like almond.
+        if (module.insertRequire) {
+            fileContents += '\n' + namespaceWithDot + 'require(["' + module.insertRequire.join('", "') + '"]);\n';
         }
 
         return {
@@ -8901,62 +15287,33 @@
         };
     };
 
-    /**
-     * Creates the regexp to find anonymous defines.
-     * @param {String} namespace an optional namespace to use. The namespace
-     * should *include* a trailing dot. So a valid value would be 'foo.'
-     * @returns {RegExp}
-     */
-    build.makeAnonDefRegExp = function (namespace) {
-        //This regexp is not bullet-proof, and it has one optional part to
-        //avoid issues with some Dojo transition modules that use a
-        //define(\n//begin v1.x content
-        //for a comment.
-        return new RegExp('(^|[^\\.])(' + (namespace || '').replace(/\./g, '\\.') +
-                          'define|define)\\s*\\(\\s*(\\/\\/[^\\n\\r]*[\\r\\n])?(\\[|f|\\{|["\']([^"\']+)["\'])(\\s*,\\s*f)?');
+    //Converts an JS array of strings to a string representation.
+    //Not using JSON.stringify() for Rhino's sake.
+    build.makeJsArrayString = function (ary) {
+        return '["' + ary.map(function (item) {
+            //Escape any double quotes, backslashes
+            return lang.jsEscape(item);
+        }).join('","') + '"]';
     };
 
-    build.leadingCommaRegExp = /^\s*,/;
-
-    build.toTransport = function (anonDefRegExp, namespace, moduleName, path, contents, layer) {
-
-        //If anonymous module, insert the module name.
-        return contents.replace(anonDefRegExp, function (match, start, callName, possibleComment, suffix, namedModule, namedFuncStart) {
-            //A named module with either listed dependencies or an object
-            //literal for a value. Skip it. If named module, only want ones
-            //whose next argument is a function literal to scan for
-            //require('') dependecies.
-            if (namedModule && !namedFuncStart) {
-                return match;
-            }
-
-            if (layer) {
+    build.toTransport = function (namespace, moduleName, path, contents, layer, options) {
+        var baseUrl = layer && layer.context.config.baseUrl;
+
+        function onFound(info) {
+            //Only mark this module as having a name if not a named module,
+            //or if a named module and the name matches expectations.
+            if (layer && (info.needsId || info.foundId === moduleName)) {
                 layer.modulesWithNames[moduleName] = true;
             }
-
-            var deps = null;
-
-            //Look for CommonJS require calls inside the function if this is
-            //an anonymous define call that just has a function registered.
-            //Also look if a named define function but has a factory function
-            //as the second arg that should be scanned for dependencies.
-            if (suffix.indexOf('f') !== -1 || (namedModule)) {
-                deps = parse.getAnonDeps(path, contents);
-
-                if (deps.length) {
-                    deps = deps.map(function (dep) {
-                        return "'" + dep + "'";
-                    });
-                } else {
-                    deps = [];
-                }
-            }
-
-            return start + namespace + "define('" + moduleName + "'," +
-                   (deps ? ('[' + deps.toString() + '],') : '') +
-                   (namedModule ? namedFuncStart.replace(build.leadingCommaRegExp, '') : suffix);
-        });
-
+        }
+
+        //Convert path to be a local one to the baseUrl, useful for
+        //useSourceUrl.
+        if (baseUrl) {
+            path = path.replace(baseUrl, '');
+        }
+
+        return transform.toTransport(namespace, moduleName, path, contents, onFound, options);
     };
 
     return build;
@@ -9001,23 +15358,50 @@
                 config.logLevel = config.hasOwnProperty('logLevel') ?
                                   config.logLevel : logger.SILENT;
 
+                //Reset build internals first in case this is part
+                //of a long-running server process that could have
+                //exceptioned out in a bad state. It is only defined
+                //after the first call though.
+                if (requirejs._buildReset) {
+                    requirejs._buildReset();
+                }
+
                 var result = build(config);
 
-                //Reset build internals on each run.
+                //And clean up, in case something else triggers
+                //a build in another pathway.
                 requirejs._buildReset();
 
-                callback(result);
+                if (callback) {
+                    callback(result);
+                }
             };
-
-            //Enable execution of this callback in a build setting.
-            //Normally, once requirePatch is run, by default it will
-            //not execute callbacks, unless this property is set on
-            //the callback.
-            runBuild.__requireJsBuild = true;
 
             requirejs({
                 context: 'build'
             }, ['build', 'logger'], runBuild);
+        };
+
+        requirejs.tools = {
+            useLib: function (contextName, callback) {
+                if (!callback) {
+                    callback = contextName;
+                    contextName = 'uselib';
+                }
+
+                if (!useLibLoaded[contextName]) {
+                    loadLib();
+                    useLibLoaded[contextName] = true;
+                }
+
+                var req = requirejs({
+                    context: contextName
+                });
+
+                req(['build'], function () {
+                    callback(req);
+                });
+            }
         };
 
         requirejs.define = define;

--- a/templates/main.tpl
+++ b/templates/main.tpl
@@ -56,12 +56,12 @@
     {block name=javascriptmodules}
     GitPHPJSModules = ['common'];
     {/block}
-
-    require({ldelim}
+    require.config({ldelim}
     	baseUrl: GitPHP.BaseUrl + 'js',
 	paths: GitPHPJSPaths,
-	priority: ['jquery']
-    {rdelim}, GitPHPJSModules);
+    {rdelim});
+
+    require(GitPHPJSModules);
     </script>
     {/block}
     {/if}

comments