Bug: 627
[controller.git] / opendaylight / md-sal / sal-rest-docgen / src / main / resources / explorer / lib / handlebars-1.0.0.js
1 /*
2
3 Copyright (C) 2011 by Yehuda Katz
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 THE SOFTWARE.
22
23 */
24
25 // lib/handlebars/browser-prefix.js
26 var Handlebars = {};
27
28 (function(Handlebars, undefined) {
29 ;
30 // lib/handlebars/base.js
31
32 Handlebars.VERSION = "1.0.0";
33 Handlebars.COMPILER_REVISION = 4;
34
35 Handlebars.REVISION_CHANGES = {
36   1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
37   2: '== 1.0.0-rc.3',
38   3: '== 1.0.0-rc.4',
39   4: '>= 1.0.0'
40 };
41
42 Handlebars.helpers  = {};
43 Handlebars.partials = {};
44
45 var toString = Object.prototype.toString,
46     functionType = '[object Function]',
47     objectType = '[object Object]';
48
49 Handlebars.registerHelper = function(name, fn, inverse) {
50   if (toString.call(name) === objectType) {
51     if (inverse || fn) { throw new Handlebars.Exception('Arg not supported with multiple helpers'); }
52     Handlebars.Utils.extend(this.helpers, name);
53   } else {
54     if (inverse) { fn.not = inverse; }
55     this.helpers[name] = fn;
56   }
57 };
58
59 Handlebars.registerPartial = function(name, str) {
60   if (toString.call(name) === objectType) {
61     Handlebars.Utils.extend(this.partials,  name);
62   } else {
63     this.partials[name] = str;
64   }
65 };
66
67 Handlebars.registerHelper('helperMissing', function(arg) {
68   if(arguments.length === 2) {
69     return undefined;
70   } else {
71     throw new Error("Missing helper: '" + arg + "'");
72   }
73 });
74
75 Handlebars.registerHelper('blockHelperMissing', function(context, options) {
76   var inverse = options.inverse || function() {}, fn = options.fn;
77
78   var type = toString.call(context);
79
80   if(type === functionType) { context = context.call(this); }
81
82   if(context === true) {
83     return fn(this);
84   } else if(context === false || context == null) {
85     return inverse(this);
86   } else if(type === "[object Array]") {
87     if(context.length > 0) {
88       return Handlebars.helpers.each(context, options);
89     } else {
90       return inverse(this);
91     }
92   } else {
93     return fn(context);
94   }
95 });
96
97 Handlebars.K = function() {};
98
99 Handlebars.createFrame = Object.create || function(object) {
100   Handlebars.K.prototype = object;
101   var obj = new Handlebars.K();
102   Handlebars.K.prototype = null;
103   return obj;
104 };
105
106 Handlebars.logger = {
107   DEBUG: 0, INFO: 1, WARN: 2, ERROR: 3, level: 3,
108
109   methodMap: {0: 'debug', 1: 'info', 2: 'warn', 3: 'error'},
110
111   // can be overridden in the host environment
112   log: function(level, obj) {
113     if (Handlebars.logger.level <= level) {
114       var method = Handlebars.logger.methodMap[level];
115       if (typeof console !== 'undefined' && console[method]) {
116         console[method].call(console, obj);
117       }
118     }
119   }
120 };
121
122 Handlebars.log = function(level, obj) { Handlebars.logger.log(level, obj); };
123
124 Handlebars.registerHelper('each', function(context, options) {
125   var fn = options.fn, inverse = options.inverse;
126   var i = 0, ret = "", data;
127
128   var type = toString.call(context);
129   if(type === functionType) { context = context.call(this); }
130
131   if (options.data) {
132     data = Handlebars.createFrame(options.data);
133   }
134
135   if(context && typeof context === 'object') {
136     if(context instanceof Array){
137       for(var j = context.length; i<j; i++) {
138         if (data) { data.index = i; }
139         ret = ret + fn(context[i], { data: data });
140       }
141     } else {
142       for(var key in context) {
143         if(context.hasOwnProperty(key)) {
144           if(data) { data.key = key; }
145           ret = ret + fn(context[key], {data: data});
146           i++;
147         }
148       }
149     }
150   }
151
152   if(i === 0){
153     ret = inverse(this);
154   }
155
156   return ret;
157 });
158
159 Handlebars.registerHelper('if', function(conditional, options) {
160   var type = toString.call(conditional);
161   if(type === functionType) { conditional = conditional.call(this); }
162
163   if(!conditional || Handlebars.Utils.isEmpty(conditional)) {
164     return options.inverse(this);
165   } else {
166     return options.fn(this);
167   }
168 });
169
170 Handlebars.registerHelper('unless', function(conditional, options) {
171   return Handlebars.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn});
172 });
173
174 Handlebars.registerHelper('with', function(context, options) {
175   var type = toString.call(context);
176   if(type === functionType) { context = context.call(this); }
177
178   if (!Handlebars.Utils.isEmpty(context)) return options.fn(context);
179 });
180
181 Handlebars.registerHelper('log', function(context, options) {
182   var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
183   Handlebars.log(level, context);
184 });
185 ;
186 // lib/handlebars/compiler/parser.js
187 /* Jison generated parser */
188 var handlebars = (function(){
189 var parser = {trace: function trace() { },
190 yy: {},
191 symbols_: {"error":2,"root":3,"program":4,"EOF":5,"simpleInverse":6,"statements":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,"CLOSE_UNESCAPED":24,"OPEN_PARTIAL":25,"partialName":26,"params":27,"hash":28,"dataName":29,"param":30,"STRING":31,"INTEGER":32,"BOOLEAN":33,"hashSegments":34,"hashSegment":35,"ID":36,"EQUALS":37,"DATA":38,"pathSegments":39,"SEP":40,"$accept":0,"$end":1},
192 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:"CLOSE_UNESCAPED",25:"OPEN_PARTIAL",31:"STRING",32:"INTEGER",33:"BOOLEAN",36:"ID",37:"EQUALS",38:"DATA",40:"SEP"},
193 productions_: [0,[3,2],[4,2],[4,3],[4,2],[4,1],[4,1],[4,0],[7,1],[7,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],[6,2],[17,3],[17,2],[17,2],[17,1],[17,1],[27,2],[27,1],[30,1],[30,1],[30,1],[30,1],[30,1],[28,1],[34,2],[34,1],[35,3],[35,3],[35,3],[35,3],[35,3],[26,1],[26,1],[26,1],[29,2],[21,1],[39,3],[39,1]],
194 performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
195
196 var $0 = $$.length - 1;
197 switch (yystate) {
198 case 1: return $$[$0-1]; 
199 break;
200 case 2: this.$ = new yy.ProgramNode([], $$[$0]); 
201 break;
202 case 3: this.$ = new yy.ProgramNode($$[$0-2], $$[$0]); 
203 break;
204 case 4: this.$ = new yy.ProgramNode($$[$0-1], []); 
205 break;
206 case 5: this.$ = new yy.ProgramNode($$[$0]); 
207 break;
208 case 6: this.$ = new yy.ProgramNode([], []); 
209 break;
210 case 7: this.$ = new yy.ProgramNode([]); 
211 break;
212 case 8: this.$ = [$$[$0]]; 
213 break;
214 case 9: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 
215 break;
216 case 10: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1].inverse, $$[$0-1], $$[$0]); 
217 break;
218 case 11: this.$ = new yy.BlockNode($$[$0-2], $$[$0-1], $$[$0-1].inverse, $$[$0]); 
219 break;
220 case 12: this.$ = $$[$0]; 
221 break;
222 case 13: this.$ = $$[$0]; 
223 break;
224 case 14: this.$ = new yy.ContentNode($$[$0]); 
225 break;
226 case 15: this.$ = new yy.CommentNode($$[$0]); 
227 break;
228 case 16: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); 
229 break;
230 case 17: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1]); 
231 break;
232 case 18: this.$ = $$[$0-1]; 
233 break;
234 case 19:
235     // Parsing out the '&' escape token at this level saves ~500 bytes after min due to the removal of one parser node.
236     this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], $$[$0-2][2] === '&');
237   
238 break;
239 case 20: this.$ = new yy.MustacheNode($$[$0-1][0], $$[$0-1][1], true); 
240 break;
241 case 21: this.$ = new yy.PartialNode($$[$0-1]); 
242 break;
243 case 22: this.$ = new yy.PartialNode($$[$0-2], $$[$0-1]); 
244 break;
245 case 23: 
246 break;
247 case 24: this.$ = [[$$[$0-2]].concat($$[$0-1]), $$[$0]]; 
248 break;
249 case 25: this.$ = [[$$[$0-1]].concat($$[$0]), null]; 
250 break;
251 case 26: this.$ = [[$$[$0-1]], $$[$0]]; 
252 break;
253 case 27: this.$ = [[$$[$0]], null]; 
254 break;
255 case 28: this.$ = [[$$[$0]], null]; 
256 break;
257 case 29: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 
258 break;
259 case 30: this.$ = [$$[$0]]; 
260 break;
261 case 31: this.$ = $$[$0]; 
262 break;
263 case 32: this.$ = new yy.StringNode($$[$0]); 
264 break;
265 case 33: this.$ = new yy.IntegerNode($$[$0]); 
266 break;
267 case 34: this.$ = new yy.BooleanNode($$[$0]); 
268 break;
269 case 35: this.$ = $$[$0]; 
270 break;
271 case 36: this.$ = new yy.HashNode($$[$0]); 
272 break;
273 case 37: $$[$0-1].push($$[$0]); this.$ = $$[$0-1]; 
274 break;
275 case 38: this.$ = [$$[$0]]; 
276 break;
277 case 39: this.$ = [$$[$0-2], $$[$0]]; 
278 break;
279 case 40: this.$ = [$$[$0-2], new yy.StringNode($$[$0])]; 
280 break;
281 case 41: this.$ = [$$[$0-2], new yy.IntegerNode($$[$0])]; 
282 break;
283 case 42: this.$ = [$$[$0-2], new yy.BooleanNode($$[$0])]; 
284 break;
285 case 43: this.$ = [$$[$0-2], $$[$0]]; 
286 break;
287 case 44: this.$ = new yy.PartialNameNode($$[$0]); 
288 break;
289 case 45: this.$ = new yy.PartialNameNode(new yy.StringNode($$[$0])); 
290 break;
291 case 46: this.$ = new yy.PartialNameNode(new yy.IntegerNode($$[$0])); 
292 break;
293 case 47: this.$ = new yy.DataNode($$[$0]); 
294 break;
295 case 48: this.$ = new yy.IdNode($$[$0]); 
296 break;
297 case 49: $$[$0-2].push({part: $$[$0], separator: $$[$0-1]}); this.$ = $$[$0-2]; 
298 break;
299 case 50: this.$ = [{part: $$[$0]}]; 
300 break;
301 }
302 },
303 table: [{3:1,4:2,5:[2,7],6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],22:[1,14],23:[1,15],25:[1,16]},{1:[3]},{5:[1,17]},{5:[2,6],7:18,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,6],22:[1,14],23:[1,15],25:[1,16]},{5:[2,5],6:20,8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,5],22:[1,14],23:[1,15],25:[1,16]},{17:23,18:[1,22],21:24,29:25,36:[1,28],38:[1,27],39:26},{5:[2,8],14:[2,8],15:[2,8],16:[2,8],19:[2,8],20:[2,8],22:[2,8],23:[2,8],25:[2,8]},{4:29,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],25:[1,16]},{4:30,6:3,7:4,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,5],20:[2,7],22:[1,14],23:[1,15],25:[1,16]},{5:[2,12],14:[2,12],15:[2,12],16:[2,12],19:[2,12],20:[2,12],22:[2,12],23:[2,12],25:[2,12]},{5:[2,13],14:[2,13],15:[2,13],16:[2,13],19:[2,13],20:[2,13],22:[2,13],23:[2,13],25:[2,13]},{5:[2,14],14:[2,14],15:[2,14],16:[2,14],19:[2,14],20:[2,14],22:[2,14],23:[2,14],25:[2,14]},{5:[2,15],14:[2,15],15:[2,15],16:[2,15],19:[2,15],20:[2,15],22:[2,15],23:[2,15],25:[2,15]},{17:31,21:24,29:25,36:[1,28],38:[1,27],39:26},{17:32,21:24,29:25,36:[1,28],38:[1,27],39:26},{17:33,21:24,29:25,36:[1,28],38:[1,27],39:26},{21:35,26:34,31:[1,36],32:[1,37],36:[1,28],39:26},{1:[2,1]},{5:[2,2],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,2],22:[1,14],23:[1,15],25:[1,16]},{17:23,21:24,29:25,36:[1,28],38:[1,27],39:26},{5:[2,4],7:38,8:6,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,4],22:[1,14],23:[1,15],25:[1,16]},{5:[2,9],14:[2,9],15:[2,9],16:[2,9],19:[2,9],20:[2,9],22:[2,9],23:[2,9],25:[2,9]},{5:[2,23],14:[2,23],15:[2,23],16:[2,23],19:[2,23],20:[2,23],22:[2,23],23:[2,23],25:[2,23]},{18:[1,39]},{18:[2,27],21:44,24:[2,27],27:40,28:41,29:48,30:42,31:[1,45],32:[1,46],33:[1,47],34:43,35:49,36:[1,50],38:[1,27],39:26},{18:[2,28],24:[2,28]},{18:[2,48],24:[2,48],31:[2,48],32:[2,48],33:[2,48],36:[2,48],38:[2,48],40:[1,51]},{21:52,36:[1,28],39:26},{18:[2,50],24:[2,50],31:[2,50],32:[2,50],33:[2,50],36:[2,50],38:[2,50],40:[2,50]},{10:53,20:[1,54]},{10:55,20:[1,54]},{18:[1,56]},{18:[1,57]},{24:[1,58]},{18:[1,59],21:60,36:[1,28],39:26},{18:[2,44],36:[2,44]},{18:[2,45],36:[2,45]},{18:[2,46],36:[2,46]},{5:[2,3],8:21,9:7,11:8,12:9,13:10,14:[1,11],15:[1,12],16:[1,13],19:[1,19],20:[2,3],22:[1,14],23:[1,15],25:[1,16]},{14:[2,17],15:[2,17],16:[2,17],19:[2,17],20:[2,17],22:[2,17],23:[2,17],25:[2,17]},{18:[2,25],21:44,24:[2,25],28:61,29:48,30:62,31:[1,45],32:[1,46],33:[1,47],34:43,35:49,36:[1,50],38:[1,27],39:26},{18:[2,26],24:[2,26]},{18:[2,30],24:[2,30],31:[2,30],32:[2,30],33:[2,30],36:[2,30],38:[2,30]},{18:[2,36],24:[2,36],35:63,36:[1,64]},{18:[2,31],24:[2,31],31:[2,31],32:[2,31],33:[2,31],36:[2,31],38:[2,31]},{18:[2,32],24:[2,32],31:[2,32],32:[2,32],33:[2,32],36:[2,32],38:[2,32]},{18:[2,33],24:[2,33],31:[2,33],32:[2,33],33:[2,33],36:[2,33],38:[2,33]},{18:[2,34],24:[2,34],31:[2,34],32:[2,34],33:[2,34],36:[2,34],38:[2,34]},{18:[2,35],24:[2,35],31:[2,35],32:[2,35],33:[2,35],36:[2,35],38:[2,35]},{18:[2,38],24:[2,38],36:[2,38]},{18:[2,50],24:[2,50],31:[2,50],32:[2,50],33:[2,50],36:[2,50],37:[1,65],38:[2,50],40:[2,50]},{36:[1,66]},{18:[2,47],24:[2,47],31:[2,47],32:[2,47],33:[2,47],36:[2,47],38:[2,47]},{5:[2,10],14:[2,10],15:[2,10],16:[2,10],19:[2,10],20:[2,10],22:[2,10],23:[2,10],25:[2,10]},{21:67,36:[1,28],39:26},{5:[2,11],14:[2,11],15:[2,11],16:[2,11],19:[2,11],20:[2,11],22:[2,11],23:[2,11],25:[2,11]},{14:[2,16],15:[2,16],16:[2,16],19:[2,16],20:[2,16],22:[2,16],23:[2,16],25:[2,16]},{5:[2,19],14:[2,19],15:[2,19],16:[2,19],19:[2,19],20:[2,19],22:[2,19],23:[2,19],25:[2,19]},{5:[2,20],14:[2,20],15:[2,20],16:[2,20],19:[2,20],20:[2,20],22:[2,20],23:[2,20],25:[2,20]},{5:[2,21],14:[2,21],15:[2,21],16:[2,21],19:[2,21],20:[2,21],22:[2,21],23:[2,21],25:[2,21]},{18:[1,68]},{18:[2,24],24:[2,24]},{18:[2,29],24:[2,29],31:[2,29],32:[2,29],33:[2,29],36:[2,29],38:[2,29]},{18:[2,37],24:[2,37],36:[2,37]},{37:[1,65]},{21:69,29:73,31:[1,70],32:[1,71],33:[1,72],36:[1,28],38:[1,27],39:26},{18:[2,49],24:[2,49],31:[2,49],32:[2,49],33:[2,49],36:[2,49],38:[2,49],40:[2,49]},{18:[1,74]},{5:[2,22],14:[2,22],15:[2,22],16:[2,22],19:[2,22],20:[2,22],22:[2,22],23:[2,22],25:[2,22]},{18:[2,39],24:[2,39],36:[2,39]},{18:[2,40],24:[2,40],36:[2,40]},{18:[2,41],24:[2,41],36:[2,41]},{18:[2,42],24:[2,42],36:[2,42]},{18:[2,43],24:[2,43],36:[2,43]},{5:[2,18],14:[2,18],15:[2,18],16:[2,18],19:[2,18],20:[2,18],22:[2,18],23:[2,18],25:[2,18]}],
304 defaultActions: {17:[2,1]},
305 parseError: function parseError(str, hash) {
306     throw new Error(str);
307 },
308 parse: function parse(input) {
309     var self = this, stack = [0], vstack = [null], lstack = [], table = this.table, yytext = "", yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
310     this.lexer.setInput(input);
311     this.lexer.yy = this.yy;
312     this.yy.lexer = this.lexer;
313     this.yy.parser = this;
314     if (typeof this.lexer.yylloc == "undefined")
315         this.lexer.yylloc = {};
316     var yyloc = this.lexer.yylloc;
317     lstack.push(yyloc);
318     var ranges = this.lexer.options && this.lexer.options.ranges;
319     if (typeof this.yy.parseError === "function")
320         this.parseError = this.yy.parseError;
321     function popStack(n) {
322         stack.length = stack.length - 2 * n;
323         vstack.length = vstack.length - n;
324         lstack.length = lstack.length - n;
325     }
326     function lex() {
327         var token;
328         token = self.lexer.lex() || 1;
329         if (typeof token !== "number") {
330             token = self.symbols_[token] || token;
331         }
332         return token;
333     }
334     var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
335     while (true) {
336         state = stack[stack.length - 1];
337         if (this.defaultActions[state]) {
338             action = this.defaultActions[state];
339         } else {
340             if (symbol === null || typeof symbol == "undefined") {
341                 symbol = lex();
342             }
343             action = table[state] && table[state][symbol];
344         }
345         if (typeof action === "undefined" || !action.length || !action[0]) {
346             var errStr = "";
347             if (!recovering) {
348                 expected = [];
349                 for (p in table[state])
350                     if (this.terminals_[p] && p > 2) {
351                         expected.push("'" + this.terminals_[p] + "'");
352                     }
353                 if (this.lexer.showPosition) {
354                     errStr = "Parse error on line " + (yylineno + 1) + ":\n" + this.lexer.showPosition() + "\nExpecting " + expected.join(", ") + ", got '" + (this.terminals_[symbol] || symbol) + "'";
355                 } else {
356                     errStr = "Parse error on line " + (yylineno + 1) + ": Unexpected " + (symbol == 1?"end of input":"'" + (this.terminals_[symbol] || symbol) + "'");
357                 }
358                 this.parseError(errStr, {text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
359             }
360         }
361         if (action[0] instanceof Array && action.length > 1) {
362             throw new Error("Parse Error: multiple actions possible at state: " + state + ", token: " + symbol);
363         }
364         switch (action[0]) {
365         case 1:
366             stack.push(symbol);
367             vstack.push(this.lexer.yytext);
368             lstack.push(this.lexer.yylloc);
369             stack.push(action[1]);
370             symbol = null;
371             if (!preErrorSymbol) {
372                 yyleng = this.lexer.yyleng;
373                 yytext = this.lexer.yytext;
374                 yylineno = this.lexer.yylineno;
375                 yyloc = this.lexer.yylloc;
376                 if (recovering > 0)
377                     recovering--;
378             } else {
379                 symbol = preErrorSymbol;
380                 preErrorSymbol = null;
381             }
382             break;
383         case 2:
384             len = this.productions_[action[1]][1];
385             yyval.$ = vstack[vstack.length - len];
386             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};
387             if (ranges) {
388                 yyval._$.range = [lstack[lstack.length - (len || 1)].range[0], lstack[lstack.length - 1].range[1]];
389             }
390             r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
391             if (typeof r !== "undefined") {
392                 return r;
393             }
394             if (len) {
395                 stack = stack.slice(0, -1 * len * 2);
396                 vstack = vstack.slice(0, -1 * len);
397                 lstack = lstack.slice(0, -1 * len);
398             }
399             stack.push(this.productions_[action[1]][0]);
400             vstack.push(yyval.$);
401             lstack.push(yyval._$);
402             newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
403             stack.push(newState);
404             break;
405         case 3:
406             return true;
407         }
408     }
409     return true;
410 }
411 };
412 /* Jison generated lexer */
413 var lexer = (function(){
414 var lexer = ({EOF:1,
415 parseError:function parseError(str, hash) {
416         if (this.yy.parser) {
417             this.yy.parser.parseError(str, hash);
418         } else {
419             throw new Error(str);
420         }
421     },
422 setInput:function (input) {
423         this._input = input;
424         this._more = this._less = this.done = false;
425         this.yylineno = this.yyleng = 0;
426         this.yytext = this.matched = this.match = '';
427         this.conditionStack = ['INITIAL'];
428         this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
429         if (this.options.ranges) this.yylloc.range = [0,0];
430         this.offset = 0;
431         return this;
432     },
433 input:function () {
434         var ch = this._input[0];
435         this.yytext += ch;
436         this.yyleng++;
437         this.offset++;
438         this.match += ch;
439         this.matched += ch;
440         var lines = ch.match(/(?:\r\n?|\n).*/g);
441         if (lines) {
442             this.yylineno++;
443             this.yylloc.last_line++;
444         } else {
445             this.yylloc.last_column++;
446         }
447         if (this.options.ranges) this.yylloc.range[1]++;
448
449         this._input = this._input.slice(1);
450         return ch;
451     },
452 unput:function (ch) {
453         var len = ch.length;
454         var lines = ch.split(/(?:\r\n?|\n)/g);
455
456         this._input = ch + this._input;
457         this.yytext = this.yytext.substr(0, this.yytext.length-len-1);
458         //this.yyleng -= len;
459         this.offset -= len;
460         var oldLines = this.match.split(/(?:\r\n?|\n)/g);
461         this.match = this.match.substr(0, this.match.length-1);
462         this.matched = this.matched.substr(0, this.matched.length-1);
463
464         if (lines.length-1) this.yylineno -= lines.length-1;
465         var r = this.yylloc.range;
466
467         this.yylloc = {first_line: this.yylloc.first_line,
468           last_line: this.yylineno+1,
469           first_column: this.yylloc.first_column,
470           last_column: lines ?
471               (lines.length === oldLines.length ? this.yylloc.first_column : 0) + oldLines[oldLines.length - lines.length].length - lines[0].length:
472               this.yylloc.first_column - len
473           };
474
475         if (this.options.ranges) {
476             this.yylloc.range = [r[0], r[0] + this.yyleng - len];
477         }
478         return this;
479     },
480 more:function () {
481         this._more = true;
482         return this;
483     },
484 less:function (n) {
485         this.unput(this.match.slice(n));
486     },
487 pastInput:function () {
488         var past = this.matched.substr(0, this.matched.length - this.match.length);
489         return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
490     },
491 upcomingInput:function () {
492         var next = this.match;
493         if (next.length < 20) {
494             next += this._input.substr(0, 20-next.length);
495         }
496         return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
497     },
498 showPosition:function () {
499         var pre = this.pastInput();
500         var c = new Array(pre.length + 1).join("-");
501         return pre + this.upcomingInput() + "\n" + c+"^";
502     },
503 next:function () {
504         if (this.done) {
505             return this.EOF;
506         }
507         if (!this._input) this.done = true;
508
509         var token,
510             match,
511             tempMatch,
512             index,
513             col,
514             lines;
515         if (!this._more) {
516             this.yytext = '';
517             this.match = '';
518         }
519         var rules = this._currentRules();
520         for (var i=0;i < rules.length; i++) {
521             tempMatch = this._input.match(this.rules[rules[i]]);
522             if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
523                 match = tempMatch;
524                 index = i;
525                 if (!this.options.flex) break;
526             }
527         }
528         if (match) {
529             lines = match[0].match(/(?:\r\n?|\n).*/g);
530             if (lines) this.yylineno += lines.length;
531             this.yylloc = {first_line: this.yylloc.last_line,
532                            last_line: this.yylineno+1,
533                            first_column: this.yylloc.last_column,
534                            last_column: lines ? lines[lines.length-1].length-lines[lines.length-1].match(/\r?\n?/)[0].length : this.yylloc.last_column + match[0].length};
535             this.yytext += match[0];
536             this.match += match[0];
537             this.matches = match;
538             this.yyleng = this.yytext.length;
539             if (this.options.ranges) {
540                 this.yylloc.range = [this.offset, this.offset += this.yyleng];
541             }
542             this._more = false;
543             this._input = this._input.slice(match[0].length);
544             this.matched += match[0];
545             token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
546             if (this.done && this._input) this.done = false;
547             if (token) return token;
548             else return;
549         }
550         if (this._input === "") {
551             return this.EOF;
552         } else {
553             return this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
554                     {text: "", token: null, line: this.yylineno});
555         }
556     },
557 lex:function lex() {
558         var r = this.next();
559         if (typeof r !== 'undefined') {
560             return r;
561         } else {
562             return this.lex();
563         }
564     },
565 begin:function begin(condition) {
566         this.conditionStack.push(condition);
567     },
568 popState:function popState() {
569         return this.conditionStack.pop();
570     },
571 _currentRules:function _currentRules() {
572         return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
573     },
574 topState:function () {
575         return this.conditionStack[this.conditionStack.length-2];
576     },
577 pushState:function begin(condition) {
578         this.begin(condition);
579     }});
580 lexer.options = {};
581 lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
582
583 var YYSTATE=YY_START
584 switch($avoiding_name_collisions) {
585 case 0: yy_.yytext = "\\"; return 14; 
586 break;
587 case 1:
588                                    if(yy_.yytext.slice(-1) !== "\\") this.begin("mu");
589                                    if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1), this.begin("emu");
590                                    if(yy_.yytext) return 14;
591                                  
592 break;
593 case 2: return 14; 
594 break;
595 case 3:
596                                    if(yy_.yytext.slice(-1) !== "\\") this.popState();
597                                    if(yy_.yytext.slice(-1) === "\\") yy_.yytext = yy_.yytext.substr(0,yy_.yyleng-1);
598                                    return 14;
599                                  
600 break;
601 case 4: yy_.yytext = yy_.yytext.substr(0, yy_.yyleng-4); this.popState(); return 15; 
602 break;
603 case 5: return 25; 
604 break;
605 case 6: return 16; 
606 break;
607 case 7: return 20; 
608 break;
609 case 8: return 19; 
610 break;
611 case 9: return 19; 
612 break;
613 case 10: return 23; 
614 break;
615 case 11: return 22; 
616 break;
617 case 12: this.popState(); this.begin('com'); 
618 break;
619 case 13: yy_.yytext = yy_.yytext.substr(3,yy_.yyleng-5); this.popState(); return 15; 
620 break;
621 case 14: return 22; 
622 break;
623 case 15: return 37; 
624 break;
625 case 16: return 36; 
626 break;
627 case 17: return 36; 
628 break;
629 case 18: return 40; 
630 break;
631 case 19: /*ignore whitespace*/ 
632 break;
633 case 20: this.popState(); return 24; 
634 break;
635 case 21: this.popState(); return 18; 
636 break;
637 case 22: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\"/g,'"'); return 31; 
638 break;
639 case 23: yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2).replace(/\\'/g,"'"); return 31; 
640 break;
641 case 24: return 38; 
642 break;
643 case 25: return 33; 
644 break;
645 case 26: return 33; 
646 break;
647 case 27: return 32; 
648 break;
649 case 28: return 36; 
650 break;
651 case 29: yy_.yytext = yy_.yytext.substr(1, yy_.yyleng-2); return 36; 
652 break;
653 case 30: return 'INVALID'; 
654 break;
655 case 31: return 5; 
656 break;
657 }
658 };
659 lexer.rules = [/^(?:\\\\(?=(\{\{)))/,/^(?:[^\x00]*?(?=(\{\{)))/,/^(?:[^\x00]+)/,/^(?:[^\x00]{2,}?(?=(\{\{|$)))/,/^(?:[\s\S]*?--\}\})/,/^(?:\{\{>)/,/^(?:\{\{#)/,/^(?:\{\{\/)/,/^(?:\{\{\^)/,/^(?:\{\{\s*else\b)/,/^(?:\{\{\{)/,/^(?:\{\{&)/,/^(?:\{\{!--)/,/^(?:\{\{![\s\S]*?\}\})/,/^(?:\{\{)/,/^(?:=)/,/^(?:\.(?=[}\/ ]))/,/^(?:\.\.)/,/^(?:[\/.])/,/^(?:\s+)/,/^(?:\}\}\})/,/^(?:\}\})/,/^(?:"(\\["]|[^"])*")/,/^(?:'(\\[']|[^'])*')/,/^(?:@)/,/^(?:true(?=[}\s]))/,/^(?:false(?=[}\s]))/,/^(?:-?[0-9]+(?=[}\s]))/,/^(?:[^\s!"#%-,\.\/;->@\[-\^`\{-~]+(?=[=}\s\/.]))/,/^(?:\[[^\]]*\])/,/^(?:.)/,/^(?:$)/];
660 lexer.conditions = {"mu":{"rules":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],"inclusive":false},"emu":{"rules":[3],"inclusive":false},"com":{"rules":[4],"inclusive":false},"INITIAL":{"rules":[0,1,2,31],"inclusive":true}};
661 return lexer;})()
662 parser.lexer = lexer;
663 function Parser () { this.yy = {}; }Parser.prototype = parser;parser.Parser = Parser;
664 return new Parser;
665 })();;
666 // lib/handlebars/compiler/base.js
667
668 Handlebars.Parser = handlebars;
669
670 Handlebars.parse = function(input) {
671
672   // Just return if an already-compile AST was passed in.
673   if(input.constructor === Handlebars.AST.ProgramNode) { return input; }
674
675   Handlebars.Parser.yy = Handlebars.AST;
676   return Handlebars.Parser.parse(input);
677 };
678 ;
679 // lib/handlebars/compiler/ast.js
680 Handlebars.AST = {};
681
682 Handlebars.AST.ProgramNode = function(statements, inverse) {
683   this.type = "program";
684   this.statements = statements;
685   if(inverse) { this.inverse = new Handlebars.AST.ProgramNode(inverse); }
686 };
687
688 Handlebars.AST.MustacheNode = function(rawParams, hash, unescaped) {
689   this.type = "mustache";
690   this.escaped = !unescaped;
691   this.hash = hash;
692
693   var id = this.id = rawParams[0];
694   var params = this.params = rawParams.slice(1);
695
696   // a mustache is an eligible helper if:
697   // * its id is simple (a single part, not `this` or `..`)
698   var eligibleHelper = this.eligibleHelper = id.isSimple;
699
700   // a mustache is definitely a helper if:
701   // * it is an eligible helper, and
702   // * it has at least one parameter or hash segment
703   this.isHelper = eligibleHelper && (params.length || hash);
704
705   // if a mustache is an eligible helper but not a definite
706   // helper, it is ambiguous, and will be resolved in a later
707   // pass or at runtime.
708 };
709
710 Handlebars.AST.PartialNode = function(partialName, context) {
711   this.type         = "partial";
712   this.partialName  = partialName;
713   this.context      = context;
714 };
715
716 Handlebars.AST.BlockNode = function(mustache, program, inverse, close) {
717   var verifyMatch = function(open, close) {
718     if(open.original !== close.original) {
719       throw new Handlebars.Exception(open.original + " doesn't match " + close.original);
720     }
721   };
722
723   verifyMatch(mustache.id, close);
724   this.type = "block";
725   this.mustache = mustache;
726   this.program  = program;
727   this.inverse  = inverse;
728
729   if (this.inverse && !this.program) {
730     this.isInverse = true;
731   }
732 };
733
734 Handlebars.AST.ContentNode = function(string) {
735   this.type = "content";
736   this.string = string;
737 };
738
739 Handlebars.AST.HashNode = function(pairs) {
740   this.type = "hash";
741   this.pairs = pairs;
742 };
743
744 Handlebars.AST.IdNode = function(parts) {
745   this.type = "ID";
746
747   var original = "",
748       dig = [],
749       depth = 0;
750
751   for(var i=0,l=parts.length; i<l; i++) {
752     var part = parts[i].part;
753     original += (parts[i].separator || '') + part;
754
755     if (part === ".." || part === "." || part === "this") {
756       if (dig.length > 0) { throw new Handlebars.Exception("Invalid path: " + original); }
757       else if (part === "..") { depth++; }
758       else { this.isScoped = true; }
759     }
760     else { dig.push(part); }
761   }
762
763   this.original = original;
764   this.parts    = dig;
765   this.string   = dig.join('.');
766   this.depth    = depth;
767
768   // an ID is simple if it only has one part, and that part is not
769   // `..` or `this`.
770   this.isSimple = parts.length === 1 && !this.isScoped && depth === 0;
771
772   this.stringModeValue = this.string;
773 };
774
775 Handlebars.AST.PartialNameNode = function(name) {
776   this.type = "PARTIAL_NAME";
777   this.name = name.original;
778 };
779
780 Handlebars.AST.DataNode = function(id) {
781   this.type = "DATA";
782   this.id = id;
783 };
784
785 Handlebars.AST.StringNode = function(string) {
786   this.type = "STRING";
787   this.original =
788     this.string =
789     this.stringModeValue = string;
790 };
791
792 Handlebars.AST.IntegerNode = function(integer) {
793   this.type = "INTEGER";
794   this.original =
795     this.integer = integer;
796   this.stringModeValue = Number(integer);
797 };
798
799 Handlebars.AST.BooleanNode = function(bool) {
800   this.type = "BOOLEAN";
801   this.bool = bool;
802   this.stringModeValue = bool === "true";
803 };
804
805 Handlebars.AST.CommentNode = function(comment) {
806   this.type = "comment";
807   this.comment = comment;
808 };
809 ;
810 // lib/handlebars/utils.js
811
812 var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
813
814 Handlebars.Exception = function(message) {
815   var tmp = Error.prototype.constructor.apply(this, arguments);
816
817   // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
818   for (var idx = 0; idx < errorProps.length; idx++) {
819     this[errorProps[idx]] = tmp[errorProps[idx]];
820   }
821 };
822 Handlebars.Exception.prototype = new Error();
823
824 // Build out our basic SafeString type
825 Handlebars.SafeString = function(string) {
826   this.string = string;
827 };
828 Handlebars.SafeString.prototype.toString = function() {
829   return this.string.toString();
830 };
831
832 var escape = {
833   "&": "&amp;",
834   "<": "&lt;",
835   ">": "&gt;",
836   '"': "&quot;",
837   "'": "&#x27;",
838   "`": "&#x60;"
839 };
840
841 var badChars = /[&<>"'`]/g;
842 var possible = /[&<>"'`]/;
843
844 var escapeChar = function(chr) {
845   return escape[chr] || "&amp;";
846 };
847
848 Handlebars.Utils = {
849   extend: function(obj, value) {
850     for(var key in value) {
851       if(value.hasOwnProperty(key)) {
852         obj[key] = value[key];
853       }
854     }
855   },
856
857   escapeExpression: function(string) {
858     // don't escape SafeStrings, since they're already safe
859     if (string instanceof Handlebars.SafeString) {
860       return string.toString();
861     } else if (string == null || string === false) {
862       return "";
863     }
864
865     // Force a string conversion as this will be done by the append regardless and
866     // the regex test will do this transparently behind the scenes, causing issues if
867     // an object's to string has escaped characters in it.
868     string = string.toString();
869
870     if(!possible.test(string)) { return string; }
871     return string.replace(badChars, escapeChar);
872   },
873
874   isEmpty: function(value) {
875     if (!value && value !== 0) {
876       return true;
877     } else if(toString.call(value) === "[object Array]" && value.length === 0) {
878       return true;
879     } else {
880       return false;
881     }
882   }
883 };
884 ;
885 // lib/handlebars/compiler/compiler.js
886
887 /*jshint eqnull:true*/
888 var Compiler = Handlebars.Compiler = function() {};
889 var JavaScriptCompiler = Handlebars.JavaScriptCompiler = function() {};
890
891 // the foundHelper register will disambiguate helper lookup from finding a
892 // function in a context. This is necessary for mustache compatibility, which
893 // requires that context functions in blocks are evaluated by blockHelperMissing,
894 // and then proceed as if the resulting value was provided to blockHelperMissing.
895
896 Compiler.prototype = {
897   compiler: Compiler,
898
899   disassemble: function() {
900     var opcodes = this.opcodes, opcode, out = [], params, param;
901
902     for (var i=0, l=opcodes.length; i<l; i++) {
903       opcode = opcodes[i];
904
905       if (opcode.opcode === 'DECLARE') {
906         out.push("DECLARE " + opcode.name + "=" + opcode.value);
907       } else {
908         params = [];
909         for (var j=0; j<opcode.args.length; j++) {
910           param = opcode.args[j];
911           if (typeof param === "string") {
912             param = "\"" + param.replace("\n", "\\n") + "\"";
913           }
914           params.push(param);
915         }
916         out.push(opcode.opcode + " " + params.join(" "));
917       }
918     }
919
920     return out.join("\n");
921   },
922   equals: function(other) {
923     var len = this.opcodes.length;
924     if (other.opcodes.length !== len) {
925       return false;
926     }
927
928     for (var i = 0; i < len; i++) {
929       var opcode = this.opcodes[i],
930           otherOpcode = other.opcodes[i];
931       if (opcode.opcode !== otherOpcode.opcode || opcode.args.length !== otherOpcode.args.length) {
932         return false;
933       }
934       for (var j = 0; j < opcode.args.length; j++) {
935         if (opcode.args[j] !== otherOpcode.args[j]) {
936           return false;
937         }
938       }
939     }
940
941     len = this.children.length;
942     if (other.children.length !== len) {
943       return false;
944     }
945     for (i = 0; i < len; i++) {
946       if (!this.children[i].equals(other.children[i])) {
947         return false;
948       }
949     }
950
951     return true;
952   },
953
954   guid: 0,
955
956   compile: function(program, options) {
957     this.children = [];
958     this.depths = {list: []};
959     this.options = options;
960
961     // These changes will propagate to the other compiler components
962     var knownHelpers = this.options.knownHelpers;
963     this.options.knownHelpers = {
964       'helperMissing': true,
965       'blockHelperMissing': true,
966       'each': true,
967       'if': true,
968       'unless': true,
969       'with': true,
970       'log': true
971     };
972     if (knownHelpers) {
973       for (var name in knownHelpers) {
974         this.options.knownHelpers[name] = knownHelpers[name];
975       }
976     }
977
978     return this.program(program);
979   },
980
981   accept: function(node) {
982     return this[node.type](node);
983   },
984
985   program: function(program) {
986     var statements = program.statements, statement;
987     this.opcodes = [];
988
989     for(var i=0, l=statements.length; i<l; i++) {
990       statement = statements[i];
991       this[statement.type](statement);
992     }
993     this.isSimple = l === 1;
994
995     this.depths.list = this.depths.list.sort(function(a, b) {
996       return a - b;
997     });
998
999     return this;
1000   },
1001
1002   compileProgram: function(program) {
1003     var result = new this.compiler().compile(program, this.options);
1004     var guid = this.guid++, depth;
1005
1006     this.usePartial = this.usePartial || result.usePartial;
1007
1008     this.children[guid] = result;
1009
1010     for(var i=0, l=result.depths.list.length; i<l; i++) {
1011       depth = result.depths.list[i];
1012
1013       if(depth < 2) { continue; }
1014       else { this.addDepth(depth - 1); }
1015     }
1016
1017     return guid;
1018   },
1019
1020   block: function(block) {
1021     var mustache = block.mustache,
1022         program = block.program,
1023         inverse = block.inverse;
1024
1025     if (program) {
1026       program = this.compileProgram(program);
1027     }
1028
1029     if (inverse) {
1030       inverse = this.compileProgram(inverse);
1031     }
1032
1033     var type = this.classifyMustache(mustache);
1034
1035     if (type === "helper") {
1036       this.helperMustache(mustache, program, inverse);
1037     } else if (type === "simple") {
1038       this.simpleMustache(mustache);
1039
1040       // now that the simple mustache is resolved, we need to
1041       // evaluate it by executing `blockHelperMissing`
1042       this.opcode('pushProgram', program);
1043       this.opcode('pushProgram', inverse);
1044       this.opcode('emptyHash');
1045       this.opcode('blockValue');
1046     } else {
1047       this.ambiguousMustache(mustache, program, inverse);
1048
1049       // now that the simple mustache is resolved, we need to
1050       // evaluate it by executing `blockHelperMissing`
1051       this.opcode('pushProgram', program);
1052       this.opcode('pushProgram', inverse);
1053       this.opcode('emptyHash');
1054       this.opcode('ambiguousBlockValue');
1055     }
1056
1057     this.opcode('append');
1058   },
1059
1060   hash: function(hash) {
1061     var pairs = hash.pairs, pair, val;
1062
1063     this.opcode('pushHash');
1064
1065     for(var i=0, l=pairs.length; i<l; i++) {
1066       pair = pairs[i];
1067       val  = pair[1];
1068
1069       if (this.options.stringParams) {
1070         if(val.depth) {
1071           this.addDepth(val.depth);
1072         }
1073         this.opcode('getContext', val.depth || 0);
1074         this.opcode('pushStringParam', val.stringModeValue, val.type);
1075       } else {
1076         this.accept(val);
1077       }
1078
1079       this.opcode('assignToHash', pair[0]);
1080     }
1081     this.opcode('popHash');
1082   },
1083
1084   partial: function(partial) {
1085     var partialName = partial.partialName;
1086     this.usePartial = true;
1087
1088     if(partial.context) {
1089       this.ID(partial.context);
1090     } else {
1091       this.opcode('push', 'depth0');
1092     }
1093
1094     this.opcode('invokePartial', partialName.name);
1095     this.opcode('append');
1096   },
1097
1098   content: function(content) {
1099     this.opcode('appendContent', content.string);
1100   },
1101
1102   mustache: function(mustache) {
1103     var options = this.options;
1104     var type = this.classifyMustache(mustache);
1105
1106     if (type === "simple") {
1107       this.simpleMustache(mustache);
1108     } else if (type === "helper") {
1109       this.helperMustache(mustache);
1110     } else {
1111       this.ambiguousMustache(mustache);
1112     }
1113
1114     if(mustache.escaped && !options.noEscape) {
1115       this.opcode('appendEscaped');
1116     } else {
1117       this.opcode('append');
1118     }
1119   },
1120
1121   ambiguousMustache: function(mustache, program, inverse) {
1122     var id = mustache.id,
1123         name = id.parts[0],
1124         isBlock = program != null || inverse != null;
1125
1126     this.opcode('getContext', id.depth);
1127
1128     this.opcode('pushProgram', program);
1129     this.opcode('pushProgram', inverse);
1130
1131     this.opcode('invokeAmbiguous', name, isBlock);
1132   },
1133
1134   simpleMustache: function(mustache) {
1135     var id = mustache.id;
1136
1137     if (id.type === 'DATA') {
1138       this.DATA(id);
1139     } else if (id.parts.length) {
1140       this.ID(id);
1141     } else {
1142       // Simplified ID for `this`
1143       this.addDepth(id.depth);
1144       this.opcode('getContext', id.depth);
1145       this.opcode('pushContext');
1146     }
1147
1148     this.opcode('resolvePossibleLambda');
1149   },
1150
1151   helperMustache: function(mustache, program, inverse) {
1152     var params = this.setupFullMustacheParams(mustache, program, inverse),
1153         name = mustache.id.parts[0];
1154
1155     if (this.options.knownHelpers[name]) {
1156       this.opcode('invokeKnownHelper', params.length, name);
1157     } else if (this.options.knownHelpersOnly) {
1158       throw new Error("You specified knownHelpersOnly, but used the unknown helper " + name);
1159     } else {
1160       this.opcode('invokeHelper', params.length, name);
1161     }
1162   },
1163
1164   ID: function(id) {
1165     this.addDepth(id.depth);
1166     this.opcode('getContext', id.depth);
1167
1168     var name = id.parts[0];
1169     if (!name) {
1170       this.opcode('pushContext');
1171     } else {
1172       this.opcode('lookupOnContext', id.parts[0]);
1173     }
1174
1175     for(var i=1, l=id.parts.length; i<l; i++) {
1176       this.opcode('lookup', id.parts[i]);
1177     }
1178   },
1179
1180   DATA: function(data) {
1181     this.options.data = true;
1182     if (data.id.isScoped || data.id.depth) {
1183       throw new Handlebars.Exception('Scoped data references are not supported: ' + data.original);
1184     }
1185
1186     this.opcode('lookupData');
1187     var parts = data.id.parts;
1188     for(var i=0, l=parts.length; i<l; i++) {
1189       this.opcode('lookup', parts[i]);
1190     }
1191   },
1192
1193   STRING: function(string) {
1194     this.opcode('pushString', string.string);
1195   },
1196
1197   INTEGER: function(integer) {
1198     this.opcode('pushLiteral', integer.integer);
1199   },
1200
1201   BOOLEAN: function(bool) {
1202     this.opcode('pushLiteral', bool.bool);
1203   },
1204
1205   comment: function() {},
1206
1207   // HELPERS
1208   opcode: function(name) {
1209     this.opcodes.push({ opcode: name, args: [].slice.call(arguments, 1) });
1210   },
1211
1212   declare: function(name, value) {
1213     this.opcodes.push({ opcode: 'DECLARE', name: name, value: value });
1214   },
1215
1216   addDepth: function(depth) {
1217     if(isNaN(depth)) { throw new Error("EWOT"); }
1218     if(depth === 0) { return; }
1219
1220     if(!this.depths[depth]) {
1221       this.depths[depth] = true;
1222       this.depths.list.push(depth);
1223     }
1224   },
1225
1226   classifyMustache: function(mustache) {
1227     var isHelper   = mustache.isHelper;
1228     var isEligible = mustache.eligibleHelper;
1229     var options    = this.options;
1230
1231     // if ambiguous, we can possibly resolve the ambiguity now
1232     if (isEligible && !isHelper) {
1233       var name = mustache.id.parts[0];
1234
1235       if (options.knownHelpers[name]) {
1236         isHelper = true;
1237       } else if (options.knownHelpersOnly) {
1238         isEligible = false;
1239       }
1240     }
1241
1242     if (isHelper) { return "helper"; }
1243     else if (isEligible) { return "ambiguous"; }
1244     else { return "simple"; }
1245   },
1246
1247   pushParams: function(params) {
1248     var i = params.length, param;
1249
1250     while(i--) {
1251       param = params[i];
1252
1253       if(this.options.stringParams) {
1254         if(param.depth) {
1255           this.addDepth(param.depth);
1256         }
1257
1258         this.opcode('getContext', param.depth || 0);
1259         this.opcode('pushStringParam', param.stringModeValue, param.type);
1260       } else {
1261         this[param.type](param);
1262       }
1263     }
1264   },
1265
1266   setupMustacheParams: function(mustache) {
1267     var params = mustache.params;
1268     this.pushParams(params);
1269
1270     if(mustache.hash) {
1271       this.hash(mustache.hash);
1272     } else {
1273       this.opcode('emptyHash');
1274     }
1275
1276     return params;
1277   },
1278
1279   // this will replace setupMustacheParams when we're done
1280   setupFullMustacheParams: function(mustache, program, inverse) {
1281     var params = mustache.params;
1282     this.pushParams(params);
1283
1284     this.opcode('pushProgram', program);
1285     this.opcode('pushProgram', inverse);
1286
1287     if(mustache.hash) {
1288       this.hash(mustache.hash);
1289     } else {
1290       this.opcode('emptyHash');
1291     }
1292
1293     return params;
1294   }
1295 };
1296
1297 var Literal = function(value) {
1298   this.value = value;
1299 };
1300
1301 JavaScriptCompiler.prototype = {
1302   // PUBLIC API: You can override these methods in a subclass to provide
1303   // alternative compiled forms for name lookup and buffering semantics
1304   nameLookup: function(parent, name /* , type*/) {
1305     if (/^[0-9]+$/.test(name)) {
1306       return parent + "[" + name + "]";
1307     } else if (JavaScriptCompiler.isValidJavaScriptVariableName(name)) {
1308       return parent + "." + name;
1309     }
1310     else {
1311       return parent + "['" + name + "']";
1312     }
1313   },
1314
1315   appendToBuffer: function(string) {
1316     if (this.environment.isSimple) {
1317       return "return " + string + ";";
1318     } else {
1319       return {
1320         appendToBuffer: true,
1321         content: string,
1322         toString: function() { return "buffer += " + string + ";"; }
1323       };
1324     }
1325   },
1326
1327   initializeBuffer: function() {
1328     return this.quotedString("");
1329   },
1330
1331   namespace: "Handlebars",
1332   // END PUBLIC API
1333
1334   compile: function(environment, options, context, asObject) {
1335     this.environment = environment;
1336     this.options = options || {};
1337
1338     Handlebars.log(Handlebars.logger.DEBUG, this.environment.disassemble() + "\n\n");
1339
1340     this.name = this.environment.name;
1341     this.isChild = !!context;
1342     this.context = context || {
1343       programs: [],
1344       environments: [],
1345       aliases: { }
1346     };
1347
1348     this.preamble();
1349
1350     this.stackSlot = 0;
1351     this.stackVars = [];
1352     this.registers = { list: [] };
1353     this.compileStack = [];
1354     this.inlineStack = [];
1355
1356     this.compileChildren(environment, options);
1357
1358     var opcodes = environment.opcodes, opcode;
1359
1360     this.i = 0;
1361
1362     for(l=opcodes.length; this.i<l; this.i++) {
1363       opcode = opcodes[this.i];
1364
1365       if(opcode.opcode === 'DECLARE') {
1366         this[opcode.name] = opcode.value;
1367       } else {
1368         this[opcode.opcode].apply(this, opcode.args);
1369       }
1370     }
1371
1372     return this.createFunctionContext(asObject);
1373   },
1374
1375   nextOpcode: function() {
1376     var opcodes = this.environment.opcodes;
1377     return opcodes[this.i + 1];
1378   },
1379
1380   eat: function() {
1381     this.i = this.i + 1;
1382   },
1383
1384   preamble: function() {
1385     var out = [];
1386
1387     if (!this.isChild) {
1388       var namespace = this.namespace;
1389
1390       var copies = "helpers = this.merge(helpers, " + namespace + ".helpers);";
1391       if (this.environment.usePartial) { copies = copies + " partials = this.merge(partials, " + namespace + ".partials);"; }
1392       if (this.options.data) { copies = copies + " data = data || {};"; }
1393       out.push(copies);
1394     } else {
1395       out.push('');
1396     }
1397
1398     if (!this.environment.isSimple) {
1399       out.push(", buffer = " + this.initializeBuffer());
1400     } else {
1401       out.push("");
1402     }
1403
1404     // track the last context pushed into place to allow skipping the
1405     // getContext opcode when it would be a noop
1406     this.lastContext = 0;
1407     this.source = out;
1408   },
1409
1410   createFunctionContext: function(asObject) {
1411     var locals = this.stackVars.concat(this.registers.list);
1412
1413     if(locals.length > 0) {
1414       this.source[1] = this.source[1] + ", " + locals.join(", ");
1415     }
1416
1417     // Generate minimizer alias mappings
1418     if (!this.isChild) {
1419       for (var alias in this.context.aliases) {
1420         if (this.context.aliases.hasOwnProperty(alias)) {
1421           this.source[1] = this.source[1] + ', ' + alias + '=' + this.context.aliases[alias];
1422         }
1423       }
1424     }
1425
1426     if (this.source[1]) {
1427       this.source[1] = "var " + this.source[1].substring(2) + ";";
1428     }
1429
1430     // Merge children
1431     if (!this.isChild) {
1432       this.source[1] += '\n' + this.context.programs.join('\n') + '\n';
1433     }
1434
1435     if (!this.environment.isSimple) {
1436       this.source.push("return buffer;");
1437     }
1438
1439     var params = this.isChild ? ["depth0", "data"] : ["Handlebars", "depth0", "helpers", "partials", "data"];
1440
1441     for(var i=0, l=this.environment.depths.list.length; i<l; i++) {
1442       params.push("depth" + this.environment.depths.list[i]);
1443     }
1444
1445     // Perform a second pass over the output to merge content when possible
1446     var source = this.mergeSource();
1447
1448     if (!this.isChild) {
1449       var revision = Handlebars.COMPILER_REVISION,
1450           versions = Handlebars.REVISION_CHANGES[revision];
1451       source = "this.compilerInfo = ["+revision+",'"+versions+"'];\n"+source;
1452     }
1453
1454     if (asObject) {
1455       params.push(source);
1456
1457       return Function.apply(this, params);
1458     } else {
1459       var functionSource = 'function ' + (this.name || '') + '(' + params.join(',') + ') {\n  ' + source + '}';
1460       Handlebars.log(Handlebars.logger.DEBUG, functionSource + "\n\n");
1461       return functionSource;
1462     }
1463   },
1464   mergeSource: function() {
1465     // WARN: We are not handling the case where buffer is still populated as the source should
1466     // not have buffer append operations as their final action.
1467     var source = '',
1468         buffer;
1469     for (var i = 0, len = this.source.length; i < len; i++) {
1470       var line = this.source[i];
1471       if (line.appendToBuffer) {
1472         if (buffer) {
1473           buffer = buffer + '\n    + ' + line.content;
1474         } else {
1475           buffer = line.content;
1476         }
1477       } else {
1478         if (buffer) {
1479           source += 'buffer += ' + buffer + ';\n  ';
1480           buffer = undefined;
1481         }
1482         source += line + '\n  ';
1483       }
1484     }
1485     return source;
1486   },
1487
1488   // [blockValue]
1489   //
1490   // On stack, before: hash, inverse, program, value
1491   // On stack, after: return value of blockHelperMissing
1492   //
1493   // The purpose of this opcode is to take a block of the form
1494   // `{{#foo}}...{{/foo}}`, resolve the value of `foo`, and
1495   // replace it on the stack with the result of properly
1496   // invoking blockHelperMissing.
1497   blockValue: function() {
1498     this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1499
1500     var params = ["depth0"];
1501     this.setupParams(0, params);
1502
1503     this.replaceStack(function(current) {
1504       params.splice(1, 0, current);
1505       return "blockHelperMissing.call(" + params.join(", ") + ")";
1506     });
1507   },
1508
1509   // [ambiguousBlockValue]
1510   //
1511   // On stack, before: hash, inverse, program, value
1512   // Compiler value, before: lastHelper=value of last found helper, if any
1513   // On stack, after, if no lastHelper: same as [blockValue]
1514   // On stack, after, if lastHelper: value
1515   ambiguousBlockValue: function() {
1516     this.context.aliases.blockHelperMissing = 'helpers.blockHelperMissing';
1517
1518     var params = ["depth0"];
1519     this.setupParams(0, params);
1520
1521     var current = this.topStack();
1522     params.splice(1, 0, current);
1523
1524     // Use the options value generated from the invocation
1525     params[params.length-1] = 'options';
1526
1527     this.source.push("if (!" + this.lastHelper + ") { " + current + " = blockHelperMissing.call(" + params.join(", ") + "); }");
1528   },
1529
1530   // [appendContent]
1531   //
1532   // On stack, before: ...
1533   // On stack, after: ...
1534   //
1535   // Appends the string value of `content` to the current buffer
1536   appendContent: function(content) {
1537     this.source.push(this.appendToBuffer(this.quotedString(content)));
1538   },
1539
1540   // [append]
1541   //
1542   // On stack, before: value, ...
1543   // On stack, after: ...
1544   //
1545   // Coerces `value` to a String and appends it to the current buffer.
1546   //
1547   // If `value` is truthy, or 0, it is coerced into a string and appended
1548   // Otherwise, the empty string is appended
1549   append: function() {
1550     // Force anything that is inlined onto the stack so we don't have duplication
1551     // when we examine local
1552     this.flushInline();
1553     var local = this.popStack();
1554     this.source.push("if(" + local + " || " + local + " === 0) { " + this.appendToBuffer(local) + " }");
1555     if (this.environment.isSimple) {
1556       this.source.push("else { " + this.appendToBuffer("''") + " }");
1557     }
1558   },
1559
1560   // [appendEscaped]
1561   //
1562   // On stack, before: value, ...
1563   // On stack, after: ...
1564   //
1565   // Escape `value` and append it to the buffer
1566   appendEscaped: function() {
1567     this.context.aliases.escapeExpression = 'this.escapeExpression';
1568
1569     this.source.push(this.appendToBuffer("escapeExpression(" + this.popStack() + ")"));
1570   },
1571
1572   // [getContext]
1573   //
1574   // On stack, before: ...
1575   // On stack, after: ...
1576   // Compiler value, after: lastContext=depth
1577   //
1578   // Set the value of the `lastContext` compiler value to the depth
1579   getContext: function(depth) {
1580     if(this.lastContext !== depth) {
1581       this.lastContext = depth;
1582     }
1583   },
1584
1585   // [lookupOnContext]
1586   //
1587   // On stack, before: ...
1588   // On stack, after: currentContext[name], ...
1589   //
1590   // Looks up the value of `name` on the current context and pushes
1591   // it onto the stack.
1592   lookupOnContext: function(name) {
1593     this.push(this.nameLookup('depth' + this.lastContext, name, 'context'));
1594   },
1595
1596   // [pushContext]
1597   //
1598   // On stack, before: ...
1599   // On stack, after: currentContext, ...
1600   //
1601   // Pushes the value of the current context onto the stack.
1602   pushContext: function() {
1603     this.pushStackLiteral('depth' + this.lastContext);
1604   },
1605
1606   // [resolvePossibleLambda]
1607   //
1608   // On stack, before: value, ...
1609   // On stack, after: resolved value, ...
1610   //
1611   // If the `value` is a lambda, replace it on the stack by
1612   // the return value of the lambda
1613   resolvePossibleLambda: function() {
1614     this.context.aliases.functionType = '"function"';
1615
1616     this.replaceStack(function(current) {
1617       return "typeof " + current + " === functionType ? " + current + ".apply(depth0) : " + current;
1618     });
1619   },
1620
1621   // [lookup]
1622   //
1623   // On stack, before: value, ...
1624   // On stack, after: value[name], ...
1625   //
1626   // Replace the value on the stack with the result of looking
1627   // up `name` on `value`
1628   lookup: function(name) {
1629     this.replaceStack(function(current) {
1630       return current + " == null || " + current + " === false ? " + current + " : " + this.nameLookup(current, name, 'context');
1631     });
1632   },
1633
1634   // [lookupData]
1635   //
1636   // On stack, before: ...
1637   // On stack, after: data[id], ...
1638   //
1639   // Push the result of looking up `id` on the current data
1640   lookupData: function(id) {
1641     this.push('data');
1642   },
1643
1644   // [pushStringParam]
1645   //
1646   // On stack, before: ...
1647   // On stack, after: string, currentContext, ...
1648   //
1649   // This opcode is designed for use in string mode, which
1650   // provides the string value of a parameter along with its
1651   // depth rather than resolving it immediately.
1652   pushStringParam: function(string, type) {
1653     this.pushStackLiteral('depth' + this.lastContext);
1654
1655     this.pushString(type);
1656
1657     if (typeof string === 'string') {
1658       this.pushString(string);
1659     } else {
1660       this.pushStackLiteral(string);
1661     }
1662   },
1663
1664   emptyHash: function() {
1665     this.pushStackLiteral('{}');
1666
1667     if (this.options.stringParams) {
1668       this.register('hashTypes', '{}');
1669       this.register('hashContexts', '{}');
1670     }
1671   },
1672   pushHash: function() {
1673     this.hash = {values: [], types: [], contexts: []};
1674   },
1675   popHash: function() {
1676     var hash = this.hash;
1677     this.hash = undefined;
1678
1679     if (this.options.stringParams) {
1680       this.register('hashContexts', '{' + hash.contexts.join(',') + '}');
1681       this.register('hashTypes', '{' + hash.types.join(',') + '}');
1682     }
1683     this.push('{\n    ' + hash.values.join(',\n    ') + '\n  }');
1684   },
1685
1686   // [pushString]
1687   //
1688   // On stack, before: ...
1689   // On stack, after: quotedString(string), ...
1690   //
1691   // Push a quoted version of `string` onto the stack
1692   pushString: function(string) {
1693     this.pushStackLiteral(this.quotedString(string));
1694   },
1695
1696   // [push]
1697   //
1698   // On stack, before: ...
1699   // On stack, after: expr, ...
1700   //
1701   // Push an expression onto the stack
1702   push: function(expr) {
1703     this.inlineStack.push(expr);
1704     return expr;
1705   },
1706
1707   // [pushLiteral]
1708   //
1709   // On stack, before: ...
1710   // On stack, after: value, ...
1711   //
1712   // Pushes a value onto the stack. This operation prevents
1713   // the compiler from creating a temporary variable to hold
1714   // it.
1715   pushLiteral: function(value) {
1716     this.pushStackLiteral(value);
1717   },
1718
1719   // [pushProgram]
1720   //
1721   // On stack, before: ...
1722   // On stack, after: program(guid), ...
1723   //
1724   // Push a program expression onto the stack. This takes
1725   // a compile-time guid and converts it into a runtime-accessible
1726   // expression.
1727   pushProgram: function(guid) {
1728     if (guid != null) {
1729       this.pushStackLiteral(this.programExpression(guid));
1730     } else {
1731       this.pushStackLiteral(null);
1732     }
1733   },
1734
1735   // [invokeHelper]
1736   //
1737   // On stack, before: hash, inverse, program, params..., ...
1738   // On stack, after: result of helper invocation
1739   //
1740   // Pops off the helper's parameters, invokes the helper,
1741   // and pushes the helper's return value onto the stack.
1742   //
1743   // If the helper is not found, `helperMissing` is called.
1744   invokeHelper: function(paramSize, name) {
1745     this.context.aliases.helperMissing = 'helpers.helperMissing';
1746
1747     var helper = this.lastHelper = this.setupHelper(paramSize, name, true);
1748     var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1749
1750     this.push(helper.name + ' || ' + nonHelper);
1751     this.replaceStack(function(name) {
1752       return name + ' ? ' + name + '.call(' +
1753           helper.callParams + ") " + ": helperMissing.call(" +
1754           helper.helperMissingParams + ")";
1755     });
1756   },
1757
1758   // [invokeKnownHelper]
1759   //
1760   // On stack, before: hash, inverse, program, params..., ...
1761   // On stack, after: result of helper invocation
1762   //
1763   // This operation is used when the helper is known to exist,
1764   // so a `helperMissing` fallback is not required.
1765   invokeKnownHelper: function(paramSize, name) {
1766     var helper = this.setupHelper(paramSize, name);
1767     this.push(helper.name + ".call(" + helper.callParams + ")");
1768   },
1769
1770   // [invokeAmbiguous]
1771   //
1772   // On stack, before: hash, inverse, program, params..., ...
1773   // On stack, after: result of disambiguation
1774   //
1775   // This operation is used when an expression like `{{foo}}`
1776   // is provided, but we don't know at compile-time whether it
1777   // is a helper or a path.
1778   //
1779   // This operation emits more code than the other options,
1780   // and can be avoided by passing the `knownHelpers` and
1781   // `knownHelpersOnly` flags at compile-time.
1782   invokeAmbiguous: function(name, helperCall) {
1783     this.context.aliases.functionType = '"function"';
1784
1785     this.pushStackLiteral('{}');    // Hash value
1786     var helper = this.setupHelper(0, name, helperCall);
1787
1788     var helperName = this.lastHelper = this.nameLookup('helpers', name, 'helper');
1789
1790     var nonHelper = this.nameLookup('depth' + this.lastContext, name, 'context');
1791     var nextStack = this.nextStack();
1792
1793     this.source.push('if (' + nextStack + ' = ' + helperName + ') { ' + nextStack + ' = ' + nextStack + '.call(' + helper.callParams + '); }');
1794     this.source.push('else { ' + nextStack + ' = ' + nonHelper + '; ' + nextStack + ' = typeof ' + nextStack + ' === functionType ? ' + nextStack + '.apply(depth0) : ' + nextStack + '; }');
1795   },
1796
1797   // [invokePartial]
1798   //
1799   // On stack, before: context, ...
1800   // On stack after: result of partial invocation
1801   //
1802   // This operation pops off a context, invokes a partial with that context,
1803   // and pushes the result of the invocation back.
1804   invokePartial: function(name) {
1805     var params = [this.nameLookup('partials', name, 'partial'), "'" + name + "'", this.popStack(), "helpers", "partials"];
1806
1807     if (this.options.data) {
1808       params.push("data");
1809     }
1810
1811     this.context.aliases.self = "this";
1812     this.push("self.invokePartial(" + params.join(", ") + ")");
1813   },
1814
1815   // [assignToHash]
1816   //
1817   // On stack, before: value, hash, ...
1818   // On stack, after: hash, ...
1819   //
1820   // Pops a value and hash off the stack, assigns `hash[key] = value`
1821   // and pushes the hash back onto the stack.
1822   assignToHash: function(key) {
1823     var value = this.popStack(),
1824         context,
1825         type;
1826
1827     if (this.options.stringParams) {
1828       type = this.popStack();
1829       context = this.popStack();
1830     }
1831
1832     var hash = this.hash;
1833     if (context) {
1834       hash.contexts.push("'" + key + "': " + context);
1835     }
1836     if (type) {
1837       hash.types.push("'" + key + "': " + type);
1838     }
1839     hash.values.push("'" + key + "': (" + value + ")");
1840   },
1841
1842   // HELPERS
1843
1844   compiler: JavaScriptCompiler,
1845
1846   compileChildren: function(environment, options) {
1847     var children = environment.children, child, compiler;
1848
1849     for(var i=0, l=children.length; i<l; i++) {
1850       child = children[i];
1851       compiler = new this.compiler();
1852
1853       var index = this.matchExistingProgram(child);
1854
1855       if (index == null) {
1856         this.context.programs.push('');     // Placeholder to prevent name conflicts for nested children
1857         index = this.context.programs.length;
1858         child.index = index;
1859         child.name = 'program' + index;
1860         this.context.programs[index] = compiler.compile(child, options, this.context);
1861         this.context.environments[index] = child;
1862       } else {
1863         child.index = index;
1864         child.name = 'program' + index;
1865       }
1866     }
1867   },
1868   matchExistingProgram: function(child) {
1869     for (var i = 0, len = this.context.environments.length; i < len; i++) {
1870       var environment = this.context.environments[i];
1871       if (environment && environment.equals(child)) {
1872         return i;
1873       }
1874     }
1875   },
1876
1877   programExpression: function(guid) {
1878     this.context.aliases.self = "this";
1879
1880     if(guid == null) {
1881       return "self.noop";
1882     }
1883
1884     var child = this.environment.children[guid],
1885         depths = child.depths.list, depth;
1886
1887     var programParams = [child.index, child.name, "data"];
1888
1889     for(var i=0, l = depths.length; i<l; i++) {
1890       depth = depths[i];
1891
1892       if(depth === 1) { programParams.push("depth0"); }
1893       else { programParams.push("depth" + (depth - 1)); }
1894     }
1895
1896     return (depths.length === 0 ? "self.program(" : "self.programWithDepth(") + programParams.join(", ") + ")";
1897   },
1898
1899   register: function(name, val) {
1900     this.useRegister(name);
1901     this.source.push(name + " = " + val + ";");
1902   },
1903
1904   useRegister: function(name) {
1905     if(!this.registers[name]) {
1906       this.registers[name] = true;
1907       this.registers.list.push(name);
1908     }
1909   },
1910
1911   pushStackLiteral: function(item) {
1912     return this.push(new Literal(item));
1913   },
1914
1915   pushStack: function(item) {
1916     this.flushInline();
1917
1918     var stack = this.incrStack();
1919     if (item) {
1920       this.source.push(stack + " = " + item + ";");
1921     }
1922     this.compileStack.push(stack);
1923     return stack;
1924   },
1925
1926   replaceStack: function(callback) {
1927     var prefix = '',
1928         inline = this.isInline(),
1929         stack;
1930
1931     // If we are currently inline then we want to merge the inline statement into the
1932     // replacement statement via ','
1933     if (inline) {
1934       var top = this.popStack(true);
1935
1936       if (top instanceof Literal) {
1937         // Literals do not need to be inlined
1938         stack = top.value;
1939       } else {
1940         // Get or create the current stack name for use by the inline
1941         var name = this.stackSlot ? this.topStackName() : this.incrStack();
1942
1943         prefix = '(' + this.push(name) + ' = ' + top + '),';
1944         stack = this.topStack();
1945       }
1946     } else {
1947       stack = this.topStack();
1948     }
1949
1950     var item = callback.call(this, stack);
1951
1952     if (inline) {
1953       if (this.inlineStack.length || this.compileStack.length) {
1954         this.popStack();
1955       }
1956       this.push('(' + prefix + item + ')');
1957     } else {
1958       // Prevent modification of the context depth variable. Through replaceStack
1959       if (!/^stack/.test(stack)) {
1960         stack = this.nextStack();
1961       }
1962
1963       this.source.push(stack + " = (" + prefix + item + ");");
1964     }
1965     return stack;
1966   },
1967
1968   nextStack: function() {
1969     return this.pushStack();
1970   },
1971
1972   incrStack: function() {
1973     this.stackSlot++;
1974     if(this.stackSlot > this.stackVars.length) { this.stackVars.push("stack" + this.stackSlot); }
1975     return this.topStackName();
1976   },
1977   topStackName: function() {
1978     return "stack" + this.stackSlot;
1979   },
1980   flushInline: function() {
1981     var inlineStack = this.inlineStack;
1982     if (inlineStack.length) {
1983       this.inlineStack = [];
1984       for (var i = 0, len = inlineStack.length; i < len; i++) {
1985         var entry = inlineStack[i];
1986         if (entry instanceof Literal) {
1987           this.compileStack.push(entry);
1988         } else {
1989           this.pushStack(entry);
1990         }
1991       }
1992     }
1993   },
1994   isInline: function() {
1995     return this.inlineStack.length;
1996   },
1997
1998   popStack: function(wrapped) {
1999     var inline = this.isInline(),
2000         item = (inline ? this.inlineStack : this.compileStack).pop();
2001
2002     if (!wrapped && (item instanceof Literal)) {
2003       return item.value;
2004     } else {
2005       if (!inline) {
2006         this.stackSlot--;
2007       }
2008       return item;
2009     }
2010   },
2011
2012   topStack: function(wrapped) {
2013     var stack = (this.isInline() ? this.inlineStack : this.compileStack),
2014         item = stack[stack.length - 1];
2015
2016     if (!wrapped && (item instanceof Literal)) {
2017       return item.value;
2018     } else {
2019       return item;
2020     }
2021   },
2022
2023   quotedString: function(str) {
2024     return '"' + str
2025       .replace(/\\/g, '\\\\')
2026       .replace(/"/g, '\\"')
2027       .replace(/\n/g, '\\n')
2028       .replace(/\r/g, '\\r')
2029       .replace(/\u2028/g, '\\u2028')   // Per Ecma-262 7.3 + 7.8.4
2030       .replace(/\u2029/g, '\\u2029') + '"';
2031   },
2032
2033   setupHelper: function(paramSize, name, missingParams) {
2034     var params = [];
2035     this.setupParams(paramSize, params, missingParams);
2036     var foundHelper = this.nameLookup('helpers', name, 'helper');
2037
2038     return {
2039       params: params,
2040       name: foundHelper,
2041       callParams: ["depth0"].concat(params).join(", "),
2042       helperMissingParams: missingParams && ["depth0", this.quotedString(name)].concat(params).join(", ")
2043     };
2044   },
2045
2046   // the params and contexts arguments are passed in arrays
2047   // to fill in
2048   setupParams: function(paramSize, params, useRegister) {
2049     var options = [], contexts = [], types = [], param, inverse, program;
2050
2051     options.push("hash:" + this.popStack());
2052
2053     inverse = this.popStack();
2054     program = this.popStack();
2055
2056     // Avoid setting fn and inverse if neither are set. This allows
2057     // helpers to do a check for `if (options.fn)`
2058     if (program || inverse) {
2059       if (!program) {
2060         this.context.aliases.self = "this";
2061         program = "self.noop";
2062       }
2063
2064       if (!inverse) {
2065        this.context.aliases.self = "this";
2066         inverse = "self.noop";
2067       }
2068
2069       options.push("inverse:" + inverse);
2070       options.push("fn:" + program);
2071     }
2072
2073     for(var i=0; i<paramSize; i++) {
2074       param = this.popStack();
2075       params.push(param);
2076
2077       if(this.options.stringParams) {
2078         types.push(this.popStack());
2079         contexts.push(this.popStack());
2080       }
2081     }
2082
2083     if (this.options.stringParams) {
2084       options.push("contexts:[" + contexts.join(",") + "]");
2085       options.push("types:[" + types.join(",") + "]");
2086       options.push("hashContexts:hashContexts");
2087       options.push("hashTypes:hashTypes");
2088     }
2089
2090     if(this.options.data) {
2091       options.push("data:data");
2092     }
2093
2094     options = "{" + options.join(",") + "}";
2095     if (useRegister) {
2096       this.register('options', options);
2097       params.push('options');
2098     } else {
2099       params.push(options);
2100     }
2101     return params.join(", ");
2102   }
2103 };
2104
2105 var reservedWords = (
2106   "break else new var" +
2107   " case finally return void" +
2108   " catch for switch while" +
2109   " continue function this with" +
2110   " default if throw" +
2111   " delete in try" +
2112   " do instanceof typeof" +
2113   " abstract enum int short" +
2114   " boolean export interface static" +
2115   " byte extends long super" +
2116   " char final native synchronized" +
2117   " class float package throws" +
2118   " const goto private transient" +
2119   " debugger implements protected volatile" +
2120   " double import public let yield"
2121 ).split(" ");
2122
2123 var compilerWords = JavaScriptCompiler.RESERVED_WORDS = {};
2124
2125 for(var i=0, l=reservedWords.length; i<l; i++) {
2126   compilerWords[reservedWords[i]] = true;
2127 }
2128
2129 JavaScriptCompiler.isValidJavaScriptVariableName = function(name) {
2130   if(!JavaScriptCompiler.RESERVED_WORDS[name] && /^[a-zA-Z_$][0-9a-zA-Z_$]+$/.test(name)) {
2131     return true;
2132   }
2133   return false;
2134 };
2135
2136 Handlebars.precompile = function(input, options) {
2137   if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2138     throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.precompile. You passed " + input);
2139   }
2140
2141   options = options || {};
2142   if (!('data' in options)) {
2143     options.data = true;
2144   }
2145   var ast = Handlebars.parse(input);
2146   var environment = new Compiler().compile(ast, options);
2147   return new JavaScriptCompiler().compile(environment, options);
2148 };
2149
2150 Handlebars.compile = function(input, options) {
2151   if (input == null || (typeof input !== 'string' && input.constructor !== Handlebars.AST.ProgramNode)) {
2152     throw new Handlebars.Exception("You must pass a string or Handlebars AST to Handlebars.compile. You passed " + input);
2153   }
2154
2155   options = options || {};
2156   if (!('data' in options)) {
2157     options.data = true;
2158   }
2159   var compiled;
2160   function compile() {
2161     var ast = Handlebars.parse(input);
2162     var environment = new Compiler().compile(ast, options);
2163     var templateSpec = new JavaScriptCompiler().compile(environment, options, undefined, true);
2164     return Handlebars.template(templateSpec);
2165   }
2166
2167   // Template is only compiled on first use and cached after that point.
2168   return function(context, options) {
2169     if (!compiled) {
2170       compiled = compile();
2171     }
2172     return compiled.call(this, context, options);
2173   };
2174 };
2175
2176 ;
2177 // lib/handlebars/runtime.js
2178
2179 Handlebars.VM = {
2180   template: function(templateSpec) {
2181     // Just add water
2182     var container = {
2183       escapeExpression: Handlebars.Utils.escapeExpression,
2184       invokePartial: Handlebars.VM.invokePartial,
2185       programs: [],
2186       program: function(i, fn, data) {
2187         var programWrapper = this.programs[i];
2188         if(data) {
2189           programWrapper = Handlebars.VM.program(i, fn, data);
2190         } else if (!programWrapper) {
2191           programWrapper = this.programs[i] = Handlebars.VM.program(i, fn);
2192         }
2193         return programWrapper;
2194       },
2195       merge: function(param, common) {
2196         var ret = param || common;
2197
2198         if (param && common) {
2199           ret = {};
2200           Handlebars.Utils.extend(ret, common);
2201           Handlebars.Utils.extend(ret, param);
2202         }
2203         return ret;
2204       },
2205       programWithDepth: Handlebars.VM.programWithDepth,
2206       noop: Handlebars.VM.noop,
2207       compilerInfo: null
2208     };
2209
2210     return function(context, options) {
2211       options = options || {};
2212       var result = templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
2213
2214       var compilerInfo = container.compilerInfo || [],
2215           compilerRevision = compilerInfo[0] || 1,
2216           currentRevision = Handlebars.COMPILER_REVISION;
2217
2218       if (compilerRevision !== currentRevision) {
2219         if (compilerRevision < currentRevision) {
2220           var runtimeVersions = Handlebars.REVISION_CHANGES[currentRevision],
2221               compilerVersions = Handlebars.REVISION_CHANGES[compilerRevision];
2222           throw "Template was precompiled with an older version of Handlebars than the current runtime. "+
2223                 "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").";
2224         } else {
2225           // Use the embedded version info since the runtime doesn't know about this revision yet
2226           throw "Template was precompiled with a newer version of Handlebars than the current runtime. "+
2227                 "Please update your runtime to a newer version ("+compilerInfo[1]+").";
2228         }
2229       }
2230
2231       return result;
2232     };
2233   },
2234
2235   programWithDepth: function(i, fn, data /*, $depth */) {
2236     var args = Array.prototype.slice.call(arguments, 3);
2237
2238     var program = function(context, options) {
2239       options = options || {};
2240
2241       return fn.apply(this, [context, options.data || data].concat(args));
2242     };
2243     program.program = i;
2244     program.depth = args.length;
2245     return program;
2246   },
2247   program: function(i, fn, data) {
2248     var program = function(context, options) {
2249       options = options || {};
2250
2251       return fn(context, options.data || data);
2252     };
2253     program.program = i;
2254     program.depth = 0;
2255     return program;
2256   },
2257   noop: function() { return ""; },
2258   invokePartial: function(partial, name, context, helpers, partials, data) {
2259     var options = { helpers: helpers, partials: partials, data: data };
2260
2261     if(partial === undefined) {
2262       throw new Handlebars.Exception("The partial " + name + " could not be found");
2263     } else if(partial instanceof Function) {
2264       return partial(context, options);
2265     } else if (!Handlebars.compile) {
2266       throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
2267     } else {
2268       partials[name] = Handlebars.compile(partial, {data: data !== undefined});
2269       return partials[name](context, options);
2270     }
2271   }
2272 };
2273
2274 Handlebars.template = Handlebars.VM.template;
2275 ;
2276 // lib/handlebars/browser-suffix.js
2277 })(Handlebars);
2278 ;