Home | History | Annotate | Download | only in sandbox
      1 // Copyright (C) 2011 by Yehuda Katz
      2 // Licensing details in LICENSE.handlebars
      3 
      4 // lib/handlebars/base.js
      5 var Handlebars = {};
      6 
      7 Handlebars.VERSION = "1.0.beta.6";
      8 
      9 Handlebars.helpers  = {};
     10 Handlebars.partials = {};
     11 
     12 Handlebars.registerHelper = function(name, fn, inverse) {
     13   if(inverse) { fn.not = inverse; }
     14   this.helpers[name] = fn;
     15 };
     16 
     17 Handlebars.registerPartial = function(name, str) {
     18   this.partials[name] = str;
     19 };
     20 
     21 Handlebars.registerHelper('helperMissing', function(arg) {
     22   if(arguments.length === 2) {
     23     return undefined;
     24   } else {
     25     throw new Error("Could not find property '" + arg + "'");
     26   }
     27 });
     28 
     29 var toString = Object.prototype.toString, functionType = "[object Function]";
     30 
     31 Handlebars.registerHelper('blockHelperMissing', function(context, options) {
     32   var inverse = options.inverse || function() {}, fn = options.fn;
     33 
     34 
     35   var ret = "";
     36   var type = toString.call(context);
     37 
     38   if(type === functionType) { context = context.call(this); }
     39 
     40   if(context === true) {
     41     return fn(this);
     42   } else if(context === false || context == null) {
     43     return inverse(this);
     44   } else if(type === "[object Array]") {
     45     if(context.length > 0) {
     46       for(var i=0, j=context.length; i<j; i++) {
     47         ret = ret + fn(context[i]);
     48       }
     49     } else {
     50       ret = inverse(this);
     51     }
     52     return ret;
     53   } else {
     54     return fn(context);
     55   }
     56 });
     57 
     58 Handlebars.registerHelper('each', function(context, options) {
     59   var fn = options.fn, inverse = options.inverse;
     60   var ret = "";
     61 
     62   if(context && context.length > 0) {
     63     for(var i=0, j=context.length; i<j; i++) {
     64       ret = ret + fn(context[i]);
     65     }
     66   } else {
     67     ret = inverse(this);
     68   }
     69   return ret;
     70 });
     71 
     72 Handlebars.registerHelper('if', function(context, options) {
     73   var type = toString.call(context);
     74   if(type === functionType) { context = context.call(this); }
     75 
     76   if(!context || Handlebars.Utils.isEmpty(context)) {
     77     return options.inverse(this);
     78   } else {
     79     return options.fn(this);
     80   }
     81 });
     82 
     83 Handlebars.registerHelper('unless', function(context, options) {
     84   var fn = options.fn, inverse = options.inverse;
     85   options.fn = inverse;
     86   options.inverse = fn;
     87 
     88   return Handlebars.helpers['if'].call(this, context, options);
     89 });
     90 
     91 Handlebars.registerHelper('with', function(context, options) {
     92   return options.fn(context);
     93 });
     94 
     95 Handlebars.registerHelper('log', function(context) {
     96   Handlebars.log(context);
     97 });
     98 ;
     99 // lib/handlebars/compiler/parser.js
    100 /* Jison generated parser */
    101 var handlebars = (function(){
    102 
    103 var parser = {trace: function trace() { },
    104 yy: {},
    105 symbols_: {"error":2,"root":3,"program":4,"EOF":5,"statements":6,"simpleInverse":7,"statement":8,"openInverse":9,"closeBlock":10,"openBlock":11,"mustache":12,"partial":13,"CONTENT":14,"COMMENT":15,"OPEN_BLOCK":16,"inMustache":17,"CLOSE":18,"OPEN_INVERSE":19,"OPEN_ENDBLOCK":20,"path":21,"OPEN":22,"OPEN_UNESCAPED":23,"OPEN_PARTIAL":24,"params":25,"hash":26,"param":27,"STRING":28,"INTEGER":29,"BOOLEAN":30,"hashSegments":31,"hashSegment":32,"ID":33,"EQUALS":34,"pathSegments":35,"SEP":36,"$accept":0,"$end":1},
    106 terminals_: {2:"error",5:"EOF",14:"CONTENT",15:"COMMENT",16:"OPEN_BLOCK",18:"CLOSE",19:"OPEN_INVERSE",20:"OPEN_ENDBLOCK",22:"OPEN",23:"OPEN_UNESCAPED",24:"OPEN_PARTIAL",28:"STRING",29:"INTEGER",30:"BOOLEAN",33:"ID",34:"EQUALS",36:"SEP"},
    107 productions_: [0,[3,2],[4,3],[4,1],[4,0],[6,1],[6,2],[8,3],[8,3],[8,1],[8,1],[8,1],[8,1],[11,3],[9,3],[10,3],[12,3],[12,3],[13,3],[13,4],[7,2],[17,3],[17,2],[17,2],[17,1],[25,2],[25,1],[27,1],[27,1],[27,1],[27,1],[26,1],[31,2],[31,1],[32,3],[32,3],[32,3],[32,3],[21,1],[35,3],[35,1]],
    108 performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
    109 
    110 var $0 = $$.length - 1;
    111 switch (yystate) {
    112 case 1: return $$[$0-1] 
    113 break;
    114 case 2: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]) 
    115 break;
    116 case 3: this.$ = new yy.ProgramNode($$[$0]) 
    117 break;
    118 case 4: this.$ = new yy.ProgramNode([]) 
    119 break;
    120 case 5: this.$ = [$$[$0]] 
    121 break;
    122 case 6: $$[$0-1].push($$[$0]); this.$ = $$[$0-1] 
    123 break;
    124 case 7: this.$ = new yy.InverseNode($$[$0-2], $$[$0-1], $$[$0]) 
    125 break;
    126 case 8: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0]) 
    127 break;
    128 case 9: this.$ = $$[$0] 
    129 break;
    130 case 10: this.$ = $$[$0] 
    131 break;
    132 case 11: this.$ = new yy.ContentNode($$[$0]) 
    133 break;
    134 case 12: this.$ = new yy.CommentNode($$[$0]) 
    135 break;
    136 case 13: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) 
    137 break;
    138 case 14: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) 
    139 break;
    140 case 15: this.$ = $$[$0-1] 
    141 break;
    142 case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]) 
    143 break;
    144 case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true) 
    145 break;
    146 case 18: this.$ = new yy.PartialNode($$[$0-1]) 
    147 break;
    148 case 19: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]) 
    149 break;
    150 case 20: 
    151 break;
    152 case 21: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]] 
    153 break;
    154 case 22: this.$ = [[$$[$0-1]].concat($$[$0]), null] 
    155 break;
    156 case 23: this.$ = [[$$[$0-1]], $$[$0]] 
    157 break;
    158 case 24: this.$ = [[$$[$0]], null] 
    159 break;
    160 case 25: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 
    161 break;
    162 case 26: this.$ = [$$[$0]] 
    163 break;
    164 case 27: this.$ = $$[$0] 
    165 break;
    166 case 28: this.$ = new yy.StringNode($$[$0]) 
    167 break;
    168 case 29: this.$ = new yy.IntegerNode($$[$0]) 
    169 break;
    170 case 30: this.$ = new yy.BooleanNode($$[$0]) 
    171 break;
    172 case 31: this.$ = new yy.HashNode($$[$0]) 
    173 break;
    174 case 32: $$[$0-1].push($$[$0]); this.$ = $$[$0-1] 
    175 break;
    176 case 33: this.$ = [$$[$0]] 
    177 break;
    178 case 34: this.$ = [$$[$0-2], $$[$0]] 
    179 break;
    180 case 35: this.$ = [$$[$0-2], new yy.StringNode($$[$0])] 
    181 break;
    182 case 36: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])] 
    183 break;
    184 case 37: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])] 
    185 break;
    186 case 38: this.$ = new yy.IdNode($$[$0]) 
    187 break;
    188 case 39: $$[$0-2].push($$[$0]); this.$ = $$[$0-2]; 
    189 break;
    190 case 40: this.$ = [$$[$0]] 
    191 break;
    192 }
    193 },
    194 table: [{3:1,4:2,5:[2,4],6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{1:[3]},{5:[1,16]},{5:[2,3],7:17,8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,19],20:[2,3],22:[1,13],23:[1,14],24:[1,15]},{5:[2,5],14:[2,5],15:[2,5],16:[2,5],19:[2,5],20:[2,5],22:[2,5],23:[2,5],24:[2,5]},{4:20,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{4:21,6:3,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,4],22:[1,13],23:[1,14],24:[1,15]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],24:[2,9]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],24:[2,10]},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],24:[2,11]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],24:[2,12]},{17:22,21:23,33:[1,25],35:24},{17:26,21:23,33:[1,25],35:24},{17:27,21:23,33:[1,25],35:24},{17:28,21:23,33:[1,25],35:24},{21:29,33:[1,25],35:24},{1:[2,1]},{6:30,8:4,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],22:[1,13],23:[1,14],24:[1,15]},{5:[2,6],14:[2,6],15:[2,6],16:[2,6],19:[2,6],20:[2,6],22:[2,6],23:[2,6],24:[2,6]},{17:22,18:[1,31],21:23,33:[1,25],35:24},{10:32,20:[1,33]},{10:34,20:[1,33]},{18:[1,35]},{18:[2,24],21:40,25:36,26:37,27:38,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,38],28:[2,38],29:[2,38],30:[2,38],33:[2,38],36:[1,46]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],36:[2,40]},{18:[1,47]},{18:[1,48]},{18:[1,49]},{18:[1,50],21:51,33:[1,25],35:24},{5:[2,2],8:18,9:5,11:6,12:7,13:8,14:[1,9],15:[1,10],16:[1,12],19:[1,11],20:[2,2],22:[1,13],23:[1,14],24:[1,15]},{14:[2,20],15:[2,20],16:[2,20],19:[2,20],22:[2,20],23:[2,20],24:[2,20]},{5:[2,7],14:[2,7],15:[2,7],16:[2,7],19:[2,7],20:[2,7],22:[2,7],23:[2,7],24:[2,7]},{21:52,33:[1,25],35:24},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],24:[2,8]},{14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],24:[2,14]},{18:[2,22],21:40,26:53,27:54,28:[1,41],29:[1,42],30:[1,43],31:39,32:44,33:[1,45],35:24},{18:[2,23]},{18:[2,26],28:[2,26],29:[2,26],30:[2,26],33:[2,26]},{18:[2,31],32:55,33:[1,56]},{18:[2,27],28:[2,27],29:[2,27],30:[2,27],33:[2,27]},{18:[2,28],28:[2,28],29:[2,28],30:[2,28],33:[2,28]},{18:[2,29],28:[2,29],29:[2,29],30:[2,29],33:[2,29]},{18:[2,30],28:[2,30],29:[2,30],30:[2,30],33:[2,30]},{18:[2,33],33:[2,33]},{18:[2,40],28:[2,40],29:[2,40],30:[2,40],33:[2,40],34:[1,57],36:[2,40]},{33:[1,58]},{14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],24:[2,13]},{5:[2,16],14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],24:[2,16]},{5:[2,17],14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],24:[2,17]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],24:[2,18]},{18:[1,59]},{18:[1,60]},{18:[2,21]},{18:[2,25],28:[2,25],29:[2,25],30:[2,25],33:[2,25]},{18:[2,32],33:[2,32]},{34:[1,57]},{21:61,28:[1,62],29:[1,63],30:[1,64],33:[1,25],35:24},{18:[2,39],28:[2,39],29:[2,39],30:[2,39],33:[2,39],36:[2,39]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],24:[2,19]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],24:[2,15]},{18:[2,34],33:[2,34]},{18:[2,35],33:[2,35]},{18:[2,36],33:[2,36]},{18:[2,37],33:[2,37]}],
    195 defaultActions: {16:[2,1],37:[2,23],53:[2,21]},
    196 parseError: function parseError(str, hash) {
    197     throw new Error(str);
    198 },
    199 parse: function parse(input) {
    200     var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
    201     this.lexer.setInput(input);
    202     this.lexer.yy = this.yy;
    203     this.yy.lexer = this.lexer;
    204     if (typeof this.lexer.yylloc == "undefined")
    205         this.lexer.yylloc = {};
    206     var yyloc = this.lexer.yylloc;
    207     lstack.push(yyloc);
    208     if (typeof this.yy.parseError === "function")
    209         this.parseError = this.yy.parseError;
    210     function popStack(n) {
    211         stack.length = stack.length - 2 * n;
    212         vstack.length = vstack.length - n;
    213         lstack.length = lstack.length - n;
    214     }
    215     function lex() {
    216         var token;
    217         token = self.lexer.lex() || 1;
    218         if (typeof token !== "number") {
    219             token = self.symbols_[token] || token;
    220         }
    221         return token;
    222     }
    223     var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
    224     while (true) {
    225         state = stack[stack.length - 1];
    226         if (this.defaultActions[state]) {
    227             action = this.defaultActions[state];
    228         } else {
    229             if (symbol == null)
    230                 symbol = lex();
    231             action = table[state] && table[state][symbol];
    232         }
    233         if (typeof action === "undefined" || !action.length || !action[0]) {
    234             if (!recovering) {
    235                 expected = [];
    236                 for (p in table[state])
    237                     if (this.terminals_[p] && p > 2) {
    238                         expected.push("'" + this.terminals_[p] + "'");
    239                     }
    240                 var errStr = "";
    241                 if (this.lexer.showPosition) {
    242                     errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + this.terminals_[symbol] + "'";
    243                 } else {
    244                     errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
    245                 }
    246                 this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
    247             }
    248         }
    249         if (action[0] instanceof Array && action.length > 1) {
    250             throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
    251         }
    252         switch (action[0]) {
    253         case 1:
    254             stack.push(symbol);
    255             vstack.push(this.lexer.yytext);
    256             lstack.push(this.lexer.yylloc);
    257             stack.push(action[1]);
    258             symbol = null;
    259             if (!preErrorSymbol) {
    260                 yyleng = this.lexer.yyleng;
    261                 yytext = this.lexer.yytext;
    262                 yylineno = this.lexer.yylineno;
    263                 yyloc = this.lexer.yylloc;
    264                 if (recovering > 0)
    265                     recovering--;
    266             } else {
    267                 symbol = preErrorSymbol;
    268                 preErrorSymbol = null;
    269             }
    270             break;
    271         case 2:
    272             len = this.productions_[action[1]][1];
    273             yyval.$ = vstack[vstack.length - len];
    274             yyval._$ = {first_line: lstack[lstack.length - (len || 1)].first_line, last_line: lstack[lstack.length - 1].last_line, first_column: lstack[lstack.length - (len || 1)].first_column, last_column: lstack[lstack.length - 1].last_column};
    275             r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
    276             if (typeof r !== "undefined") {
    277                 return r;
    278             }
    279             if (len) {
    280                 stack = stack.slice(0, -1 * len * 2);
    281                 vstack = vstack.slice(0, -1 * len);
    282                 lstack = lstack.slice(0, -1 * len);
    283             }
    284             stack.push(this.productions_[action[1]][0]);
    285             vstack.push(yyval.$);
    286             lstack.push(yyval._$);
    287             newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
    288             stack.push(newState);
    289             break;
    290         case 3:
    291             return true;
    292         }
    293     }
    294     return true;
    295 }
    296 };/* Jison generated lexer */
    297 var lexer = (function(){
    298 
    299 var lexer = ({EOF:1,
    300 parseError:function parseError(str, hash) {
    301         if (this.yy.parseError) {
    302             this.yy.parseError(str, hash);
    303         } else {
    304             throw new Error(str);
    305         }
    306     },
    307 setInput:function (input) {
    308         this._input = input;
    309         this._more = this._less = this.done = false;
    310         this.yylineno = this.yyleng = 0;
    311         this.yytext = this.matched = this.match = '';
    312         this.conditionStack = ['INITIAL'];
    313         this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
    314         return this;
    315     },
    316 input:function () {
    317         var ch = this._input[0];
    318         this.yytext+=ch;
    319         this.yyleng++;
    320         this.match+=ch;
    321         this.matched+=ch;
    322         var lines = ch.match(/\n/);
    323         if (lines) this.yylineno++;
    324         this._input = this._input.slice(1);
    325         return ch;
    326     },
    327 unput:function (ch) {
    328         this._input = ch + this._input;
    329         return this;
    330     },
    331 more:function () {
    332         this._more = true;
    333         return this;
    334     },
    335 pastInput:function () {
    336         var past = this.matched.substr(0, this.matched.length - this.match.length);
    337         return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
    338     },
    339 upcomingInput:function () {
    340         var next = this.match;
    341         if (next.length < 20) {
    342             next += this._input.substr(0, 20-next.length);
    343         }
    344         return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
    345     },
    346 showPosition:function () {
    347         var pre = this.pastInput();
    348         var c = new Array(pre.length + 1).join("-");
    349         return pre + this.upcomingInput() + "\n" + c+"^";
    350     },
    351 next:function () {
    352         if (this.done) {
    353             return this.EOF;
    354         }
    355         if (!this._input) this.done = true;
    356 
    357         var token,
    358             match,
    359             col,
    360             lines;
    361         if (!this._more) {
    362             this.yytext = '';
    363             this.match = '';
    364         }
    365         var rules = this._currentRules();
    366         for (var i=0;i < rules.length; i++) {
    367             match = this._input.match(this.rules[rules[i]]);
    368             if (match) {
    369                 lines = match[0].match(/\n.*/g);
    370                 if (lines) this.yylineno += lines.length;
    371                 this.yylloc = {first_line: this.yylloc.last_line,
    372                                last_line: this.yylineno+1,
    373                                first_column: this.yylloc.last_column,
    374                                last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
    375                 this.yytext += match[0];
    376                 this.match += match[0];
    377                 this.matches = match;
    378                 this.yyleng = this.yytext.length;
    379                 this._more = false;
    380                 this._input = this._input.slice(match[0].length);
    381                 this.matched += match[0];
    382                 token = this.performAction.call(this, this.yy, this, rules[i],this.conditionStack[this.conditionStack.length-1]);
    383                 if (token) return token;
    384                 else return;
    385             }
    386         }
    387         if (this._input === "") {
    388             return this.EOF;
    389         } else {
    390             this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(), 
    391                     {text: "", token: null, line: this.yylineno});
    392         }
    393     },
    394 lex:function lex() {
    395         var r = this.next();
    396         if (typeof r !== 'undefined') {
    397             return r;
    398         } else {
    399             return this.lex();
    400         }
    401     },
    402 begin:function begin(condition) {
    403         this.conditionStack.push(condition);
    404     },
    405 popState:function popState() {
    406         return this.conditionStack.pop();
    407     },
    408 _currentRules:function _currentRules() {
    409         return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
    410     },
    411 topState:function () {
    412         return this.conditionStack[this.conditionStack.length-2];
    413     },
    414 pushState:function begin(condition) {
    415         this.begin(condition);
    416     }});
    417 lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
    418 
    419 var YYSTATE=YY_START
    420 switch($avoiding_name_collisions) {
    421 case 0:
    422                                    if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
    423                                    if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
    424                                    if(yy_.yytext) return 14;
    425                                  
    426 break;
    427 case 1: return 14; 
    428 break;
    429 case 2: this.popState(); return 14; 
    430 break;
    431 case 3: return 24; 
    432 break;
    433 case 4: return 16; 
    434 break;
    435 case 5: return 20; 
    436 break;
    437 case 6: return 19; 
    438 break;
    439 case 7: return 19; 
    440 break;
    441 case 8: return 23; 
    442 break;
    443 case 9: return 23; 
    444 break;
    445 case 10: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; 
    446 break;
    447 case 11: return 22; 
    448 break;
    449 case 12: return 34; 
    450 break;
    451 case 13: return 33; 
    452 break;
    453 case 14: return 33; 
    454 break;
    455 case 15: return 36; 
    456 break;
    457 case 16: /*ignore whitespace*/ 
    458 break;
    459 case 17: this.popState(); return 18; 
    460 break;
    461 case 18: this.popState(); return 18; 
    462 break;
    463 case 19: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 28; 
    464 break;
    465 case 20: return 30; 
    466 break;
    467 case 21: return 30; 
    468 break;
    469 case 22: return 29; 
    470 break;
    471 case 23: return 33; 
    472 break;
    473 case 24: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 33; 
    474 break;
    475 case 25: return 'INVALID'; 
    476 break;
    477 case 26: return 5; 
    478 break;
    479 }
    480 };
    481 lexer.rules = [/^[^\x00]*?(?=(\{\{))/,/^[^\x00]+/,/^[^\x00]{2,}?(?=(\{\{))/,/^\{\{>/,/^\{\{#/,/^\{\{\//,/^\{\{\^/,/^\{\{\s*else\b/,/^\{\{\{/,/^\{\{&/,/^\{\{![\s\S]*?\}\}/,/^\{\{/,/^=/,/^\.(?=[} ])/,/^\.\./,/^[\/.]/,/^\s+/,/^\}\}\}/,/^\}\}/,/^"(\\["]|[^"])*"/,/^true(?=[}\s])/,/^false(?=[}\s])/,/^[0-9]+(?=[}\s])/,/^[a-zA-Z0-9_$-]+(?=[=}\s\/.])/,/^\[[^\]]*\]/,/^./,/^$/];
    482 lexer.conditions = {"mu":{"rules":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26],"inclusive":false},"emu":{"rules":[2],"inclusive":false},"INITIAL":{"rules":[0,1,26],"inclusive":true}};return lexer;})()
    483 parser.lexer = lexer;
    484 return parser;
    485 })();
    486 if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
    487 exports.parser = handlebars;
    488 exports.parse = function () { return handlebars.parse.apply(handlebars, arguments); }
    489 exports.main = function commonjsMain(args) {
    490     if (!args[1])
    491         throw new Error('Usage: '+args[0]+' FILE');
    492     if (typeof process !== 'undefined') {
    493         var source = require('fs').readFileSync(require('path').join(process.cwd(), args[1]), "utf8");
    494     } else {
    495         var cwd = require("file").path(require("file").cwd());
    496         var source = cwd.join(args[1]).read({charset: "utf-8"});
    497     }
    498     return exports.parser.parse(source);
    499 }
    500 if (typeof module !== 'undefined' && require.main === module) {
    501   exports.main(typeof process !== 'undefined' ? process.argv.slice(1) : require("system").args);
    502 }
    503 };
    504 ;
    505 // lib/handlebars/compiler/base.js
    506 Handlebars.Parser = handlebars;
    507 
    508 Handlebars.parse = function(string) {
    509   Handlebars.Parser.yy = Handlebars.AST;
    510   return Handlebars.Parser.parse(string);
    511 };
    512 
    513 Handlebars.print = function(ast) {
    514   return new Handlebars.PrintVisitor().accept(ast);
    515 };
    516 
    517 Handlebars.logger = {
    518   DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
    519 
    520   // override in the host environment
    521   log: function(level, str) {}
    522 };
    523 
    524 Handlebars.log = function(level, str) { Handlebars.logger.log(level, str); };
    525 ;
    526 // lib/handlebars/compiler/ast.js
    527 (function() {
    528 
    529   Handlebars.AST = {};
    530 
    531   Handlebars.AST.ProgramNode = function(statements, inverse) {
    532     this.type = "program";
    533     this.statements = statements;
    534     if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
    535   };
    536 
    537   Handlebars.AST.MustacheNode = function(params, hash, unescaped) {
    538     this.type = "mustache";
    539     this.id = params[0];
    540     this.params = params.slice(1);
    541     this.hash = hash;
    542     this.escaped = !unescaped;
    543   };
    544 
    545   Handlebars.AST.PartialNode = function(id, context) {
    546     this.type    = "partial";
    547 
    548     // TODO: disallow complex IDs
    549 
    550     this.id      = id;
    551     this.context = context;
    552   };
    553 
    554   var verifyMatch = function(open, close) {
    555     if(open.original !== close.original) {
    556       throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
    557     }
    558   };
    559 
    560   Handlebars.AST.BlockNode = function(mustache, program, close) {
    561     verifyMatch(mustache.id, close);
    562     this.type = "block";
    563     this.mustache = mustache;
    564     this.program  = program;
    565   };
    566 
    567   Handlebars.AST.InverseNode = function(mustache, program, close) {
    568     verifyMatch(mustache.id, close);
    569     this.type = "inverse";
    570     this.mustache = mustache;
    571     this.program  = program;
    572   };
    573 
    574   Handlebars.AST.ContentNode = function(string) {
    575     this.type = "content";
    576     this.string = string;
    577   };
    578 
    579   Handlebars.AST.HashNode = function(pairs) {
    580     this.type = "hash";
    581     this.pairs = pairs;
    582   };
    583 
    584   Handlebars.AST.IdNode = function(parts) {
    585     this.type = "ID";
    586     this.original = parts.join(".");
    587 
    588     var dig = [], depth = 0;
    589 
    590     for(var i=0,l=parts.length; i<l; i++) {
    591       var part = parts[i];
    592 
    593       if(part === "..") { depth++; }
    594       else if(part === "." || part === "this") { this.isScoped = true; }
    595       else { dig.push(part); }
    596     }
    597 
    598     this.parts    = dig;
    599     this.string   = dig.join('.');
    600     this.depth    = depth;
    601     this.isSimple = (dig.length === 1) && (depth === 0);
    602   };
    603 
    604   Handlebars.AST.StringNode = function(string) {
    605     this.type = "STRING";
    606     this.string = string;
    607   };
    608 
    609   Handlebars.AST.IntegerNode = function(integer) {
    610     this.type = "INTEGER";
    611     this.integer = integer;
    612   };
    613 
    614   Handlebars.AST.BooleanNode = function(bool) {
    615     this.type = "BOOLEAN";
    616     this.bool = bool;
    617   };
    618 
    619   Handlebars.AST.CommentNode = function(comment) {
    620     this.type = "comment";
    621     this.comment = comment;
    622   };
    623 
    624 })();;
    625 // lib/handlebars/utils.js
    626 Handlebars.Exception = function(message) {
    627   var tmp = Error.prototype.constructor.apply(this, arguments);
    628 
    629   for (var p in tmp) {
    630     if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
    631   }
    632 
    633   this.message = tmp.message;
    634 };
    635 Handlebars.Exception.prototype = new Error;
    636 
    637 // Build out our basic SafeString type
    638 Handlebars.SafeString = function(string) {
    639   this.string = string;
    640 };
    641 Handlebars.SafeString.prototype.toString = function() {
    642   return this.string.toString();
    643 };
    644 
    645 (function() {
    646   var escape = {
    647     "<": "&lt;",
    648     ">": "&gt;",
    649     '"': "&quot;",
    650     "'": "&#x27;",
    651     "`": "&#x60;"
    652   };
    653 
    654   var badChars = /&(?!\w+;)|[<>"'`]/g;
    655   var possible = /[&<>"'`]/;
    656 
    657   var escapeChar = function(chr) {
    658     return escape[chr] || "&amp;";
    659   };
    660 
    661   Handlebars.Utils = {
    662     escapeExpression: function(string) {
    663       // don't escape SafeStrings, since they're already safe
    664       if (string instanceof Handlebars.SafeString) {
    665         return string.toString();
    666       } else if (string == null || string === false) {
    667         return "";
    668       }
    669 
    670       if(!possible.test(string)) { return string; }
    671       return string.replace(badChars, escapeChar);
    672     },
    673 
    674     isEmpty: function(value) {
    675       if (typeof value === "undefined") {
    676         return true;
    677       } else if (value === null) {
    678         return true;
    679       } else if (value === false) {
    680         return true;
    681       } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
    682         return true;
    683       } else {
    684         return false;
    685       }
    686     }
    687   };
    688 })();;
    689 // lib/handlebars/compiler/compiler.js
    690 Handlebars.Compiler = function() {};
    691 Handlebars.JavaScriptCompiler = function() {};
    692 
    693 (function(Compiler, JavaScriptCompiler) {
    694   Compiler.OPCODE_MAP = {
    695     appendContent: 1,
    696     getContext: 2,
    697     lookupWithHelpers: 3,
    698     lookup: 4,
    699     append: 5,
    700     invokeMustache: 6,
    701     appendEscaped: 7,
    702     pushString: 8,
    703     truthyOrFallback: 9,
    704     functionOrFallback: 10,
    705     invokeProgram: 11,
    706     invokePartial: 12,
    707     push: 13,
    708     assignToHash: 15,
    709     pushStringParam: 16
    710   };
    711 
    712   Compiler.MULTI_PARAM_OPCODES = {
    713     appendContent: 1,
    714     getContext: 1,
    715     lookupWithHelpers: 2,
    716     lookup: 1,
    717     invokeMustache: 3,
    718     pushString: 1,
    719     truthyOrFallback: 1,
    720     functionOrFallback: 1,
    721     invokeProgram: 3,
    722     invokePartial: 1,
    723     push: 1,
    724     assignToHash: 1,
    725     pushStringParam: 1
    726   };
    727 
    728   Compiler.DISASSEMBLE_MAP = {};
    729 
    730   for(var prop in Compiler.OPCODE_MAP) {
    731     var value = Compiler.OPCODE_MAP[prop];
    732     Compiler.DISASSEMBLE_MAP[value] = prop;
    733   }
    734 
    735   Compiler.multiParamSize = function(code) {
    736     return Compiler.MULTI_PARAM_OPCODES[Compiler.DISASSEMBLE_MAP[code]];
    737   };
    738 
    739   Compiler.prototype = {
    740     compiler: Compiler,
    741 
    742     disassemble: function() {
    743       var opcodes = this.opcodes, opcode, nextCode;
    744       var out = [], str, name, value;
    745 
    746       for(var i=0, l=opcodes.length; i<l; i++) {
    747         opcode = opcodes[i];
    748 
    749         if(opcode === 'DECLARE') {
    750           name = opcodes[++i];
    751           value = opcodes[++i];
    752           out.push("DECLARE " + name + " = " + value);
    753         } else {
    754           str = Compiler.DISASSEMBLE_MAP[opcode];
    755 
    756           var extraParams = Compiler.multiParamSize(opcode);
    757           var codes = [];
    758 
    759           for(var j=0; j<extraParams; j++) {
    760             nextCode = opcodes[++i];
    761 
    762             if(typeof nextCode === "string") {
    763               nextCode = "\"" + nextCode.replace("\n", "\\n") + "\"";
    764             }
    765 
    766             codes.push(nextCode);
    767           }
    768 
    769           str = str + " " + codes.join(" ");
    770 
    771           out.push(str);
    772         }
    773       }
    774 
    775       return out.join("\n");
    776     },
    777 
    778     guid: 0,
    779 
    780     compile: function(program, options) {
    781       this.children = [];
    782       this.depths = {list: []};
    783       this.options = options;
    784 
    785       // These changes will propagate to the other compiler components
    786       var knownHelpers = this.options.knownHelpers;
    787       this.options.knownHelpers = {
    788         'helperMissing': true,
    789         'blockHelperMissing': true,
    790         'each': true,
    791         'if': true,
    792         'unless': true,
    793         'with': true,
    794         'log': true
    795       };
    796       if (knownHelpers) {
    797         for (var name in knownHelpers) {
    798           this.options.knownHelpers[name] = knownHelpers[name];
    799         }
    800       }
    801 
    802       return this.program(program);
    803     },
    804 
    805     accept: function(node) {
    806       return this[node.type](node);
    807     },
    808 
    809     program: function(program) {
    810       var statements = program.statements, statement;
    811       this.opcodes = [];
    812 
    813       for(var i=0, l=statements.length; i<l; i++) {
    814         statement = statements[i];
    815         this[statement.type](statement);
    816       }
    817       this.isSimple = l === 1;
    818 
    819       this.depths.list = this.depths.list.sort(function(a, b) {
    820         return a - b;
    821       });
    822 
    823       return this;
    824     },
    825 
    826     compileProgram: function(program) {
    827       var result = new this.compiler().compile(program, this.options);
    828       var guid = this.guid++;
    829 
    830       this.usePartial = this.usePartial || result.usePartial;
    831 
    832       this.children[guid] = result;
    833 
    834       for(var i=0, l=result.depths.list.length; i<l; i++) {
    835         depth = result.depths.list[i];
    836 
    837         if(depth < 2) { continue; }
    838         else { this.addDepth(depth - 1); }
    839       }
    840 
    841       return guid;
    842     },
    843 
    844     block: function(block) {
    845       var mustache = block.mustache;
    846       var depth, child, inverse, inverseGuid;
    847 
    848       var params = this.setupStackForMustache(mustache);
    849 
    850       var programGuid = this.compileProgram(block.program);
    851 
    852       if(block.program.inverse) {
    853         inverseGuid = this.compileProgram(block.program.inverse);
    854         this.declare('inverse', inverseGuid);
    855       }
    856 
    857       this.opcode('invokeProgram', programGuid, params.length, !!mustache.hash);
    858       this.declare('inverse', null);
    859       this.opcode('append');
    860     },
    861 
    862     inverse: function(block) {
    863       var params = this.setupStackForMustache(block.mustache);
    864 
    865       var programGuid = this.compileProgram(block.program);
    866 
    867       this.declare('inverse', programGuid);
    868 
    869       this.opcode('invokeProgram', null, params.length, !!block.mustache.hash);
    870       this.declare('inverse', null);
    871       this.opcode('append');
    872     },
    873 
    874     hash: function(hash) {
    875       var pairs = hash.pairs, pair, val;
    876 
    877       this.opcode('push', '{}');
    878 
    879       for(var i=0, l=pairs.length; i<l; i++) {
    880         pair = pairs[i];
    881         val  = pair[1];
    882 
    883         this.accept(val);
    884         this.opcode('assignToHash', pair[0]);
    885       }
    886     },
    887 
    888     partial: function(partial) {
    889       var id = partial.id;
    890       this.usePartial = true;
    891 
    892       if(partial.context) {
    893         this.ID(partial.context);
    894       } else {
    895         this.opcode('push', 'depth0');
    896       }
    897 
    898       this.opcode('invokePartial', id.original);
    899       this.opcode('append');
    900     },
    901 
    902     content: function(content) {
    903       this.opcode('appendContent', content.string);
    904     },
    905 
    906     mustache: function(mustache) {
    907       var params = this.setupStackForMustache(mustache);
    908 
    909       this.opcode('invokeMustache', params.length, mustache.id.original, !!mustache.hash);
    910 
    911       if(mustache.escaped && !this.options.noEscape) {
    912         this.opcode('appendEscaped');
    913       } else {
    914         this.opcode('append');
    915       }
    916     },
    917 
    918     ID: function(id) {
    919       this.addDepth(id.depth);
    920 
    921       this.opcode('getContext', id.depth);
    922 
    923       this.opcode('lookupWithHelpers', id.parts[0] || null, id.isScoped || false);
    924 
    925       for(var i=1, l=id.parts.length; i<l; i++) {
    926         this.opcode('lookup', id.parts[i]);
    927       }
    928     },
    929 
    930     STRING: function(string) {
    931       this.opcode('pushString', string.string);
    932     },
    933 
    934     INTEGER: function(integer) {
    935       this.opcode('push', integer.integer);
    936     },
    937 
    938     BOOLEAN: function(bool) {
    939       this.opcode('push', bool.bool);
    940     },
    941 
    942     comment: function() {},
    943 
    944     // HELPERS
    945     pushParams: function(params) {
    946       var i = params.length, param;
    947 
    948       while(i--) {
    949         param = params[i];
    950 
    951         if(this.options.stringParams) {
    952           if(param.depth) {
    953             this.addDepth(param.depth);
    954           }
    955 
    956           this.opcode('getContext', param.depth || 0);
    957           this.opcode('pushStringParam', param.string);
    958         } else {
    959           this[param.type](param);
    960         }
    961       }
    962     },
    963 
    964     opcode: function(name, val1, val2, val3) {
    965       this.opcodes.push(Compiler.OPCODE_MAP[name]);
    966       if(val1 !== undefined) { this.opcodes.push(val1); }
    967       if(val2 !== undefined) { this.opcodes.push(val2); }
    968       if(val3 !== undefined) { this.opcodes.push(val3); }
    969     },
    970 
    971     declare: function(name, value) {
    972       this.opcodes.push('DECLARE');
    973       this.opcodes.push(name);
    974       this.opcodes.push(value);
    975     },
    976 
    977     addDepth: function(depth) {
    978       if(depth === 0) { return; }
    979 
    980       if(!this.depths[depth]) {
    981         this.depths[depth] = true;
    982         this.depths.list.push(depth);
    983       }
    984     },
    985 
    986     setupStackForMustache: function(mustache) {
    987       var params = mustache.params;
    988 
    989       this.pushParams(params);
    990 
    991       if(mustache.hash) {
    992         this.hash(mustache.hash);
    993       }
    994 
    995       this.ID(mustache.id);
    996 
    997       return params;
    998     }
    999   };
   1000 
   1001   JavaScriptCompiler.prototype = {
   1002     // PUBLIC API: You can override these methods in a subclass to provide
   1003     // alternative compiled forms for name lookup and buffering semantics
   1004     nameLookup: function(parent, name, type) {
   1005       if (/^[0-9]+$/.test(name)) {
   1006         return parent + "[" + name + "]";
   1007       } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
   1008         return parent + "." + name;
   1009       }
   1010       else {
   1011         return parent + "['" + name + "']";
   1012       }
   1013     },
   1014 
   1015     appendToBuffer: function(string) {
   1016       if (this.environment.isSimple) {
   1017         return "return " + string + ";";
   1018       } else {
   1019         return "buffer += " + string + ";";
   1020       }
   1021     },
   1022 
   1023     initializeBuffer: function() {
   1024       return this.quotedString("");
   1025     },
   1026 
   1027     namespace: "Handlebars",
   1028     // END PUBLIC API
   1029 
   1030     compile: function(environment, options, context, asObject) {
   1031       this.environment = environment;
   1032       this.options = options || {};
   1033 
   1034       this.name = this.environment.name;
   1035       this.isChild = !!context;
   1036       this.context = context || {
   1037         programs: [],
   1038         aliases: { self: 'this' },
   1039         registers: {list: []}
   1040       };
   1041 
   1042       this.preamble();
   1043 
   1044       this.stackSlot = 0;
   1045       this.stackVars = [];
   1046 
   1047       this.compileChildren(environment, options);
   1048 
   1049       var opcodes = environment.opcodes, opcode;
   1050 
   1051       this.i = 0;
   1052 
   1053       for(l=opcodes.length; this.i<l; this.i++) {
   1054         opcode = this.nextOpcode(0);
   1055 
   1056         if(opcode[0] === 'DECLARE') {
   1057           this.i = this.i + 2;
   1058           this[opcode[1]] = opcode[2];
   1059         } else {
   1060           this.i = this.i + opcode[1].length;
   1061           this[opcode[0]].apply(this, opcode[1]);
   1062         }
   1063       }
   1064 
   1065       return this.createFunctionContext(asObject);
   1066     },
   1067 
   1068     nextOpcode: function(n) {
   1069       var opcodes = this.environment.opcodes, opcode = opcodes[this.i + n], name, val;
   1070       var extraParams, codes;
   1071 
   1072       if(opcode === 'DECLARE') {
   1073         name = opcodes[this.i + 1];
   1074         val  = opcodes[this.i + 2];
   1075         return ['DECLARE', name, val];
   1076       } else {
   1077         name = Compiler.DISASSEMBLE_MAP[opcode];
   1078 
   1079         extraParams = Compiler.multiParamSize(opcode);
   1080         codes = [];
   1081 
   1082         for(var j=0; j<extraParams; j++) {
   1083           codes.push(opcodes[this.i + j + 1 + n]);
   1084         }
   1085 
   1086         return [name, codes];
   1087       }
   1088     },
   1089 
   1090     eat: function(opcode) {
   1091       this.i = this.i + opcode.length;
   1092     },
   1093 
   1094     preamble: function() {
   1095       var out = [];
   1096 
   1097       // this register will disambiguate helper lookup from finding a function in
   1098       // a context. This is necessary for mustache compatibility, which requires
   1099       // that context functions in blocks are evaluated by blockHelperMissing, and
   1100       // then proceed as if the resulting value was provided to blockHelperMissing.
   1101       this.useRegister('foundHelper');
   1102 
   1103       if (!this.isChild) {
   1104         var namespace = this.namespace;
   1105         var copies = "helpers = helpers || " + namespace + ".helpers;";
   1106         if(this.environment.usePartial) { copies = copies + " partials = partials || " + namespace + ".partials;"; }
   1107         out.push(copies);
   1108       } else {
   1109         out.push('');
   1110       }
   1111 
   1112       if (!this.environment.isSimple) {
   1113         out.push(", buffer = " + this.initializeBuffer());
   1114       } else {
   1115         out.push("");
   1116       }
   1117 
   1118       // track the last context pushed into place to allow skipping the
   1119       // getContext opcode when it would be a noop
   1120       this.lastContext = 0;
   1121       this.source = out;
   1122     },
   1123 
   1124     createFunctionContext: function(asObject) {
   1125       var locals = this.stackVars;
   1126       if (!this.isChild) {
   1127         locals = locals.concat(this.context.registers.list);
   1128       }
   1129 
   1130       if(locals.length > 0) {
   1131         this.source[1] = this.source[1] + ", " + locals.join(", ");
   1132       }
   1133 
   1134       // Generate minimizer alias mappings
   1135       if (!this.isChild) {
   1136         var aliases = []
   1137         for (var alias in this.context.aliases) {
   1138           this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
   1139         }
   1140       }
   1141 
   1142       if (this.source[1]) {
   1143         this.source[1] = "var " + this.source[1].substring(2) + ";";
   1144       }
   1145 
   1146       // Merge children
   1147       if (!this.isChild) {
   1148         this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
   1149       }
   1150 
   1151       if (!this.environment.isSimple) {
   1152         this.source.push("return buffer;");
   1153       }
   1154 
   1155       var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
   1156 
   1157       for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
   1158         params.push("depth" + this.environment.depths.list[i]);
   1159       }
   1160 
   1161       if (asObject) {
   1162         params.push(this.source.join("\n  "));
   1163 
   1164         return Function.apply(this, params);
   1165       } else {
   1166         var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n  ' + this.source.join("\n  ") + '}';
   1167         Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
   1168         return functionSource;
   1169       }
   1170     },
   1171 
   1172     appendContent: function(content) {
   1173       this.source.push(this.appendToBuffer(this.quotedString(content)));
   1174     },
   1175 
   1176     append: function() {
   1177       var local = this.popStack();
   1178       this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
   1179       if (this.environment.isSimple) {
   1180         this.source.push("else { " + this.appendToBuffer("''") + " }");
   1181       }
   1182     },
   1183 
   1184     appendEscaped: function() {
   1185       var opcode = this.nextOpcode(1), extra = "";
   1186       this.context.aliases.escapeExpression = 'this.escapeExpression';
   1187 
   1188       if(opcode[0] === 'appendContent') {
   1189         extra = " + " + this.quotedString(opcode[1][0]);
   1190         this.eat(opcode);
   1191       }
   1192 
   1193       this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")" + extra));
   1194     },
   1195 
   1196     getContext: function(depth) {
   1197       if(this.lastContext !== depth) {
   1198         this.lastContext = depth;
   1199       }
   1200     },
   1201 
   1202     lookupWithHelpers: function(name, isScoped) {
   1203       if(name) {
   1204         var topStack = this.nextStack();
   1205 
   1206         this.usingKnownHelper = false;
   1207 
   1208         var toPush;
   1209         if (!isScoped && this.options.knownHelpers[name]) {
   1210           toPush = topStack + " = " + this.nameLookup('helpers', name, 'helper');
   1211           this.usingKnownHelper = true;
   1212         } else if (isScoped || this.options.knownHelpersOnly) {
   1213           toPush = topStack + " = " + this.nameLookup('depth' + this.lastContext, name, 'context');
   1214         } else {
   1215           this.register('foundHelper', this.nameLookup('helpers', name, 'helper'));
   1216           toPush = topStack + " = foundHelper || " + this.nameLookup('depth' + this.lastContext, name, 'context');
   1217         }
   1218 
   1219         toPush += ';';
   1220         this.source.push(toPush);
   1221       } else {
   1222         this.pushStack('depth' + this.lastContext);
   1223       }
   1224     },
   1225 
   1226     lookup: function(name) {
   1227       var topStack = this.topStack();
   1228       this.source.push(topStack + " = (" + topStack + " === null || " + topStack + " === undefined || " + topStack + " === false ? " +
   1229         topStack + " : " + this.nameLookup(topStack, name, 'context') + ");");
   1230     },
   1231 
   1232     pushStringParam: function(string) {
   1233       this.pushStack('depth' + this.lastContext);
   1234       this.pushString(string);
   1235     },
   1236 
   1237     pushString: function(string) {
   1238       this.pushStack(this.quotedString(string));
   1239     },
   1240 
   1241     push: function(name) {
   1242       this.pushStack(name);
   1243     },
   1244 
   1245     invokeMustache: function(paramSize, original, hasHash) {
   1246       this.populateParams(paramSize, this.quotedString(original), "{}", null, hasHash, function(nextStack, helperMissingString, id) {
   1247         if (!this.usingKnownHelper) {
   1248           this.context.aliases.helperMissing = 'helpers.helperMissing';
   1249           this.context.aliases.undef = 'void 0';
   1250           this.source.push("else if(" + id + "=== undef) { " + nextStack + " = helperMissing.call(" + helperMissingString + "); }");
   1251           if (nextStack !== id) {
   1252             this.source.push("else { " + nextStack + " = " + id + "; }");
   1253           }
   1254         }
   1255       });
   1256     },
   1257 
   1258     invokeProgram: function(guid, paramSize, hasHash) {
   1259       var inverse = this.programExpression(this.inverse);
   1260       var mainProgram = this.programExpression(guid);
   1261 
   1262       this.populateParams(paramSize, null, mainProgram, inverse, hasHash, function(nextStack, helperMissingString, id) {
   1263         if (!this.usingKnownHelper) {
   1264           this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
   1265           this.source.push("else { " + nextStack + " = blockHelperMissing.call(" + helperMissingString + "); }");
   1266         }
   1267       });
   1268     },
   1269 
   1270     populateParams: function(paramSize, helperId, program, inverse, hasHash, fn) {
   1271       var needsRegister = hasHash || this.options.stringParams || inverse || this.options.data;
   1272       var id = this.popStack(), nextStack;
   1273       var params = [], param, stringParam, stringOptions;
   1274 
   1275       if (needsRegister) {
   1276         this.register('tmp1', program);
   1277         stringOptions = 'tmp1';
   1278       } else {
   1279         stringOptions = '{ hash: {} }';
   1280       }
   1281 
   1282       if (needsRegister) {
   1283         var hash = (hasHash ? this.popStack() : '{}');
   1284         this.source.push('tmp1.hash = ' + hash + ';');
   1285       }
   1286 
   1287       if(this.options.stringParams) {
   1288         this.source.push('tmp1.contexts = [];');
   1289       }
   1290 
   1291       for(var i=0; i<paramSize; i++) {
   1292         param = this.popStack();
   1293         params.push(param);
   1294 
   1295         if(this.options.stringParams) {
   1296           this.source.push('tmp1.contexts.push(' + this.popStack() + ');');
   1297         }
   1298       }
   1299 
   1300       if(inverse) {
   1301         this.source.push('tmp1.fn = tmp1;');
   1302         this.source.push('tmp1.inverse = ' + inverse + ';');
   1303       }
   1304 
   1305       if(this.options.data) {
   1306         this.source.push('tmp1.data = data;');
   1307       }
   1308 
   1309       params.push(stringOptions);
   1310 
   1311       this.populateCall(params, id, helperId || id, fn, program !== '{}');
   1312     },
   1313 
   1314     populateCall: function(params, id, helperId, fn, program) {
   1315       var paramString = ["depth0"].concat(params).join(", ");
   1316       var helperMissingString = ["depth0"].concat(helperId).concat(params).join(", ");
   1317 
   1318       var nextStack = this.nextStack();
   1319 
   1320       if (this.usingKnownHelper) {
   1321         this.source.push(nextStack + " = " + id + ".call(" + paramString + ");");
   1322       } else {
   1323         this.context.aliases.functionType = '"function"';
   1324         var condition = program ? "foundHelper && " : ""
   1325         this.source.push("if(" + condition + "typeof " + id + " === functionType) { " + nextStack + " = " + id + ".call(" + paramString + "); }");
   1326       }
   1327       fn.call(this, nextStack, helperMissingString, id);
   1328       this.usingKnownHelper = false;
   1329     },
   1330 
   1331     invokePartial: function(context) {
   1332       params = [this.nameLookup('partials', context, 'partial'), "'" + context + "'", this.popStack(), "helpers", "partials"];
   1333 
   1334       if (this.options.data) {
   1335         params.push("data");
   1336       }
   1337 
   1338       this.pushStack("self.invokePartial(" + params.join(", ") + ");");
   1339     },
   1340 
   1341     assignToHash: function(key) {
   1342       var value = this.popStack();
   1343       var hash = this.topStack();
   1344 
   1345       this.source.push(hash + "['" + key + "'] = " + value + ";");
   1346     },
   1347 
   1348     // HELPERS
   1349 
   1350     compiler: JavaScriptCompiler,
   1351 
   1352     compileChildren: function(environment, options) {
   1353       var children = environment.children, child, compiler;
   1354 
   1355       for(var i=0, l=children.length; i<l; i++) {
   1356         child = children[i];
   1357         compiler = new this.compiler();
   1358 
   1359         this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children
   1360         var index = this.context.programs.length;
   1361         child.index = index;
   1362         child.name = 'program' + index;
   1363         this.context.programs[index] = compiler.compile(child, options, this.context);
   1364       }
   1365     },
   1366 
   1367     programExpression: function(guid) {
   1368       if(guid == null) { return "self.noop"; }
   1369 
   1370       var child = this.environment.children[guid],
   1371           depths = child.depths.list;
   1372       var programParams = [child.index, child.name, "data"];
   1373 
   1374       for(var i=0, l = depths.length; i<l; i++) {
   1375         depth = depths[i];
   1376 
   1377         if(depth === 1) { programParams.push("depth0"); }
   1378         else { programParams.push("depth" + (depth - 1)); }
   1379       }
   1380 
   1381       if(depths.length === 0) {
   1382         return "self.program(" + programParams.join(", ") + ")";
   1383       } else {
   1384         programParams.shift();
   1385         return "self.programWithDepth(" + programParams.join(", ") + ")";
   1386       }
   1387     },
   1388 
   1389     register: function(name, val) {
   1390       this.useRegister(name);
   1391       this.source.push(name + " = " + val + ";");
   1392     },
   1393 
   1394     useRegister: function(name) {
   1395       if(!this.context.registers[name]) {
   1396         this.context.registers[name] = true;
   1397         this.context.registers.list.push(name);
   1398       }
   1399     },
   1400 
   1401     pushStack: function(item) {
   1402       this.source.push(this.nextStack() + " = " + item + ";");
   1403       return "stack" + this.stackSlot;
   1404     },
   1405 
   1406     nextStack: function() {
   1407       this.stackSlot++;
   1408       if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
   1409       return "stack" + this.stackSlot;
   1410     },
   1411 
   1412     popStack: function() {
   1413       return "stack" + this.stackSlot--;
   1414     },
   1415 
   1416     topStack: function() {
   1417       return "stack" + this.stackSlot;
   1418     },
   1419 
   1420     quotedString: function(str) {
   1421       return '"' + str
   1422         .replace(/\\/g, '\\\\')
   1423         .replace(/"/g, '\\"')
   1424         .replace(/\n/g, '\\n')
   1425         .replace(/\r/g, '\\r') + '"';
   1426     }
   1427   };
   1428 
   1429   var reservedWords = (
   1430     "break else new var" +
   1431     " case finally return void" +
   1432     " catch for switch while" +
   1433     " continue function this with" +
   1434     " default if throw" +
   1435     " delete in try" +
   1436     " do instanceof typeof" +
   1437     " abstract enum int short" +
   1438     " boolean export interface static" +
   1439     " byte extends long super" +
   1440     " char final native synchronized" +
   1441     " class float package throws" +
   1442     " const goto private transient" +
   1443     " debugger implements protected volatile" +
   1444     " double import public let yield"
   1445   ).split(" ");
   1446 
   1447   var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
   1448 
   1449   for(var i=0, l=reservedWords.length; i<l; i++) {
   1450     compilerWords[reservedWords[i]] = true;
   1451   }
   1452 
   1453   JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
   1454     if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
   1455       return true;
   1456     }
   1457     return false;
   1458   }
   1459 
   1460 })(Handlebars.Compiler, Handlebars.JavaScriptCompiler);
   1461 
   1462 Handlebars.precompile = function(string, options) {
   1463   options = options || {};
   1464 
   1465   var ast = Handlebars.parse(string);
   1466   var environment = new Handlebars.Compiler().compile(ast, options);
   1467   return new Handlebars.JavaScriptCompiler().compile(environment, options);
   1468 };
   1469 
   1470 Handlebars.compile = function(string, options) {
   1471   options = options || {};
   1472 
   1473   var compiled;
   1474   function compile() {
   1475     var ast = Handlebars.parse(string);
   1476     var environment = new Handlebars.Compiler().compile(ast, options);
   1477     var templateSpec = new Handlebars.JavaScriptCompiler().compile(environment, options, undefined, true);
   1478     return Handlebars.template(templateSpec);
   1479   }
   1480 
   1481   // Template is only compiled on first use and cached after that point.
   1482   return function(context, options) {
   1483     if (!compiled) {
   1484       compiled = compile();
   1485     }
   1486     return compiled.call(this, context, options);
   1487   };
   1488 };
   1489 ;
   1490 // lib/handlebars/runtime.js
   1491 Handlebars.VM = {
   1492   template: function(templateSpec) {
   1493     // Just add water
   1494     var container = {
   1495       escapeExpression: Handlebars.Utils.escapeExpression,
   1496       invokePartial: Handlebars.VM.invokePartial,
   1497       programs: [],
   1498       program: function(i, fn, data) {
   1499         var programWrapper = this.programs[i];
   1500         if(data) {
   1501           return Handlebars.VM.program(fn, data);
   1502         } else if(programWrapper) {
   1503           return programWrapper;
   1504         } else {
   1505           programWrapper = this.programs[i] = Handlebars.VM.program(fn);
   1506           return programWrapper;
   1507         }
   1508       },
   1509       programWithDepth: Handlebars.VM.programWithDepth,
   1510       noop: Handlebars.VM.noop
   1511     };
   1512 
   1513     return function(context, options) {
   1514       options = options || {};
   1515       return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
   1516     };
   1517   },
   1518 
   1519   programWithDepth: function(fn, data, $depth) {
   1520     var args = Array.prototype.slice.call(arguments, 2);
   1521 
   1522     return function(context, options) {
   1523       options = options || {};
   1524 
   1525       return fn.apply(this, [context, options.data || data].concat(args));
   1526     };
   1527   },
   1528   program: function(fn, data) {
   1529     return function(context, options) {
   1530       options = options || {};
   1531 
   1532       return fn(context, options.data || data);
   1533     };
   1534   },
   1535   noop: function() { return ""; },
   1536   invokePartial: function(partial, name, context, helpers, partials, data) {
   1537     options = { helpers: helpers, partials: partials, data: data };
   1538 
   1539     if(partial === undefined) {
   1540       throw new Handlebars.Exception("The partial " + name + " could not be found");
   1541     } else if(partial instanceof Function) {
   1542       return partial(context, options);
   1543     } else if (!Handlebars.compile) {
   1544       throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
   1545     } else {
   1546       partials[name] = Handlebars.compile(partial);
   1547       return partials[name](context, options);
   1548     }
   1549   }
   1550 };
   1551 
   1552 Handlebars.template = Handlebars.VM.template;
   1553 ;
   1554