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