81c90a70 by Lee Whitaker

Use handelbars to make templates for the manifest files. Add tests for media_se…

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