{"version":3,"sources":["spacebars-compiler/templatetag.js","spacebars-compiler/optimizer.js","spacebars-compiler/codegen.js","spacebars-compiler/compiler.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,uB;;AAEA,iE;AACA,E;AACA,0C;AACA,E;AACA,2B;AACA,6B;AACA,8B;AACA,sC;AACA,gC;AACA,+B;AACA,gC;AACA,0B;AACA,kD;AACA,E;AACA,iE;AACA,E;AACA,yE;AACA,2E;AACA,oB;AACA,E;AACA,wE;AACA,sE;AACA,2E;AACA,uE;AACA,sC;AACA,E;AACA,qE;AACA,kB;AACA,E;AACA,qD;AACA,E;AACA,6E;AACA,yE;AACA,qD;AACA,mC;AACA,E;AACA,sE;AACA,sE;AACA,6B;;AAEA,4D;;AAEA,2D;AACA,+C;AACA,E;AACA,kD;AACA,wE;;AAEA,4C;AACA,oD;AACA,6C;AACA,E;;AAEA,yD;AACA,6D;AACA,mD;AACA,c;AACA,2B;AACA,0D;AACA,oD;AACA,sD;AACA,uD;AACA,gD;AACA,2D;AACA,2D;AACA,4D;AACA,E;;AAEA,Y;AACA,qB;AACA,sB;AACA,E;;AAEA,iE;AACA,qE;AACA,yE;AACA,6C;AACA,gD;AACA,gC;AACA,kC;AACA,qD;;AAEA,kC;AACA,gD;AACA,gB;;AAEA,8B;AACA,yC;AACA,4C;AACA,iB;AACA,kB;AACA,wB;AACA,8B;AACA,e;AACA,I;;AAEA,mC;AACA,0B;AACA,I;;AAEA,iD;AACA,qD;AACA,a;AACA,6B;AACA,wB;AACA,2D;AACA,yF;;AAEA,c;AACA,I;;AAEA,8B;AACA,sB;;AAEA,oE;AACA,a;AACA,mC;AACA,4D;AACA,2C;;AAEA,wB;AACA,iC;;AAEA,0D;AACA,0B;AACA,sD;AACA,iD;AACA,gB;AACA,iC;AACA,sC;AACA,S;;AAEA,+B;AACA,6B;AACA,S;;AAEA,iC;;AAEA,yB;AACA,wB;AACA,K;;AAEA,kB;AACA,4B;;AAEA,uB;AACA,qC;AACA,kB;AACA,6C;AACA,+B;AACA,uC;AACA,sD;AACA,2B;AACA,c;AACA,mD;AACA,4B;AACA,kC;AACA,6B;AACA,+B;AACA,kB;AACA,oI;AACA,W;AACA,gB;AACA,4B;AACA,S;AACA,O;;AAEA,+B;AACA,gB;AACA,c;AACA,K;;AAEA,oB;AACA,I;;AAEA,mD;AACA,sC;AACA,kD;AACA,iD;AACA,oC;AACA,0E;AACA,gB;AACA,qC;AACA,sB;AACA,Y;AACA,kB;AACA,K;AACA,I;;AAEA,0C;AACA,8C;AACA,sD;AACA,kB;AACA,6B;AACA,kE;AACA,+B;AACA,mD;AACA,I;;AAEA,kE;AACA,4D;AACA,kC;AACA,+B;AACA,e;AACA,qD;AACA,sC;AACA,mE;AACA,sC;AACA,gD;AACA,kC;AACA,oE;AACA,sB;AACA,0B;AACA,8B;AACA,mD;AACA,0C;AACA,c;AACA,iD;AACA,oC;AACA,O;AACA,Y;AACA,+D;AACA,K;AACA,I;;AAEA,W;;AAEA,8B;AACA,uB;AACA,I;;AAEA,kC;AACA,8B;AACA,I;;AAEA,uD;AACA,mC;AACA,0C;AACA,2C;AACA,+C;AACA,+C;AACA,2D;AACA,iD;AACA,qD;AACA,qD;AACA,uD;AACA,M;AACA,gC;;AAEA,4B;AACA,kB;;AAEA,gC;AACA,4C;AACA,iB;AACA,sC;AACA,0D;AACA,kC;AACA,sC;AACA,iB;AACA,gC;AACA,oC;AACA,qC;AACA,0B;AACA,2B;AACA,uB;AACA,+B;AACA,2B;AACA,uB;AACA,iC;AACA,+B;AACA,2C;AACA,U;AACA,2C;AACA,0B;AACA,kB;AACA,2B;AACA,kB;AACA,kB;AACA,8B;AACA,6B;AACA,gB;AACA,wC;AACA,4B;AACA,c;AACA,6B;AACA,gB;AACA,wC;AACA,2B;AACA,O;AACA,6B;AACA,gC;AACA,0B;AACA,c;AACA,uB;AACA,8E;AACA,O;AACA,4B;;AAEA,mC;AACA,0B;AACA,K;AACA,G;;AAEA,a;AACA,E;;AAEA,iF;AACA,4B;AACA,E;AACA,wE;AACA,wB;AACA,uC;AACA,6B;AACA,0C;AACA,yB;AACA,gB;AACA,E;;AAEA,0E;AACA,0E;AACA,+B;AACA,E;AACA,e;AACA,E;AACA,oE;AACA,E;AACA,sE;AACA,8D;AACA,E;AACA,2E;AACA,wC;AACA,E;AACA,yE;AACA,qE;AACA,gC;AACA,kC;AACA,qD;;AAEA,mD;AACA,kD;AACA,e;AACA,kB;;AAEA,qC;AACA,gB;;AAEA,gC;AACA,gB;;AAEA,6B;AACA,yC;;AAEA,mC;AACA,qD;;AAEA,yD;AACA,iD;AACA,+B;;AAEA,oC;AACA,2B;;AAEA,oE;AACA,uE;AACA,oE;AACA,gB;AACA,0C;;AAEA,wB;AACA,qC;AACA,0D;AACA,wC;AACA,gE;AACA,mE;AACA,wC;AACA,O;AACA,2B;AACA,qD;AACA,yC;AACA,0B;AACA,Q;AACA,qE;;AAEA,4C;AACA,yE;;AAEA,yD;AACA,qE;;AAEA,kC;AACA,mD;AACA,2E;;AAEA,8C;AACA,+D;;AAEA,4B;AACA,2C;AACA,K;;AAEA,wC;AACA,8C;AACA,qC;AACA,8B;AACA,yE;AACA,kC;AACA,O;AACA,Y;AACA,4B;AACA,uE;AACA,kC;AACA,K;AACA,G;;AAEA,6B;AACA,yB;AACA,+B;AACA,yB;;AAEA,gB;AACA,E;;AAEA,+C;AACA,qC;AACA,I;AACA,yE;AACA,kE;AACA,yE;AACA,2C;AACA,iB;AACA,mC;AACA,yD;AACA,6C;AACA,oD;AACA,sD;AACA,E;;AAEA,oE;AACA,mE;AACA,W;AACA,4C;;AAEA,+D;AACA,yB;AACA,2E;AACA,qE;AACA,wB;AACA,yH;AACA,K;AACA,G;;AAEA,gE;AACA,wD;AACA,2D;AACA,a;AACA,2C;AACA,2B;AACA,0B;AACA,oD;AACA,wD;AACA,sD;AACA,wD;AACA,0H;AACA,O;AACA,Y;AACA,qF;AACA,K;AACA,+D;AACA,qC;AACA,8N;AACA,K;AACA,iC;AACA,4L;AACA,K;AACA,G;;AAEA,E;;;;;;;;;;;;;;;;;;;AC/dA,yE;AACA,yB;;AAEA,iC;AACA,uC;AACA,E;;AAEA,mB;AACA,U;AACA,W;AACA,S;AACA,E;;AAEA,0E;AACA,yE;AACA,qE;AACA,0E;AACA,8E;AACA,E;AACA,yE;AACA,2E;AACA,sE;AACA,4E;AACA,qB;AACA,+C;AACA,wB;AACA,wC;AACA,6C;AACA,2C;AACA,2C;AACA,uC;AACA,0C;AACA,4C;AACA,4B;AACA,sC;AACA,gD;AACA,iC;AACA,4B;AACA,I;AACA,4B;AACA,8B;AACA,iC;AACA,yE;AACA,qB;AACA,8B;AACA,iD;AACA,uD;AACA,sE;AACA,8B;AACA,qC;AACA,2E;AACA,8E;AACA,wE;AACA,0B;AACA,8B;AACA,K;;AAEA,gC;AACA,6C;AACA,uD;AACA,iC;;AAEA,6D;AACA,+B;;AAEA,4B;AACA,I;AACA,qC;AACA,gB;AACA,wC;AACA,8D;AACA,6C;AACA,4E;AACA,mC;AACA,wB;AACA,oD;AACA,qC;AACA,O;AACA,K;AACA,4B;AACA,G;AACA,G;;AAEA,4C;AACA,iD;AACA,E;;AAEA,0B;AACA,kC;AACA,E;;AAEA,wD;AACA,qB;AACA,8C;AACA,4C;AACA,+C;AACA,mB;;AAEA,oE;AACA,uB;AACA,G;AACA,G;;AAEA,kE;AACA,+D;AACA,iD;AACA,uB;AACA,mB;AACA,wB;AACA,sB;AACA,sB;AACA,gC;AACA,kD;AACA,8C;AACA,0B;AACA,sD;AACA,oE;AACA,Y;AACA,mB;AACA,K;AACA,I;AACA,4B;AACA,gD;AACA,8C;AACA,wB;AACA,sD;AACA,gE;AACA,Y;AACA,iB;AACA,K;AACA,I;AACA,sC;AACA,2D;AACA,qE;AACA,I;AACA,qC;AACA,iB;AACA,G;AACA,G;;AAEA,qD;AACA,oD;AACA,0B;AACA,gC;AACA,oB;AACA,4C;AACA,0B;AACA,uC;AACA,4B;AACA,4B;AACA,gE;AACA,+D;AACA,mE;AACA,2D;AACA,yB;AACA,+C;AACA,0D;AACA,S;AACA,c;AACA,0B;AACA,O;AACA,K;AACA,kB;AACA,G;AACA,G;;AAEA,wE;AACA,kC;AACA,mD;AACA,yB;AACA,4B;AACA,yB;AACA,yD;AACA,kB;AACA,Y;AACA,iB;AACA,K;AACA,G;AACA,G;;AAEA,8C;AACA,6C;AACA,gD;AACA,+C;AACA,c;AACA,E;;;;;;;;;;;;;;;;;;;ACzLA,+D;AACA,mC;;AAEA,qE;AACA,kE;AACA,yC;AACA,yD;;AAEA,oE;AACA,mB;AACA,2B;AACA,2B;AACA,sB;AACA,E;;;AAGA,kE;AACA,oE;AACA,W;AACA,6B;AACA,+D;AACA,kE;AACA,qC;AACA,8C;AACA,wC;;AAEA,8D;AACA,kE;AACA,6C;AACA,kC;;AAEA,sE;AACA,E;;AAEA,8D;AACA,iD;AACA,E;AACA,qE;AACA,kE;AACA,mB;AACA,oD;AACA,oD;AACA,+C;AACA,E;;AAEA,wC;AACA,iB;AACA,oB;AACA,iE;AACA,sC;AACA,E;;AAEA,6B;AACA,sC;AACA,oB;AACA,wE;AACA,yD;AACA,qE;AACA,0D;AACA,kE;AACA,mB;AACA,Y;AACA,2D;AACA,4D;AACA,oC;AACA,mD;AACA,S;AACA,4E;AACA,mE;AACA,oD;AACA,qD;AACA,qE;AACA,oD;AACA,S;AACA,yC;AACA,wE;AACA,4B;;AAEA,uC;AACA,0D;AACA,oC;AACA,Y;AACA,wD;AACA,8E;;AAEA,qF;AACA,uC;AACA,8B;AACA,gF;AACA,gC;AACA,qE;;AAEA,oD;AACA,2E;AACA,iC;AACA,kD;AACA,qE;AACA,wC;AACA,0D;AACA,6E;;AAEA,kD;AACA,+B;AACA,4C;;AAEA,qC;AACA,4E;;AAEA,gB;AACA,wE;AACA,gC;AACA,iC;AACA,0E;AACA,qB;AACA,W;;AAEA,iE;AACA,6C;AACA,gE;AACA,qD;AACA,wE;;AAEA,uC;AACA,wB;AACA,sC;AACA,4B;AACA,4C;AACA,W;;AAEA,2B;AACA,oE;;AAEA,yE;AACA,sE;AACA,mE;AACA,oE;AACA,0E;AACA,0E;AACA,oE;AACA,yB;AACA,yB;AACA,6E;AACA,mC;AACA,W;;AAEA,sE;AACA,6D;AACA,wE;AACA,uE;AACA,mF;AACA,qC;AACA,W;;AAEA,kD;AACA,S;AACA,yC;AACA,yB;AACA,c;AACA,kE;AACA,qE;AACA,qE;AACA,O;AACA,K;AACA,I;;AAEA,+C;AACA,I;AACA,6D;AACA,sD;AACA,I;AACA,gE;AACA,I;AACA,a;AACA,I;AACA,qE;AACA,mE;AACA,oE;AACA,iC;AACA,sC;AACA,oD;AACA,uE;AACA,0E;AACA,4E;AACA,qC;AACA,gE;AACA,2B;AACA,oD;AACA,2D;AACA,0B;AACA,kE;AACA,iD;AACA,4C;AACA,K;;AAEA,wD;AACA,gC;AACA,yD;AACA,sC;AACA,kE;;AAEA,0B;AACA,6C;AACA,sE;AACA,K;;AAEA,gB;AACA,I;;AAEA,+D;AACA,mE;AACA,I;AACA,iE;AACA,4D;AACA,mC;AACA,oB;;AAEA,yB;AACA,0B;;AAEA,gB;AACA,sB;AACA,kB;AACA,kB;AACA,mB;AACA,gB;AACA,iD;AACA,Y;AACA,gB;AACA,2C;AACA,Y;AACA,Y;AACA,uB;AACA,yD;AACA,K;;AAEA,mB;AACA,I;;AAEA,wE;AACA,uE;AACA,qC;AACA,wD;AACA,oB;;AAEA,0C;AACA,iD;AACA,gD;;AAEA,qD;AACA,uD;AACA,I;;AAEA,oD;AACA,iB;AACA,2C;AACA,oB;;AAEA,0C;AACA,gC;;AAEA,0B;AACA,oC;AACA,8C;;AAEA,2B;AACA,gE;AACA,gC;AACA,iC;AACA,c;AACA,8B;AACA,4B;AACA,2B;AACA,O;AACA,O;;AAEA,sD;AACA,iB;AACA,0B;AACA,mE;AACA,K;;AAEA,gB;AACA,I;;AAEA,oC;AACA,8C;AACA,I;;AAEA,6C;AACA,oB;;AAEA,4B;;AAEA,wB;AACA,wB;AACA,kB;AACA,sC;AACA,2D;AACA,yB;AACA,mC;AACA,4B;AACA,gF;AACA,S;AACA,kD;AACA,uC;AACA,wD;AACA,Q;AACA,uE;AACA,2C;AACA,mD;AACA,mC;AACA,qC;AACA,4E;AACA,Y;AACA,8D;AACA,wB;AACA,oE;AACA,0D;AACA,K;;AAEA,0D;AACA,G;;AAEA,G;;;;;;;;;;;;;;;;;;;;AClUA,4C;;AAEA,qC;AACA,U;AACA,sD;;AAEA,c;AACA,E;;AAEA,uD;AACA,4C;AACA,kD;AACA,E;;AAEA,2E;AACA,4C;AACA,6B;AACA,6C;;AAEA,gE;AACA,0D;AACA,4D;AACA,kE;AACA,6D;AACA,yB;AACA,gC;AACA,kE;;AAEA,gD;AACA,K;;AAEA,wE;AACA,I;AACA,qC;AACA,+C;AACA,oD;;AAEA,2D;AACA,gF;AACA,I;AACA,+C;AACA,iC;AACA,mC;AACA,kC;;AAEA,2B;AACA,sE;AACA,sE;AACA,wD;AACA,uE;AACA,4E;AACA,iD;AACA,oE;AACA,K;AACA,kB;AACA,G;AACA,G;;AAEA,2D;AACA,sD;AACA,wB;AACA,mD;AACA,2C;;AAEA,uB;;AAEA,4D;AACA,6B;AACA,4E;AACA,0B;AACA,4C;AACA,G;;AAEA,8C;AACA,qD;AACA,qC;;AAEA,+B;AACA,6B;AACA,gC;AACA,G;AACA,oB;AACA,gC;AACA,iB;;AAEA,2C;;AAEA,c;AACA,E;;AAEA,+C;AACA,8D;AACA,kD;AACA,W;AACA,yB;AACA,sB;AACA,wB;AACA,iC;AACA,kC;AACA,iC;AACA,6B;AACA,+E;AACA,gC;AACA,sC;AACA,kB;AACA,U;AACA,2C;AACA,gB;AACA,G;AACA,E","file":"/packages/spacebars-compiler.js","sourcesContent":["SpacebarsCompiler = {};\n\n// A TemplateTag is the result of parsing a single `{{...}}` tag.\n//\n// The `.type` of a TemplateTag is one of:\n//\n// - `\"DOUBLE\"` - `{{foo}}`\n// - `\"TRIPLE\"` - `{{{foo}}}`\n// - `\"COMMENT\"` - `{{! foo}}`\n// - `\"BLOCKCOMMENT\" - `{{!-- foo--}}`\n// - `\"INCLUSION\"` - `{{> foo}}`\n// - `\"BLOCKOPEN\"` - `{{#foo}}`\n// - `\"BLOCKCLOSE\"` - `{{/foo}}`\n// - `\"ELSE\"` - `{{else}}`\n// - `\"ESCAPE\"` - `{{|`, `{{{|`, `{{{{|` and so on\n//\n// Besides `type`, the mandatory properties of a TemplateTag are:\n//\n// - `path` - An array of one or more strings.  The path of `{{foo.bar}}`\n//   is `[\"foo\", \"bar\"]`.  Applies to DOUBLE, TRIPLE, INCLUSION, BLOCKOPEN,\n//   and BLOCKCLOSE.\n//\n// - `args` - An array of zero or more argument specs.  An argument spec\n//   is a two or three element array, consisting of a type, value, and\n//   optional keyword name.  For example, the `args` of `{{foo \"bar\" x=3}}`\n//   are `[[\"STRING\", \"bar\"], [\"NUMBER\", 3, \"x\"]]`.  Applies to DOUBLE,\n//   TRIPLE, INCLUSION, and BLOCKOPEN.\n//\n// - `value` - A string of the comment's text. Applies to COMMENT and\n//   BLOCKCOMMENT.\n//\n// These additional are typically set during parsing:\n//\n// - `position` - The HTMLTools.TEMPLATE_TAG_POSITION specifying at what sort\n//   of site the TemplateTag was encountered (e.g. at element level or as\n//   part of an attribute value). Its absence implies\n//   TEMPLATE_TAG_POSITION.ELEMENT.\n//\n// - `content` and `elseContent` - When a BLOCKOPEN tag's contents are\n//   parsed, they are put here.  `elseContent` will only be present if\n//   an `{{else}}` was found.\n\nvar TEMPLATE_TAG_POSITION = HTMLTools.TEMPLATE_TAG_POSITION;\n\nTemplateTag = SpacebarsCompiler.TemplateTag = function () {\n  HTMLTools.TemplateTag.apply(this, arguments);\n};\nTemplateTag.prototype = new HTMLTools.TemplateTag;\nTemplateTag.prototype.constructorName = 'SpacebarsCompiler.TemplateTag';\n\nvar makeStacheTagStartRegex = function (r) {\n  return new RegExp(r.source + /(?![{>!#/])/.source,\n                    r.ignoreCase ? 'i' : '');\n};\n\n// \"starts\" regexes are used to see what type of template\n// tag the parser is looking at.  They must match a non-empty\n// result, but not the interesting part of the tag.\nvar starts = {\n  ESCAPE: /^\\{\\{(?=\\{*\\|)/,\n  ELSE: makeStacheTagStartRegex(/^\\{\\{\\s*else(?=[\\s}])/i),\n  DOUBLE: makeStacheTagStartRegex(/^\\{\\{\\s*(?!\\s)/),\n  TRIPLE: makeStacheTagStartRegex(/^\\{\\{\\{\\s*(?!\\s)/),\n  BLOCKCOMMENT: makeStacheTagStartRegex(/^\\{\\{\\s*!--/),\n  COMMENT: makeStacheTagStartRegex(/^\\{\\{\\s*!/),\n  INCLUSION: makeStacheTagStartRegex(/^\\{\\{\\s*>\\s*(?!\\s)/),\n  BLOCKOPEN: makeStacheTagStartRegex(/^\\{\\{\\s*#\\s*(?!\\s)/),\n  BLOCKCLOSE: makeStacheTagStartRegex(/^\\{\\{\\s*\\/\\s*(?!\\s)/)\n};\n\nvar ends = {\n  DOUBLE: /^\\s*\\}\\}/,\n  TRIPLE: /^\\s*\\}\\}\\}/\n};\n\n// Parse a tag from the provided scanner or string.  If the input\n// doesn't start with `{{`, returns null.  Otherwise, either succeeds\n// and returns a SpacebarsCompiler.TemplateTag, or throws an error (using\n// `scanner.fatal` if a scanner is provided).\nTemplateTag.parse = function (scannerOrString) {\n  var scanner = scannerOrString;\n  if (typeof scanner === 'string')\n    scanner = new HTMLTools.Scanner(scannerOrString);\n\n  if (! (scanner.peek() === '{' &&\n         (scanner.rest()).slice(0, 2) === '{{'))\n    return null;\n\n  var run = function (regex) {\n    // regex is assumed to start with `^`\n    var result = regex.exec(scanner.rest());\n    if (! result)\n      return null;\n    var ret = result[0];\n    scanner.pos += ret.length;\n    return ret;\n  };\n\n  var advance = function (amount) {\n    scanner.pos += amount;\n  };\n\n  var scanIdentifier = function (isFirstInPath) {\n    var id = BlazeTools.parseIdentifierName(scanner);\n    if (! id)\n      expected('IDENTIFIER');\n    if (isFirstInPath &&\n        (id === 'null' || id === 'true' || id === 'false'))\n      scanner.fatal(\"Can't use null, true, or false, as an identifier at start of path\");\n\n    return id;\n  };\n\n  var scanPath = function () {\n    var segments = [];\n\n    // handle initial `.`, `..`, `./`, `../`, `../..`, `../../`, etc\n    var dots;\n    if ((dots = run(/^[\\.\\/]+/))) {\n      var ancestorStr = '.'; // eg `../../..` maps to `....`\n      var endsWithSlash = /\\/$/.test(dots);\n\n      if (endsWithSlash)\n        dots = dots.slice(0, -1);\n\n      _.each(dots.split('/'), function(dotClause, index) {\n        if (index === 0) {\n          if (dotClause !== '.' && dotClause !== '..')\n            expected(\"`.`, `..`, `./` or `../`\");\n        } else {\n          if (dotClause !== '..')\n            expected(\"`..` or `../`\");\n        }\n\n        if (dotClause === '..')\n          ancestorStr += '.';\n      });\n\n      segments.push(ancestorStr);\n\n      if (!endsWithSlash)\n        return segments;\n    }\n\n    while (true) {\n      // scan a path segment\n\n      if (run(/^\\[/)) {\n        var seg = run(/^[\\s\\S]*?\\]/);\n        if (! seg)\n          error(\"Unterminated path segment\");\n        seg = seg.slice(0, -1);\n        if (! seg && ! segments.length)\n          error(\"Path can't start with empty string\");\n        segments.push(seg);\n      } else {\n        var id = scanIdentifier(! segments.length);\n        if (id === 'this') {\n          if (! segments.length) {\n            // initial `this`\n            segments.push('.');\n          } else {\n            error(\"Can only use `this` at the beginning of a path.\\nInstead of `foo.this` or `../this`, just write `foo` or `..`.\");\n          }\n        } else {\n          segments.push(id);\n        }\n      }\n\n      var sep = run(/^[\\.\\/]/);\n      if (! sep)\n        break;\n    }\n\n    return segments;\n  };\n\n  // scan the keyword portion of a keyword argument\n  // (the \"foo\" portion in \"foo=bar\").\n  // Result is either the keyword matched, or null\n  // if we're not at a keyword argument position.\n  var scanArgKeyword = function () {\n    var match = /^([^\\{\\}\\(\\)\\>#=\\s\"'\\[\\]]+)\\s*=\\s*/.exec(scanner.rest());\n    if (match) {\n      scanner.pos += match[0].length;\n      return match[1];\n    } else {\n      return null;\n    }\n  };\n\n  // scan an argument; succeeds or errors.\n  // Result is an array of two or three items:\n  // type , value, and (indicating a keyword argument)\n  // keyword name.\n  var scanArg = function () {\n    var keyword = scanArgKeyword(); // null if not parsing a kwarg\n    var value = scanArgValue();\n    return keyword ? value.concat(keyword) : value;\n  };\n\n  // scan an argument value (for keyword or positional arguments);\n  // succeeds or errors.  Result is an array of type, value.\n  var scanArgValue = function () {\n    var startPos = scanner.pos;\n    var result;\n    if ((result = BlazeTools.parseNumber(scanner))) {\n      return ['NUMBER', result.value];\n    } else if ((result = BlazeTools.parseStringLiteral(scanner))) {\n      return ['STRING', result.value];\n    } else if (/^[\\.\\[]/.test(scanner.peek())) {\n      return ['PATH', scanPath()];\n    } else if ((result = BlazeTools.parseIdentifierName(scanner))) {\n      var id = result;\n      if (id === 'null') {\n        return ['NULL', null];\n      } else if (id === 'true' || id === 'false') {\n        return ['BOOLEAN', id === 'true'];\n      } else {\n        scanner.pos = startPos; // unconsume `id`\n        return ['PATH', scanPath()];\n      }\n    } else {\n      expected('identifier, number, string, boolean, or null');\n    }\n  };\n\n  var type;\n\n  var error = function (msg) {\n    scanner.fatal(msg);\n  };\n\n  var expected = function (what) {\n    error('Expected ' + what);\n  };\n\n  // must do ESCAPE first, immediately followed by ELSE\n  // order of others doesn't matter\n  if (run(starts.ESCAPE)) type = 'ESCAPE';\n  else if (run(starts.ELSE)) type = 'ELSE';\n  else if (run(starts.DOUBLE)) type = 'DOUBLE';\n  else if (run(starts.TRIPLE)) type = 'TRIPLE';\n  else if (run(starts.BLOCKCOMMENT)) type = 'BLOCKCOMMENT';\n  else if (run(starts.COMMENT)) type = 'COMMENT';\n  else if (run(starts.INCLUSION)) type = 'INCLUSION';\n  else if (run(starts.BLOCKOPEN)) type = 'BLOCKOPEN';\n  else if (run(starts.BLOCKCLOSE)) type = 'BLOCKCLOSE';\n  else\n    error('Unknown stache tag');\n\n  var tag = new TemplateTag;\n  tag.type = type;\n\n  if (type === 'BLOCKCOMMENT') {\n    var result = run(/^[\\s\\S]*?--\\s*?\\}\\}/);\n    if (! result)\n      error(\"Unclosed block comment\");\n    tag.value = result.slice(0, result.lastIndexOf('--'));\n  } else if (type === 'COMMENT') {\n    var result = run(/^[\\s\\S]*?\\}\\}/);\n    if (! result)\n      error(\"Unclosed comment\");\n    tag.value = result.slice(0, -2);\n  } else if (type === 'BLOCKCLOSE') {\n    tag.path = scanPath();\n    if (! run(ends.DOUBLE))\n      expected('`}}`');\n  } else if (type === 'ELSE') {\n    if (! run(ends.DOUBLE))\n      expected('`}}`');\n  } else if (type === 'ESCAPE') {\n    var result = run(/^\\{*\\|/);\n    tag.value = '{{' + result.slice(0, -1);\n  } else {\n    // DOUBLE, TRIPLE, BLOCKOPEN, INCLUSION\n    tag.path = scanPath();\n    tag.args = [];\n    var foundKwArg = false;\n    while (true) {\n      run(/^\\s*/);\n      if (type === 'TRIPLE') {\n        if (run(ends.TRIPLE))\n          break;\n        else if (scanner.peek() === '}')\n          expected('`}}}`');\n      } else {\n        if (run(ends.DOUBLE))\n          break;\n        else if (scanner.peek() === '}')\n          expected('`}}`');\n      }\n      var newArg = scanArg();\n      if (newArg.length === 3) {\n        foundKwArg = true;\n      } else {\n        if (foundKwArg)\n          error(\"Can't have a non-keyword argument after a keyword argument\");\n      }\n      tag.args.push(newArg);\n\n      if (run(/^(?=[\\s}])/) !== '')\n        expected('space');\n    }\n  }\n\n  return tag;\n};\n\n// Returns a SpacebarsCompiler.TemplateTag parsed from `scanner`, leaving scanner\n// at its original position.\n//\n// An error will still be thrown if there is not a valid template tag at\n// the current position.\nTemplateTag.peek = function (scanner) {\n  var startPos = scanner.pos;\n  var result = TemplateTag.parse(scanner);\n  scanner.pos = startPos;\n  return result;\n};\n\n// Like `TemplateTag.parse`, but in the case of blocks, parse the complete\n// `{{#foo}}...{{/foo}}` with `content` and possible `elseContent`, rather\n// than just the BLOCKOPEN tag.\n//\n// In addition:\n//\n// - Throws an error if `{{else}}` or `{{/foo}}` tag is encountered.\n//\n// - Returns `null` for a COMMENT.  (This case is distinguishable from\n//   parsing no tag by the fact that the scanner is advanced.)\n//\n// - Takes an HTMLTools.TEMPLATE_TAG_POSITION `position` and sets it as the\n//   TemplateTag's `.position` property.\n//\n// - Validates the tag's well-formedness and legality at in its position.\nTemplateTag.parseCompleteTag = function (scannerOrString, position) {\n  var scanner = scannerOrString;\n  if (typeof scanner === 'string')\n    scanner = new HTMLTools.Scanner(scannerOrString);\n\n  var startPos = scanner.pos; // for error messages\n  var result = TemplateTag.parse(scannerOrString);\n  if (! result)\n    return result;\n\n  if (result.type === 'BLOCKCOMMENT')\n    return null;\n\n  if (result.type === 'COMMENT')\n    return null;\n\n  if (result.type === 'ELSE')\n    scanner.fatal(\"Unexpected {{else}}\");\n\n  if (result.type === 'BLOCKCLOSE')\n    scanner.fatal(\"Unexpected closing template tag\");\n\n  position = (position || TEMPLATE_TAG_POSITION.ELEMENT);\n  if (position !== TEMPLATE_TAG_POSITION.ELEMENT)\n    result.position = position;\n\n  if (result.type === 'BLOCKOPEN') {\n    // parse block contents\n\n    // Construct a string version of `.path` for comparing start and\n    // end tags.  For example, `foo/[0]` was parsed into `[\"foo\", \"0\"]`\n    // and now becomes `foo,0`.  This form may also show up in error\n    // messages.\n    var blockName = result.path.join(',');\n\n    var textMode = null;\n      if (blockName === 'markdown' ||\n          position === TEMPLATE_TAG_POSITION.IN_RAWTEXT) {\n        textMode = HTML.TEXTMODE.STRING;\n      } else if (position === TEMPLATE_TAG_POSITION.IN_RCDATA ||\n                 position === TEMPLATE_TAG_POSITION.IN_ATTRIBUTE) {\n        textMode = HTML.TEXTMODE.RCDATA;\n      }\n      var parserOptions = {\n        getTemplateTag: TemplateTag.parseCompleteTag,\n        shouldStop: isAtBlockCloseOrElse,\n        textMode: textMode\n      };\n    result.content = HTMLTools.parseFragment(scanner, parserOptions);\n\n    if (scanner.rest().slice(0, 2) !== '{{')\n      scanner.fatal(\"Expected {{else}} or block close for \" + blockName);\n\n    var lastPos = scanner.pos; // save for error messages\n    var tmplTag = TemplateTag.parse(scanner); // {{else}} or {{/foo}}\n\n    if (tmplTag.type === 'ELSE') {\n      // parse {{else}} and content up to close tag\n      result.elseContent = HTMLTools.parseFragment(scanner, parserOptions);\n\n      if (scanner.rest().slice(0, 2) !== '{{')\n        scanner.fatal(\"Expected block close for \" + blockName);\n\n      lastPos = scanner.pos;\n      tmplTag = TemplateTag.parse(scanner);\n    }\n\n    if (tmplTag.type === 'BLOCKCLOSE') {\n      var blockName2 = tmplTag.path.join(',');\n      if (blockName !== blockName2) {\n        scanner.pos = lastPos;\n        scanner.fatal('Expected tag to close ' + blockName + ', found ' +\n                      blockName2);\n      }\n    } else {\n      scanner.pos = lastPos;\n      scanner.fatal('Expected tag to close ' + blockName + ', found ' +\n                    tmplTag.type);\n    }\n  }\n\n  var finalPos = scanner.pos;\n  scanner.pos = startPos;\n  validateTag(result, scanner);\n  scanner.pos = finalPos;\n\n  return result;\n};\n\nvar isAtBlockCloseOrElse = function (scanner) {\n  // Detect `{{else}}` or `{{/foo}}`.\n  //\n  // We do as much work ourselves before deferring to `TemplateTag.peek`,\n  // for efficiency (we're called for every input token) and to be\n  // less obtrusive, because `TemplateTag.peek` will throw an error if it\n  // sees `{{` followed by a malformed tag.\n  var rest, type;\n  return (scanner.peek() === '{' &&\n          (rest = scanner.rest()).slice(0, 2) === '{{' &&\n          /^\\{\\{\\s*(\\/|else\\b)/.test(rest) &&\n          (type = TemplateTag.peek(scanner).type) &&\n          (type === 'BLOCKCLOSE' || type === 'ELSE'));\n};\n\n// Validate that `templateTag` is correctly formed and legal for its\n// HTML position.  Use `scanner` to report errors. On success, does\n// nothing.\nvar validateTag = function (ttag, scanner) {\n\n  if (ttag.type === 'INCLUSION' || ttag.type === 'BLOCKOPEN') {\n    var args = ttag.args;\n    if (args.length > 1 && args[0].length === 2 && args[0][0] !== 'PATH') {\n      // we have a positional argument that is not a PATH followed by\n      // other arguments\n      scanner.fatal(\"First argument must be a function, to be called on the rest of the arguments; found \" + args[0][0]);\n    }\n  }\n\n  var position = ttag.position || TEMPLATE_TAG_POSITION.ELEMENT;\n  if (position === TEMPLATE_TAG_POSITION.IN_ATTRIBUTE) {\n    if (ttag.type === 'DOUBLE' || ttag.type === 'ESCAPE') {\n      return;\n    } else if (ttag.type === 'BLOCKOPEN') {\n      var path = ttag.path;\n      var path0 = path[0];\n      if (! (path.length === 1 && (path0 === 'if' ||\n                                   path0 === 'unless' ||\n                                   path0 === 'with' ||\n                                   path0 === 'each'))) {\n        scanner.fatal(\"Custom block helpers are not allowed in an HTML attribute, only built-in ones like #each and #if\");\n      }\n    } else {\n      scanner.fatal(ttag.type + \" template tag is not allowed in an HTML attribute\");\n    }\n  } else if (position === TEMPLATE_TAG_POSITION.IN_START_TAG) {\n    if (! (ttag.type === 'DOUBLE')) {\n      scanner.fatal(\"Reactive HTML attributes must either have a constant name or consist of a single {{helper}} providing a dictionary of names and values.  A template tag of type \" + ttag.type + \" is not allowed here.\");\n    }\n    if (scanner.peek() === '=') {\n      scanner.fatal(\"Template tags are not allowed in attribute names, only in attribute values or in the form of a single {{helper}} that evaluates to a dictionary of name=value pairs.\");\n    }\n  }\n\n};\n","// Optimize parts of an HTMLjs tree into raw HTML strings when they don't\n// contain template tags.\n\nvar constant = function (value) {\n  return function () { return value; };\n};\n\nvar OPTIMIZABLE = {\n  NONE: 0,\n  PARTS: 1,\n  FULL: 2\n};\n\n// We can only turn content into an HTML string if it contains no template\n// tags and no \"tricky\" HTML tags.  If we can optimize the entire content\n// into a string, we return OPTIMIZABLE.FULL.  If the we are given an\n// unoptimizable node, we return OPTIMIZABLE.NONE.  If we are given a tree\n// that contains an unoptimizable node somewhere, we return OPTIMIZABLE.PARTS.\n//\n// For example, we always create SVG elements programmatically, since SVG\n// doesn't have innerHTML.  If we are given an SVG element, we return NONE.\n// However, if we are given a big tree that contains SVG somewhere, we\n// return PARTS so that the optimizer can descend into the tree and optimize\n// other parts of it.\nvar CanOptimizeVisitor = HTML.Visitor.extend();\nCanOptimizeVisitor.def({\n  visitNull: constant(OPTIMIZABLE.FULL),\n  visitPrimitive: constant(OPTIMIZABLE.FULL),\n  visitComment: constant(OPTIMIZABLE.FULL),\n  visitCharRef: constant(OPTIMIZABLE.FULL),\n  visitRaw: constant(OPTIMIZABLE.FULL),\n  visitObject: constant(OPTIMIZABLE.NONE),\n  visitFunction: constant(OPTIMIZABLE.NONE),\n  visitArray: function (x) {\n    for (var i = 0; i < x.length; i++)\n      if (this.visit(x[i]) !== OPTIMIZABLE.FULL)\n        return OPTIMIZABLE.PARTS;\n    return OPTIMIZABLE.FULL;\n  },\n  visitTag: function (tag) {\n    var tagName = tag.tagName;\n    if (tagName === 'textarea') {\n      // optimizing into a TEXTAREA's RCDATA would require being a little\n      // more clever.\n      return OPTIMIZABLE.NONE;\n    } else if (! (HTML.isKnownElement(tagName) &&\n                  ! HTML.isKnownSVGElement(tagName))) {\n      // foreign elements like SVG can't be stringified for innerHTML.\n      return OPTIMIZABLE.NONE;\n    } else if (tagName === 'table') {\n      // Avoid ever producing HTML containing `<table><tr>...`, because the\n      // browser will insert a TBODY.  If we just `createElement(\"table\")` and\n      // `createElement(\"tr\")`, on the other hand, no TBODY is necessary\n      // (assuming IE 8+).\n      return OPTIMIZABLE.NONE;\n    }\n\n    var children = tag.children;\n    for (var i = 0; i < children.length; i++)\n      if (this.visit(children[i]) !== OPTIMIZABLE.FULL)\n        return OPTIMIZABLE.PARTS;\n\n    if (this.visitAttributes(tag.attrs) !== OPTIMIZABLE.FULL)\n      return OPTIMIZABLE.PARTS;\n\n    return OPTIMIZABLE.FULL;\n  },\n  visitAttributes: function (attrs) {\n    if (attrs) {\n      var isArray = HTML.isArray(attrs);\n      for (var i = 0; i < (isArray ? attrs.length : 1); i++) {\n        var a = (isArray ? attrs[i] : attrs);\n        if ((typeof a !== 'object') || (a instanceof HTMLTools.TemplateTag))\n          return OPTIMIZABLE.PARTS;\n        for (var k in a)\n          if (this.visit(a[k]) !== OPTIMIZABLE.FULL)\n            return OPTIMIZABLE.PARTS;\n      }\n    }\n    return OPTIMIZABLE.FULL;\n  }\n});\n\nvar getOptimizability = function (content) {\n  return (new CanOptimizeVisitor).visit(content);\n};\n\nvar toRaw = function (x) {\n  return HTML.Raw(HTML.toHTML(x));\n};\n\nvar TreeTransformer = HTML.TransformingVisitor.extend();\nTreeTransformer.def({\n  visitAttributes: function (attrs/*, ...*/) {\n    // pass template tags through by default\n    if (attrs instanceof HTMLTools.TemplateTag)\n      return attrs;\n\n    return HTML.TransformingVisitor.prototype.visitAttributes.apply(\n      this, arguments);\n  }\n});\n\n// Replace parts of the HTMLjs tree that have no template tags (or\n// tricky HTML tags) with HTML.Raw objects containing raw HTML.\nvar OptimizingVisitor = TreeTransformer.extend();\nOptimizingVisitor.def({\n  visitNull: toRaw,\n  visitPrimitive: toRaw,\n  visitComment: toRaw,\n  visitCharRef: toRaw,\n  visitArray: function (array) {\n    var optimizability = getOptimizability(array);\n    if (optimizability === OPTIMIZABLE.FULL) {\n      return toRaw(array);\n    } else if (optimizability === OPTIMIZABLE.PARTS) {\n      return TreeTransformer.prototype.visitArray.call(this, array);\n    } else {\n      return array;\n    }\n  },\n  visitTag: function (tag) {\n    var optimizability = getOptimizability(tag);\n    if (optimizability === OPTIMIZABLE.FULL) {\n      return toRaw(tag);\n    } else if (optimizability === OPTIMIZABLE.PARTS) {\n      return TreeTransformer.prototype.visitTag.call(this, tag);\n    } else {\n      return tag;\n    }\n  },\n  visitChildren: function (children) {\n    // don't optimize the children array into a Raw object!\n    return TreeTransformer.prototype.visitArray.call(this, children);\n  },\n  visitAttributes: function (attrs) {\n    return attrs;\n  }\n});\n\n// Combine consecutive HTML.Raws.  Remove empty ones.\nvar RawCompactingVisitor = TreeTransformer.extend();\nRawCompactingVisitor.def({\n  visitArray: function (array) {\n    var result = [];\n    for (var i = 0; i < array.length; i++) {\n      var item = array[i];\n      if ((item instanceof HTML.Raw) &&\n          ((! item.value) ||\n           (result.length &&\n            (result[result.length - 1] instanceof HTML.Raw)))) {\n        // two cases: item is an empty Raw, or previous item is\n        // a Raw as well.  In the latter case, replace the previous\n        // Raw with a longer one that includes the new Raw.\n        if (item.value) {\n          result[result.length - 1] = HTML.Raw(\n            result[result.length - 1].value + item.value);\n        }\n      } else {\n        result.push(item);\n      }\n    }\n    return result;\n  }\n});\n\n// Replace pointless Raws like `HTMl.Raw('foo')` that contain no special\n// characters with simple strings.\nvar RawReplacingVisitor = TreeTransformer.extend();\nRawReplacingVisitor.def({\n  visitRaw: function (raw) {\n    var html = raw.value;\n    if (html.indexOf('&') < 0 && html.indexOf('<') < 0) {\n      return html;\n    } else {\n      return raw;\n    }\n  }\n});\n\nSpacebarsCompiler.optimize = function (tree) {\n  tree = (new OptimizingVisitor).visit(tree);\n  tree = (new RawCompactingVisitor).visit(tree);\n  tree = (new RawReplacingVisitor).visit(tree);\n  return tree;\n};\n","// ============================================================\n// Code-generation of template tags\n\n// The `CodeGen` class currently has no instance state, but in theory\n// it could be useful to track per-function state, like whether we\n// need to emit `var self = this` or not.\nvar CodeGen = SpacebarsCompiler.CodeGen = function () {};\n\nvar builtInBlockHelpers = SpacebarsCompiler._builtInBlockHelpers = {\n  'if': 'Blaze.If',\n  'unless': 'Blaze.Unless',\n  'with': 'Spacebars.With',\n  'each': 'Blaze.Each'\n};\n\n\n// Mapping of \"macros\" which, when preceded by `Template.`, expand\n// to special code rather than following the lookup rules for dotted\n// symbols.\nvar builtInTemplateMacros = {\n  // `view` is a local variable defined in the generated render\n  // function for the template in which `Template.contentBlock` or\n  // `Template.elseBlock` is invoked.\n  'contentBlock': 'view.templateContentBlock',\n  'elseBlock': 'view.templateElseBlock',\n\n  // Confusingly, this makes `{{> Template.dynamic}}` an alias\n  // for `{{> __dynamic}}`, where \"__dynamic\" is the template that\n  // implements the dynamic template feature.\n  'dynamic': 'Template.__dynamic',\n\n  'subscriptionsReady': 'view.templateInstance().subscriptionsReady()'\n};\n\n// A \"reserved name\" can't be used as a <template> name.  This\n// function is used by the template file scanner.\n//\n// Note that the runtime imposes additional restrictions, for example\n// banning the name \"body\" and names of built-in object properties\n// like \"toString\".\nSpacebarsCompiler.isReservedName = function (name) {\n  return builtInBlockHelpers.hasOwnProperty(name) ||\n    builtInTemplateMacros.hasOwnProperty(name);\n};\n\nvar makeObjectLiteral = function (obj) {\n  var parts = [];\n  for (var k in obj)\n    parts.push(BlazeTools.toObjectLiteralKey(k) + ': ' + obj[k]);\n  return '{' + parts.join(', ') + '}';\n};\n\n_.extend(CodeGen.prototype, {\n  codeGenTemplateTag: function (tag) {\n    var self = this;\n    if (tag.position === HTMLTools.TEMPLATE_TAG_POSITION.IN_START_TAG) {\n      // Special dynamic attributes: `<div {{attrs}}>...`\n      // only `tag.type === 'DOUBLE'` allowed (by earlier validation)\n      return BlazeTools.EmitCode('function () { return ' +\n          self.codeGenMustache(tag.path, tag.args, 'attrMustache')\n          + '; }');\n    } else {\n      if (tag.type === 'DOUBLE' || tag.type === 'TRIPLE') {\n        var code = self.codeGenMustache(tag.path, tag.args);\n        if (tag.type === 'TRIPLE') {\n          code = 'Spacebars.makeRaw(' + code + ')';\n        }\n        if (tag.position !== HTMLTools.TEMPLATE_TAG_POSITION.IN_ATTRIBUTE) {\n          // Reactive attributes are already wrapped in a function,\n          // and there's no fine-grained reactivity.\n          // Anywhere else, we need to create a View.\n          code = 'Blaze.View(\"lookup:' + tag.path.join('.') + '\", ' +\n            'function () { return ' + code + '; })';\n        }\n        return BlazeTools.EmitCode(code);\n      } else if (tag.type === 'INCLUSION' || tag.type === 'BLOCKOPEN') {\n        var path = tag.path;\n\n        if (tag.type === 'BLOCKOPEN' &&\n            builtInBlockHelpers.hasOwnProperty(path[0])) {\n          // if, unless, with, each.\n          //\n          // If someone tries to do `{{> if}}`, we don't\n          // get here, but an error is thrown when we try to codegen the path.\n\n          // Note: If we caught these errors earlier, while scanning, we'd be able to\n          // provide nice line numbers.\n          if (path.length > 1)\n            throw new Error(\"Unexpected dotted path beginning with \" + path[0]);\n          if (! tag.args.length)\n            throw new Error(\"#\" + path[0] + \" requires an argument\");\n\n          // `args` must exist (tag.args.length > 0)\n          var dataCode = self.codeGenInclusionDataFunc(tag.args) || 'null';\n          // `content` must exist\n          var contentBlock = (('content' in tag) ?\n                              self.codeGenBlock(tag.content) : null);\n          // `elseContent` may not exist\n          var elseContentBlock = (('elseContent' in tag) ?\n                                  self.codeGenBlock(tag.elseContent) : null);\n\n          var callArgs = [dataCode, contentBlock];\n          if (elseContentBlock)\n            callArgs.push(elseContentBlock);\n\n          return BlazeTools.EmitCode(\n            builtInBlockHelpers[path[0]] + '(' + callArgs.join(', ') + ')');\n\n        } else {\n          var compCode = self.codeGenPath(path, {lookupTemplate: true});\n          if (path.length > 1) {\n            // capture reactivity\n            compCode = 'function () { return Spacebars.call(' + compCode +\n              '); }';\n          }\n\n          var dataCode = self.codeGenInclusionDataFunc(tag.args);\n          var content = (('content' in tag) ?\n                         self.codeGenBlock(tag.content) : null);\n          var elseContent = (('elseContent' in tag) ?\n                             self.codeGenBlock(tag.elseContent) : null);\n\n          var includeArgs = [compCode];\n          if (content) {\n            includeArgs.push(content);\n            if (elseContent)\n              includeArgs.push(elseContent);\n          }\n\n          var includeCode =\n                'Spacebars.include(' + includeArgs.join(', ') + ')';\n\n          // calling convention compat -- set the data context around the\n          // entire inclusion, so that if the name of the inclusion is\n          // a helper function, it gets the data context in `this`.\n          // This makes for a pretty confusing calling convention --\n          // In `{{#foo bar}}`, `foo` is evaluated in the context of `bar`\n          // -- but it's what we shipped for 0.8.0.  The rationale is that\n          // `{{#foo bar}}` is sugar for `{{#with bar}}{{#foo}}...`.\n          if (dataCode) {\n            includeCode =\n              'Blaze._TemplateWith(' + dataCode + ', function () { return ' +\n              includeCode + '; })';\n          }\n\n          // XXX BACK COMPAT - UI is the old name, Template is the new\n          if ((path[0] === 'UI' || path[0] === 'Template') &&\n              (path[1] === 'contentBlock' || path[1] === 'elseBlock')) {\n            // Call contentBlock and elseBlock in the appropriate scope\n            includeCode = 'Blaze._InOuterTemplateScope(view, function () { return '\n              + includeCode + '; })';\n          }\n\n          return BlazeTools.EmitCode(includeCode);\n        }\n      } else if (tag.type === 'ESCAPE') {\n        return tag.value;\n      } else {\n        // Can't get here; TemplateTag validation should catch any\n        // inappropriate tag types that might come out of the parser.\n        throw new Error(\"Unexpected template tag type: \" + tag.type);\n      }\n    }\n  },\n\n  // `path` is an array of at least one string.\n  //\n  // If `path.length > 1`, the generated code may be reactive\n  // (i.e. it may invalidate the current computation).\n  //\n  // No code is generated to call the result if it's a function.\n  //\n  // Options:\n  //\n  // - lookupTemplate {Boolean} If true, generated code also looks in\n  //   the list of templates. (After helpers, before data context).\n  //   Used when generating code for `{{> foo}}` or `{{#foo}}`. Only\n  //   used for non-dotted paths.\n  codeGenPath: function (path, opts) {\n    if (builtInBlockHelpers.hasOwnProperty(path[0]))\n      throw new Error(\"Can't use the built-in '\" + path[0] + \"' here\");\n    // Let `{{#if Template.contentBlock}}` check whether this template was\n    // invoked via inclusion or as a block helper, in addition to supporting\n    // `{{> Template.contentBlock}}`.\n    // XXX BACK COMPAT - UI is the old name, Template is the new\n    if (path.length >= 2 &&\n        (path[0] === 'UI' || path[0] === 'Template')\n        && builtInTemplateMacros.hasOwnProperty(path[1])) {\n      if (path.length > 2)\n        throw new Error(\"Unexpected dotted path beginning with \" +\n                        path[0] + '.' + path[1]);\n      return builtInTemplateMacros[path[1]];\n    }\n\n    var firstPathItem = BlazeTools.toJSLiteral(path[0]);\n    var lookupMethod = 'lookup';\n    if (opts && opts.lookupTemplate && path.length === 1)\n      lookupMethod = 'lookupTemplate';\n    var code = 'view.' + lookupMethod + '(' + firstPathItem + ')';\n\n    if (path.length > 1) {\n      code = 'Spacebars.dot(' + code + ', ' +\n        _.map(path.slice(1), BlazeTools.toJSLiteral).join(', ') + ')';\n    }\n\n    return code;\n  },\n\n  // Generates code for an `[argType, argValue]` argument spec,\n  // ignoring the third element (keyword argument name) if present.\n  //\n  // The resulting code may be reactive (in the case of a PATH of\n  // more than one element) and is not wrapped in a closure.\n  codeGenArgValue: function (arg) {\n    var self = this;\n\n    var argType = arg[0];\n    var argValue = arg[1];\n\n    var argCode;\n    switch (argType) {\n    case 'STRING':\n    case 'NUMBER':\n    case 'BOOLEAN':\n    case 'NULL':\n      argCode = BlazeTools.toJSLiteral(argValue);\n      break;\n    case 'PATH':\n      argCode = self.codeGenPath(argValue);\n      break;\n    default:\n      // can't get here\n      throw new Error(\"Unexpected arg type: \" + argType);\n    }\n\n    return argCode;\n  },\n\n  // Generates a call to `Spacebars.fooMustache` on evaluated arguments.\n  // The resulting code has no function literals and must be wrapped in\n  // one for fine-grained reactivity.\n  codeGenMustache: function (path, args, mustacheType) {\n    var self = this;\n\n    var nameCode = self.codeGenPath(path);\n    var argCode = self.codeGenMustacheArgs(args);\n    var mustache = (mustacheType || 'mustache');\n\n    return 'Spacebars.' + mustache + '(' + nameCode +\n      (argCode ? ', ' + argCode.join(', ') : '') + ')';\n  },\n\n  // returns: array of source strings, or null if no\n  // args at all.\n  codeGenMustacheArgs: function (tagArgs) {\n    var self = this;\n\n    var kwArgs = null; // source -> source\n    var args = null; // [source]\n\n    // tagArgs may be null\n    _.each(tagArgs, function (arg) {\n      var argCode = self.codeGenArgValue(arg);\n\n      if (arg.length > 2) {\n        // keyword argument (represented as [type, value, name])\n        kwArgs = (kwArgs || {});\n        kwArgs[arg[2]] = argCode;\n      } else {\n        // positional argument\n        args = (args || []);\n        args.push(argCode);\n      }\n    });\n\n    // put kwArgs in options dictionary at end of args\n    if (kwArgs) {\n      args = (args || []);\n      args.push('Spacebars.kw(' + makeObjectLiteral(kwArgs) + ')');\n    }\n\n    return args;\n  },\n\n  codeGenBlock: function (content) {\n    return SpacebarsCompiler.codeGen(content);\n  },\n\n  codeGenInclusionDataFunc: function (args) {\n    var self = this;\n\n    var dataFuncCode = null;\n\n    if (! args.length) {\n      // e.g. `{{#foo}}`\n      return null;\n    } else if (args[0].length === 3) {\n      // keyword arguments only, e.g. `{{> point x=1 y=2}}`\n      var dataProps = {};\n      _.each(args, function (arg) {\n        var argKey = arg[2];\n        dataProps[argKey] = 'Spacebars.call(' + self.codeGenArgValue(arg) + ')';\n      });\n      dataFuncCode = makeObjectLiteral(dataProps);\n    } else if (args[0][0] !== 'PATH') {\n      // literal first argument, e.g. `{{> foo \"blah\"}}`\n      //\n      // tag validation has confirmed, in this case, that there is only\n      // one argument (`args.length === 1`)\n      dataFuncCode = self.codeGenArgValue(args[0]);\n    } else if (args.length === 1) {\n      // one argument, must be a PATH\n      dataFuncCode = 'Spacebars.call(' + self.codeGenPath(args[0][1]) + ')';\n    } else {\n      // Multiple positional arguments; treat them as a nested\n      // \"data mustache\"\n      dataFuncCode = self.codeGenMustache(args[0][1], args.slice(1),\n                                          'dataMustache');\n    }\n\n    return 'function () { return ' + dataFuncCode + '; }';\n  }\n\n});\n","\nSpacebarsCompiler.parse = function (input) {\n\n  var tree = HTMLTools.parseFragment(\n    input,\n    { getTemplateTag: TemplateTag.parseCompleteTag });\n\n  return tree;\n};\n\nSpacebarsCompiler.compile = function (input, options) {\n  var tree = SpacebarsCompiler.parse(input);\n  return SpacebarsCompiler.codeGen(tree, options);\n};\n\nSpacebarsCompiler._TemplateTagReplacer = HTML.TransformingVisitor.extend();\nSpacebarsCompiler._TemplateTagReplacer.def({\n  visitObject: function (x) {\n    if (x instanceof HTMLTools.TemplateTag) {\n\n      // Make sure all TemplateTags in attributes have the right\n      // `.position` set on them.  This is a bit of a hack\n      // (we shouldn't be mutating that here), but it allows\n      // cleaner codegen of \"synthetic\" attributes like TEXTAREA's\n      // \"value\", where the template tags were originally not\n      // in an attribute.\n      if (this.inAttributeValue)\n        x.position = HTMLTools.TEMPLATE_TAG_POSITION.IN_ATTRIBUTE;\n\n      return this.codegen.codeGenTemplateTag(x);\n    }\n\n    return HTML.TransformingVisitor.prototype.visitObject.call(this, x);\n  },\n  visitAttributes: function (attrs) {\n    if (attrs instanceof HTMLTools.TemplateTag)\n      return this.codegen.codeGenTemplateTag(attrs);\n\n    // call super (e.g. for case where `attrs` is an array)\n    return HTML.TransformingVisitor.prototype.visitAttributes.call(this, attrs);\n  },\n  visitAttribute: function (name, value, tag) {\n    this.inAttributeValue = true;\n    var result = this.visit(value);\n    this.inAttributeValue = false;\n\n    if (result !== value) {\n      // some template tags must have been replaced, because otherwise\n      // we try to keep things `===` when transforming.  Wrap the code\n      // in a function as per the rules.  You can't have\n      // `{id: Blaze.View(...)}` as an attributes dict because the View\n      // would be rendered more than once; you need to wrap it in a function\n      // so that it's a different View each time.\n      return BlazeTools.EmitCode(this.codegen.codeGenBlock(result));\n    }\n    return result;\n  }\n});\n\nSpacebarsCompiler.codeGen = function (parseTree, options) {\n  // is this a template, rather than a block passed to\n  // a block helper, say\n  var isTemplate = (options && options.isTemplate);\n  var isBody = (options && options.isBody);\n\n  var tree = parseTree;\n\n  // The flags `isTemplate` and `isBody` are kind of a hack.\n  if (isTemplate || isBody) {\n    // optimizing fragments would require being smarter about whether we are\n    // in a TEXTAREA, say.\n    tree = SpacebarsCompiler.optimize(tree);\n  }\n\n  var codegen = new SpacebarsCompiler.CodeGen;\n  tree = (new SpacebarsCompiler._TemplateTagReplacer(\n    {codegen: codegen})).visit(tree);\n\n  var code = '(function () { ';\n  if (isTemplate || isBody) {\n    code += 'var view = this; ';\n  }\n  code += 'return ';\n  code += BlazeTools.toJS(tree);\n  code += '; })';\n\n  code = SpacebarsCompiler._beautify(code);\n\n  return code;\n};\n\nSpacebarsCompiler._beautify = function (code) {\n  if (Package.minifiers && Package.minifiers.UglifyJSMinify) {\n    var result = Package.minifiers.UglifyJSMinify(\n      code,\n      { fromString: true,\n        mangle: false,\n        compress: false,\n        output: { beautify: true,\n                  indent_level: 2,\n                  width: 80 } });\n    var output = result.code;\n    // Uglify interprets our expression as a statement and may add a semicolon.\n    // Strip trailing semicolon.\n    output = output.replace(/;$/, '');\n    return output;\n  } else {\n    // don't actually beautify; no UglifyJS\n    return code;\n  }\n};\n"]}