diff --git a/README.rst b/README.rst
index 4f9a3f7..9f347e8 100644
--- a/README.rst
+++ b/README.rst
@@ -367,3 +367,34 @@ the dispatcher invokes ``certidude`` in order to generate RSA keys,
submit CSR, fetch signed certificate,
create NetworkManager configuration for the VPN connection and
finally to bring up the VPN tunnel as well.
+
+
+Development
+-----------
+
+Clone the repository:
+
+.. code:: bash
+
+ git clone https://github.com/laurivosandi/certidude
+ cd certidude
+
+To generate templates:
+
+.. code:: bash
+
+ apt-get install npm nodejs
+ npm install nunjucks
+ nunjucks-precompile --include "\\.html$" --include "\\.svg" certidude/static/ > certidude/static/js/templates.js
+
+To run from source tree:
+
+.. code:: bash
+
+ PYTHONPATH=. KRB5_KTNAME=/etc/certidude/server.keytab LANG=C.UTF-8 python3 misc/certidude
+
+To install the package from the source:
+
+.. code:: bash
+
+ python3 setup.py install --single-version-externally-managed --root /
diff --git a/certidude/static/index.html b/certidude/static/index.html
index ed05e61..f677127 100644
--- a/certidude/static/index.html
+++ b/certidude/static/index.html
@@ -6,7 +6,8 @@
Certidude server
-
+
+
diff --git a/certidude/static/js/certidude.js b/certidude/static/js/certidude.js
index 9edcdbe..533e43d 100644
--- a/certidude/static/js/certidude.js
+++ b/certidude/static/js/certidude.js
@@ -50,7 +50,7 @@ function onLogEntry (e) {
var entry = JSON.parse(e.data);
if ($("#log_level_" + entry.severity).prop("checked")) {
console.info("Received log entry:", entry);
- $("#log_entries").prepend(nunjucks.render("logentry.html", {
+ $("#log_entries").prepend(nunjucks.render("views/logentry.html", {
entry: {
created: new Date(entry.created).toLocaleString(),
message: entry.message,
@@ -69,7 +69,7 @@ function onRequestSubmitted(e) {
success: function(request, status, xhr) {
console.info(request);
$("#pending_requests").prepend(
- nunjucks.render('request.html', { request: request }));
+ nunjucks.render('views/request.html', { request: request }));
}
});
}
@@ -83,7 +83,7 @@ function onClientUp(e) {
console.log("Adding security association:" + e.data);
var lease = JSON.parse(e.data);
var $status = $("#signed_certificates [data-dn='" + lease.identity + "'] .status");
- $status.html(nunjucks.render('status.html', {
+ $status.html(nunjucks.render('views/status.html', {
lease: {
address: lease.address,
identity: lease.identity,
@@ -96,7 +96,7 @@ function onClientDown(e) {
console.log("Removing security association:" + e.data);
var lease = JSON.parse(e.data);
var $status = $("#signed_certificates [data-dn='" + lease.identity + "'] .status");
- $status.html(nunjucks.render('status.html', {
+ $status.html(nunjucks.render('views/status.html', {
lease: {
address: lease.address,
identity: lease.identity,
@@ -116,7 +116,7 @@ function onRequestSigned(e) {
success: function(certificate, status, xhr) {
console.info(certificate);
$("#signed_certificates").prepend(
- nunjucks.render('signed.html', { certificate: certificate }));
+ nunjucks.render('views/signed.html', { certificate: certificate }));
}
});
}
@@ -172,7 +172,7 @@ $(document).ready(function() {
} else {
var msg = { title: "Error " + response.status, description: response.statusText }
}
- $("#container").html(nunjucks.render('error.html', { message: msg }));
+ $("#container").html(nunjucks.render('views/error.html', { message: msg }));
},
success: function(session, status, xhr) {
console.info("Opening EventSource from:", session.event_channel);
@@ -197,7 +197,7 @@ $(document).ready(function() {
/**
* Render authority views
**/
- $("#container").html(nunjucks.render('authority.html', { session: session, window: window }));
+ $("#container").html(nunjucks.render('views/authority.html', { session: session, window: window }));
console.info("Swtiching to requests section");
$("section").hide();
$("section#requests").show();
@@ -239,7 +239,7 @@ $(document).ready(function() {
dataType: "json",
success: function(configuration, status, xhr) {
console.info("Appending " + configuration.length + " configuration items");
- $("#config").html(nunjucks.render('configuration.html', { configuration:configuration}));
+ $("#config").html(nunjucks.render('views/configuration.html', { configuration:configuration}));
/**
* Fetch tags for certificates
*/
@@ -278,7 +278,7 @@ $(document).ready(function() {
console.info("Detected rogue client:", leases[j]);
continue;
}
- $status.html(nunjucks.render('status.html', {
+ $status.html(nunjucks.render('views/status.html', {
lease: {
address: leases[j].address,
identity: leases[j].identity,
@@ -301,7 +301,7 @@ $(document).ready(function() {
console.info("Got", entries.length, "log entries");
for (var j = 0; j < entries.length; j++) {
if ($("#log_level_" + entries[j].severity).prop("checked")) {
- $("#log_entries").append(nunjucks.render("logentry.html", {
+ $("#log_entries").append(nunjucks.render("views/logentry.html", {
entry: {
created: new Date(entries[j].created).toLocaleString("et-EE"),
message: entries[j].message,
diff --git a/certidude/static/js/nunjucks-slim.js b/certidude/static/js/nunjucks-slim.js
new file mode 100644
index 0000000..0b0914b
--- /dev/null
+++ b/certidude/static/js/nunjucks-slim.js
@@ -0,0 +1,2633 @@
+/*! Browser bundle of nunjucks 2.3.0 (slim, only works with precompiled templates) */
+var nunjucks =
+/******/ (function(modules) { // webpackBootstrap
+/******/ // The module cache
+/******/ var installedModules = {};
+
+/******/ // The require function
+/******/ function __webpack_require__(moduleId) {
+
+/******/ // Check if module is in cache
+/******/ if(installedModules[moduleId])
+/******/ return installedModules[moduleId].exports;
+
+/******/ // Create a new module (and put it into the cache)
+/******/ var module = installedModules[moduleId] = {
+/******/ exports: {},
+/******/ id: moduleId,
+/******/ loaded: false
+/******/ };
+
+/******/ // Execute the module function
+/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+
+/******/ // Flag the module as loaded
+/******/ module.loaded = true;
+
+/******/ // Return the exports of the module
+/******/ return module.exports;
+/******/ }
+
+
+/******/ // expose the modules object (__webpack_modules__)
+/******/ __webpack_require__.m = modules;
+
+/******/ // expose the module cache
+/******/ __webpack_require__.c = installedModules;
+
+/******/ // __webpack_public_path__
+/******/ __webpack_require__.p = "";
+
+/******/ // Load entry module and return exports
+/******/ return __webpack_require__(0);
+/******/ })
+/************************************************************************/
+/******/ ([
+/* 0 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var env = __webpack_require__(2);
+ var Loader = __webpack_require__(11);
+ var loaders = __webpack_require__(3);
+ var precompile = __webpack_require__(3);
+
+ module.exports = {};
+ module.exports.Environment = env.Environment;
+ module.exports.Template = env.Template;
+
+ module.exports.Loader = Loader;
+ module.exports.FileSystemLoader = loaders.FileSystemLoader;
+ module.exports.PrecompiledLoader = loaders.PrecompiledLoader;
+ module.exports.WebLoader = loaders.WebLoader;
+
+ module.exports.compiler = __webpack_require__(3);
+ module.exports.parser = __webpack_require__(3);
+ module.exports.lexer = __webpack_require__(3);
+ module.exports.runtime = __webpack_require__(8);
+ module.exports.lib = lib;
+ module.exports.nodes = __webpack_require__(3);
+
+ module.exports.installJinjaCompat = __webpack_require__(12);
+
+ // A single instance of an environment, since this is so commonly used
+
+ var e;
+ module.exports.configure = function(templatesPath, opts) {
+ opts = opts || {};
+ if(lib.isObject(templatesPath)) {
+ opts = templatesPath;
+ templatesPath = null;
+ }
+
+ var TemplateLoader;
+ if(loaders.FileSystemLoader) {
+ TemplateLoader = new loaders.FileSystemLoader(templatesPath, {
+ watch: opts.watch,
+ noCache: opts.noCache
+ });
+ }
+ else if(loaders.WebLoader) {
+ TemplateLoader = new loaders.WebLoader(templatesPath, {
+ useCache: opts.web && opts.web.useCache,
+ async: opts.web && opts.web.async
+ });
+ }
+
+ e = new env.Environment(TemplateLoader, opts);
+
+ if(opts && opts.express) {
+ e.express(opts.express);
+ }
+
+ return e;
+ };
+
+ module.exports.compile = function(src, env, path, eagerCompile) {
+ if(!e) {
+ module.exports.configure();
+ }
+ return new module.exports.Template(src, env, path, eagerCompile);
+ };
+
+ module.exports.render = function(name, ctx, cb) {
+ if(!e) {
+ module.exports.configure();
+ }
+
+ return e.render(name, ctx, cb);
+ };
+
+ module.exports.renderString = function(src, ctx, cb) {
+ if(!e) {
+ module.exports.configure();
+ }
+
+ return e.renderString(src, ctx, cb);
+ };
+
+ if(precompile) {
+ module.exports.precompile = precompile.precompile;
+ module.exports.precompileString = precompile.precompileString;
+ }
+
+
+/***/ },
+/* 1 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ var ArrayProto = Array.prototype;
+ var ObjProto = Object.prototype;
+
+ var escapeMap = {
+ '&': '&',
+ '"': '"',
+ '\'': ''',
+ '<': '<',
+ '>': '>'
+ };
+
+ var escapeRegex = /[&"'<>]/g;
+
+ var lookupEscape = function(ch) {
+ return escapeMap[ch];
+ };
+
+ var exports = module.exports = {};
+
+ exports.prettifyError = function(path, withInternals, err) {
+ // jshint -W022
+ // http://jslinterrors.com/do-not-assign-to-the-exception-parameter
+ if (!err.Update) {
+ // not one of ours, cast it
+ err = new exports.TemplateError(err);
+ }
+ err.Update(path);
+
+ // Unless they marked the dev flag, show them a trace from here
+ if (!withInternals) {
+ var old = err;
+ err = new Error(old.message);
+ err.name = old.name;
+ }
+
+ return err;
+ };
+
+ exports.TemplateError = function(message, lineno, colno) {
+ var err = this;
+
+ if (message instanceof Error) { // for casting regular js errors
+ err = message;
+ message = message.name + ': ' + message.message;
+
+ try {
+ if(err.name = '') {}
+ }
+ catch(e) {
+ // If we can't set the name of the error object in this
+ // environment, don't use it
+ err = this;
+ }
+ } else {
+ if(Error.captureStackTrace) {
+ Error.captureStackTrace(err);
+ }
+ }
+
+ err.name = 'Template render error';
+ err.message = message;
+ err.lineno = lineno;
+ err.colno = colno;
+ err.firstUpdate = true;
+
+ err.Update = function(path) {
+ var message = '(' + (path || 'unknown path') + ')';
+
+ // only show lineno + colno next to path of template
+ // where error occurred
+ if (this.firstUpdate) {
+ if(this.lineno && this.colno) {
+ message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']';
+ }
+ else if(this.lineno) {
+ message += ' [Line ' + this.lineno + ']';
+ }
+ }
+
+ message += '\n ';
+ if (this.firstUpdate) {
+ message += ' ';
+ }
+
+ this.message = message + (this.message || '');
+ this.firstUpdate = false;
+ return this;
+ };
+
+ return err;
+ };
+
+ exports.TemplateError.prototype = Error.prototype;
+
+ exports.escape = function(val) {
+ return val.replace(escapeRegex, lookupEscape);
+ };
+
+ exports.isFunction = function(obj) {
+ return ObjProto.toString.call(obj) === '[object Function]';
+ };
+
+ exports.isArray = Array.isArray || function(obj) {
+ return ObjProto.toString.call(obj) === '[object Array]';
+ };
+
+ exports.isString = function(obj) {
+ return ObjProto.toString.call(obj) === '[object String]';
+ };
+
+ exports.isObject = function(obj) {
+ return ObjProto.toString.call(obj) === '[object Object]';
+ };
+
+ exports.groupBy = function(obj, val) {
+ var result = {};
+ var iterator = exports.isFunction(val) ? val : function(obj) { return obj[val]; };
+ for(var i=0; i>> 0; // Hack to convert object.length to a UInt32
+
+ fromIndex = +fromIndex || 0;
+
+ if(Math.abs(fromIndex) === Infinity) {
+ fromIndex = 0;
+ }
+
+ if(fromIndex < 0) {
+ fromIndex += length;
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ }
+
+ for(;fromIndex < length; fromIndex++) {
+ if (arr[fromIndex] === searchElement) {
+ return fromIndex;
+ }
+ }
+
+ return -1;
+ };
+
+ if(!Array.prototype.map) {
+ Array.prototype.map = function() {
+ throw new Error('map is unimplemented for this js engine');
+ };
+ }
+
+ exports.keys = function(obj) {
+ if(Object.prototype.keys) {
+ return obj.keys();
+ }
+ else {
+ var keys = [];
+ for(var k in obj) {
+ if(obj.hasOwnProperty(k)) {
+ keys.push(k);
+ }
+ }
+ return keys;
+ }
+ };
+
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var asap = __webpack_require__(4);
+ var lib = __webpack_require__(1);
+ var Obj = __webpack_require__(6);
+ var compiler = __webpack_require__(3);
+ var builtin_filters = __webpack_require__(7);
+ var builtin_loaders = __webpack_require__(3);
+ var runtime = __webpack_require__(8);
+ var globals = __webpack_require__(9);
+ var Frame = runtime.Frame;
+ var Template;
+
+ // Unconditionally load in this loader, even if no other ones are
+ // included (possible in the slim browser build)
+ builtin_loaders.PrecompiledLoader = __webpack_require__(10);
+
+ // If the user is using the async API, *always* call it
+ // asynchronously even if the template was synchronous.
+ function callbackAsap(cb, err, res) {
+ asap(function() { cb(err, res); });
+ }
+
+ var Environment = Obj.extend({
+ init: function(loaders, opts) {
+ // The dev flag determines the trace that'll be shown on errors.
+ // If set to true, returns the full trace from the error point,
+ // otherwise will return trace starting from Template.render
+ // (the full trace from within nunjucks may confuse developers using
+ // the library)
+ // defaults to false
+ opts = this.opts = opts || {};
+ this.opts.dev = !!opts.dev;
+
+ // The autoescape flag sets global autoescaping. If true,
+ // every string variable will be escaped by default.
+ // If false, strings can be manually escaped using the `escape` filter.
+ // defaults to true
+ this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true;
+
+ // If true, this will make the system throw errors if trying
+ // to output a null or undefined value
+ this.opts.throwOnUndefined = !!opts.throwOnUndefined;
+ this.opts.trimBlocks = !!opts.trimBlocks;
+ this.opts.lstripBlocks = !!opts.lstripBlocks;
+
+ this.loaders = [];
+
+ if(!loaders) {
+ // The filesystem loader is only available server-side
+ if(builtin_loaders.FileSystemLoader) {
+ this.loaders = [new builtin_loaders.FileSystemLoader('views')];
+ }
+ else if(builtin_loaders.WebLoader) {
+ this.loaders = [new builtin_loaders.WebLoader('/views')];
+ }
+ }
+ else {
+ this.loaders = lib.isArray(loaders) ? loaders : [loaders];
+ }
+
+ // It's easy to use precompiled templates: just include them
+ // before you configure nunjucks and this will automatically
+ // pick it up and use it
+ if((true) && window.nunjucksPrecompiled) {
+ this.loaders.unshift(
+ new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled)
+ );
+ }
+
+ this.initCache();
+
+ this.globals = globals();
+ this.filters = {};
+ this.asyncFilters = [];
+ this.extensions = {};
+ this.extensionsList = [];
+
+ for(var name in builtin_filters) {
+ this.addFilter(name, builtin_filters[name]);
+ }
+ },
+
+ initCache: function() {
+ // Caching and cache busting
+ lib.each(this.loaders, function(loader) {
+ loader.cache = {};
+
+ if(typeof loader.on === 'function') {
+ loader.on('update', function(template) {
+ loader.cache[template] = null;
+ });
+ }
+ });
+ },
+
+ addExtension: function(name, extension) {
+ extension._name = name;
+ this.extensions[name] = extension;
+ this.extensionsList.push(extension);
+ return this;
+ },
+
+ removeExtension: function(name) {
+ var extension = this.getExtension(name);
+ if (!extension) return;
+
+ this.extensionsList = lib.without(this.extensionsList, extension);
+ delete this.extensions[name];
+ },
+
+ getExtension: function(name) {
+ return this.extensions[name];
+ },
+
+ hasExtension: function(name) {
+ return !!this.extensions[name];
+ },
+
+ addGlobal: function(name, value) {
+ this.globals[name] = value;
+ return this;
+ },
+
+ getGlobal: function(name) {
+ if(!this.globals[name]) {
+ throw new Error('global not found: ' + name);
+ }
+ return this.globals[name];
+ },
+
+ addFilter: function(name, func, async) {
+ var wrapped = func;
+
+ if(async) {
+ this.asyncFilters.push(name);
+ }
+ this.filters[name] = wrapped;
+ return this;
+ },
+
+ getFilter: function(name) {
+ if(!this.filters[name]) {
+ throw new Error('filter not found: ' + name);
+ }
+ return this.filters[name];
+ },
+
+ resolveTemplate: function(loader, parentName, filename) {
+ var isRelative = (loader.isRelative && parentName)? loader.isRelative(filename) : false;
+ return (isRelative && loader.resolve)? loader.resolve(parentName, filename) : filename;
+ },
+
+ getTemplate: function(name, eagerCompile, parentName, ignoreMissing, cb) {
+ var that = this;
+ var tmpl = null;
+ if(name && name.raw) {
+ // this fixes autoescape for templates referenced in symbols
+ name = name.raw;
+ }
+
+ if(lib.isFunction(parentName)) {
+ cb = parentName;
+ parentName = null;
+ eagerCompile = eagerCompile || false;
+ }
+
+ if(lib.isFunction(eagerCompile)) {
+ cb = eagerCompile;
+ eagerCompile = false;
+ }
+
+ if (name instanceof Template) {
+ tmpl = name;
+ }
+ else if(typeof name !== 'string') {
+ throw new Error('template names must be a string: ' + name);
+ }
+ else {
+ for (var i = 0; i < this.loaders.length; i++) {
+ var _name = this.resolveTemplate(this.loaders[i], parentName, name);
+ tmpl = this.loaders[i].cache[_name];
+ if (tmpl) break;
+ }
+ }
+
+ if(tmpl) {
+ if(eagerCompile) {
+ tmpl.compile();
+ }
+
+ if(cb) {
+ cb(null, tmpl);
+ }
+ else {
+ return tmpl;
+ }
+ } else {
+ var syncResult;
+ var _this = this;
+
+ var createTemplate = function(err, info) {
+ if(!info && !err) {
+ if(!ignoreMissing) {
+ err = new Error('template not found: ' + name);
+ }
+ }
+
+ if (err) {
+ if(cb) {
+ cb(err);
+ }
+ else {
+ throw err;
+ }
+ }
+ else {
+ var tmpl;
+ if(info) {
+ tmpl = new Template(info.src, _this,
+ info.path, eagerCompile);
+
+ if(!info.noCache) {
+ info.loader.cache[name] = tmpl;
+ }
+ }
+ else {
+ tmpl = new Template('', _this,
+ '', eagerCompile);
+ }
+
+ if(cb) {
+ cb(null, tmpl);
+ }
+ else {
+ syncResult = tmpl;
+ }
+ }
+ };
+
+ lib.asyncIter(this.loaders, function(loader, i, next, done) {
+ function handle(err, src) {
+ if(err) {
+ done(err);
+ }
+ else if(src) {
+ src.loader = loader;
+ done(null, src);
+ }
+ else {
+ next();
+ }
+ }
+
+ // Resolve name relative to parentName
+ name = that.resolveTemplate(loader, parentName, name);
+
+ if(loader.async) {
+ loader.getSource(name, handle);
+ }
+ else {
+ handle(null, loader.getSource(name));
+ }
+ }, createTemplate);
+
+ return syncResult;
+ }
+ },
+
+ express: function(app) {
+ var env = this;
+
+ function NunjucksView(name, opts) {
+ this.name = name;
+ this.path = name;
+ this.defaultEngine = opts.defaultEngine;
+ this.ext = path.extname(name);
+ if (!this.ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
+ if (!this.ext) this.name += (this.ext = ('.' !== this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
+ }
+
+ NunjucksView.prototype.render = function(opts, cb) {
+ env.render(this.name, opts, cb);
+ };
+
+ app.set('view', NunjucksView);
+ return this;
+ },
+
+ render: function(name, ctx, cb) {
+ if(lib.isFunction(ctx)) {
+ cb = ctx;
+ ctx = null;
+ }
+
+ // We support a synchronous API to make it easier to migrate
+ // existing code to async. This works because if you don't do
+ // anything async work, the whole thing is actually run
+ // synchronously.
+ var syncResult = null;
+
+ this.getTemplate(name, function(err, tmpl) {
+ if(err && cb) {
+ callbackAsap(cb, err);
+ }
+ else if(err) {
+ throw err;
+ }
+ else {
+ syncResult = tmpl.render(ctx, cb);
+ }
+ });
+
+ return syncResult;
+ },
+
+ renderString: function(src, ctx, opts, cb) {
+ if(lib.isFunction(opts)) {
+ cb = opts;
+ opts = {};
+ }
+ opts = opts || {};
+
+ var tmpl = new Template(src, this, opts.path);
+ return tmpl.render(ctx, cb);
+ }
+ });
+
+ var Context = Obj.extend({
+ init: function(ctx, blocks, env) {
+ // Has to be tied to an environment so we can tap into its globals.
+ this.env = env || new Environment();
+
+ // Make a duplicate of ctx
+ this.ctx = {};
+ for(var k in ctx) {
+ if(ctx.hasOwnProperty(k)) {
+ this.ctx[k] = ctx[k];
+ }
+ }
+
+ this.blocks = {};
+ this.exported = [];
+
+ for(var name in blocks) {
+ this.addBlock(name, blocks[name]);
+ }
+ },
+
+ lookup: function(name) {
+ // This is one of the most called functions, so optimize for
+ // the typical case where the name isn't in the globals
+ if(name in this.env.globals && !(name in this.ctx)) {
+ return this.env.globals[name];
+ }
+ else {
+ return this.ctx[name];
+ }
+ },
+
+ setVariable: function(name, val) {
+ this.ctx[name] = val;
+ },
+
+ getVariables: function() {
+ return this.ctx;
+ },
+
+ addBlock: function(name, block) {
+ this.blocks[name] = this.blocks[name] || [];
+ this.blocks[name].push(block);
+ return this;
+ },
+
+ getBlock: function(name) {
+ if(!this.blocks[name]) {
+ throw new Error('unknown block "' + name + '"');
+ }
+
+ return this.blocks[name][0];
+ },
+
+ getSuper: function(env, name, block, frame, runtime, cb) {
+ var idx = lib.indexOf(this.blocks[name] || [], block);
+ var blk = this.blocks[name][idx + 1];
+ var context = this;
+
+ if(idx === -1 || !blk) {
+ throw new Error('no super block available for "' + name + '"');
+ }
+
+ blk(env, context, frame, runtime, cb);
+ },
+
+ addExport: function(name) {
+ this.exported.push(name);
+ },
+
+ getExported: function() {
+ var exported = {};
+ for(var i=0; i capacity) {
+ // Manually shift all values starting at the index back to the
+ // beginning of the queue.
+ for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
+ queue[scan] = queue[scan + index];
+ }
+ queue.length -= index;
+ index = 0;
+ }
+ }
+ queue.length = 0;
+ index = 0;
+ flushing = false;
+ }
+
+ // `requestFlush` is implemented using a strategy based on data collected from
+ // every available SauceLabs Selenium web driver worker at time of writing.
+ // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
+
+ // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
+ // have WebKitMutationObserver but not un-prefixed MutationObserver.
+ // Must use `global` instead of `window` to work in both frames and web
+ // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
+ var BrowserMutationObserver = global.MutationObserver || global.WebKitMutationObserver;
+
+ // MutationObservers are desirable because they have high priority and work
+ // reliably everywhere they are implemented.
+ // They are implemented in all modern browsers.
+ //
+ // - Android 4-4.3
+ // - Chrome 26-34
+ // - Firefox 14-29
+ // - Internet Explorer 11
+ // - iPad Safari 6-7.1
+ // - iPhone Safari 7-7.1
+ // - Safari 6-7
+ if (typeof BrowserMutationObserver === "function") {
+ requestFlush = makeRequestCallFromMutationObserver(flush);
+
+ // MessageChannels are desirable because they give direct access to the HTML
+ // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
+ // 11-12, and in web workers in many engines.
+ // Although message channels yield to any queued rendering and IO tasks, they
+ // would be better than imposing the 4ms delay of timers.
+ // However, they do not work reliably in Internet Explorer or Safari.
+
+ // Internet Explorer 10 is the only browser that has setImmediate but does
+ // not have MutationObservers.
+ // Although setImmediate yields to the browser's renderer, it would be
+ // preferrable to falling back to setTimeout since it does not have
+ // the minimum 4ms penalty.
+ // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
+ // Desktop to a lesser extent) that renders both setImmediate and
+ // MessageChannel useless for the purposes of ASAP.
+ // https://github.com/kriskowal/q/issues/396
+
+ // Timers are implemented universally.
+ // We fall back to timers in workers in most engines, and in foreground
+ // contexts in the following browsers.
+ // However, note that even this simple case requires nuances to operate in a
+ // broad spectrum of browsers.
+ //
+ // - Firefox 3-13
+ // - Internet Explorer 6-9
+ // - iPad Safari 4.3
+ // - Lynx 2.8.7
+ } else {
+ requestFlush = makeRequestCallFromTimer(flush);
+ }
+
+ // `requestFlush` requests that the high priority event queue be flushed as
+ // soon as possible.
+ // This is useful to prevent an error thrown in a task from stalling the event
+ // queue if the exception handled by Node.js’s
+ // `process.on("uncaughtException")` or by a domain.
+ rawAsap.requestFlush = requestFlush;
+
+ // To request a high priority event, we induce a mutation observer by toggling
+ // the text of a text node between "1" and "-1".
+ function makeRequestCallFromMutationObserver(callback) {
+ var toggle = 1;
+ var observer = new BrowserMutationObserver(callback);
+ var node = document.createTextNode("");
+ observer.observe(node, {characterData: true});
+ return function requestCall() {
+ toggle = -toggle;
+ node.data = toggle;
+ };
+ }
+
+ // The message channel technique was discovered by Malte Ubl and was the
+ // original foundation for this library.
+ // http://www.nonblocking.io/2011/06/windownexttick.html
+
+ // Safari 6.0.5 (at least) intermittently fails to create message ports on a
+ // page's first load. Thankfully, this version of Safari supports
+ // MutationObservers, so we don't need to fall back in that case.
+
+ // function makeRequestCallFromMessageChannel(callback) {
+ // var channel = new MessageChannel();
+ // channel.port1.onmessage = callback;
+ // return function requestCall() {
+ // channel.port2.postMessage(0);
+ // };
+ // }
+
+ // For reasons explained above, we are also unable to use `setImmediate`
+ // under any circumstances.
+ // Even if we were, there is another bug in Internet Explorer 10.
+ // It is not sufficient to assign `setImmediate` to `requestFlush` because
+ // `setImmediate` must be called *by name* and therefore must be wrapped in a
+ // closure.
+ // Never forget.
+
+ // function makeRequestCallFromSetImmediate(callback) {
+ // return function requestCall() {
+ // setImmediate(callback);
+ // };
+ // }
+
+ // Safari 6.0 has a problem where timers will get lost while the user is
+ // scrolling. This problem does not impact ASAP because Safari 6.0 supports
+ // mutation observers, so that implementation is used instead.
+ // However, if we ever elect to use timers in Safari, the prevalent work-around
+ // is to add a scroll event listener that calls for a flush.
+
+ // `setTimeout` does not call the passed callback if the delay is less than
+ // approximately 7 in web workers in Firefox 8 through 18, and sometimes not
+ // even then.
+
+ function makeRequestCallFromTimer(callback) {
+ return function requestCall() {
+ // We dispatch a timeout with a specified delay of 0 for engines that
+ // can reliably accommodate that request. This will usually be snapped
+ // to a 4 milisecond delay, but once we're flushing, there's no delay
+ // between events.
+ var timeoutHandle = setTimeout(handleTimer, 0);
+ // However, since this timer gets frequently dropped in Firefox
+ // workers, we enlist an interval handle that will try to fire
+ // an event 20 times per second until it succeeds.
+ var intervalHandle = setInterval(handleTimer, 50);
+
+ function handleTimer() {
+ // Whichever timer succeeds will cancel both timers and
+ // execute the callback.
+ clearTimeout(timeoutHandle);
+ clearInterval(intervalHandle);
+ callback();
+ }
+ };
+ }
+
+ // This is for `asap.js` only.
+ // Its name will be periodically randomized to break any code that depends on
+ // its existence.
+ rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
+
+ // ASAP was originally a nextTick shim included in Q. This was factored out
+ // into this ASAP package. It was later adapted to RSVP which made further
+ // amendments. These decisions, particularly to marginalize MessageChannel and
+ // to capture the MutationObserver implementation in a closure, were integrated
+ // back into ASAP proper.
+ // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 6 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ // A simple class system, more documentation to come
+
+ function extend(cls, name, props) {
+ // This does that same thing as Object.create, but with support for IE8
+ var F = function() {};
+ F.prototype = cls.prototype;
+ var prototype = new F();
+
+ // jshint undef: false
+ var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/;
+ props = props || {};
+
+ for(var k in props) {
+ var src = props[k];
+ var parent = prototype[k];
+
+ if(typeof parent === 'function' &&
+ typeof src === 'function' &&
+ fnTest.test(src)) {
+ /*jshint -W083 */
+ prototype[k] = (function (src, parent) {
+ return function() {
+ // Save the current parent method
+ var tmp = this.parent;
+
+ // Set parent to the previous method, call, and restore
+ this.parent = parent;
+ var res = src.apply(this, arguments);
+ this.parent = tmp;
+
+ return res;
+ };
+ })(src, parent);
+ }
+ else {
+ prototype[k] = src;
+ }
+ }
+
+ prototype.typename = name;
+
+ var new_cls = function() {
+ if(prototype.init) {
+ prototype.init.apply(this, arguments);
+ }
+ };
+
+ new_cls.prototype = prototype;
+ new_cls.prototype.constructor = new_cls;
+
+ new_cls.extend = function(name, props) {
+ if(typeof name === 'object') {
+ props = name;
+ name = 'anonymous';
+ }
+ return extend(new_cls, name, props);
+ };
+
+ return new_cls;
+ }
+
+ module.exports = extend(Object, 'Object', {});
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var r = __webpack_require__(8);
+
+ function normalize(value, defaultValue) {
+ if(value === null || value === undefined || value === false) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ var filters = {
+ abs: function(n) {
+ return Math.abs(n);
+ },
+
+ batch: function(arr, linecount, fill_with) {
+ var i;
+ var res = [];
+ var tmp = [];
+
+ for(i = 0; i < arr.length; i++) {
+ if(i % linecount === 0 && tmp.length) {
+ res.push(tmp);
+ tmp = [];
+ }
+
+ tmp.push(arr[i]);
+ }
+
+ if(tmp.length) {
+ if(fill_with) {
+ for(i = tmp.length; i < linecount; i++) {
+ tmp.push(fill_with);
+ }
+ }
+
+ res.push(tmp);
+ }
+
+ return res;
+ },
+
+ capitalize: function(str) {
+ str = normalize(str, '');
+ var ret = str.toLowerCase();
+ return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1));
+ },
+
+ center: function(str, width) {
+ str = normalize(str, '');
+ width = width || 80;
+
+ if(str.length >= width) {
+ return str;
+ }
+
+ var spaces = width - str.length;
+ var pre = lib.repeat(' ', spaces/2 - spaces % 2);
+ var post = lib.repeat(' ', spaces/2);
+ return r.copySafeness(str, pre + str + post);
+ },
+
+ 'default': function(val, def, bool) {
+ if(bool) {
+ return val ? val : def;
+ }
+ else {
+ return (val !== undefined) ? val : def;
+ }
+ },
+
+ dictsort: function(val, case_sensitive, by) {
+ if (!lib.isObject(val)) {
+ throw new lib.TemplateError('dictsort filter: val must be an object');
+ }
+
+ var array = [];
+ for (var k in val) {
+ // deliberately include properties from the object's prototype
+ array.push([k,val[k]]);
+ }
+
+ var si;
+ if (by === undefined || by === 'key') {
+ si = 0;
+ } else if (by === 'value') {
+ si = 1;
+ } else {
+ throw new lib.TemplateError(
+ 'dictsort filter: You can only sort by either key or value');
+ }
+
+ array.sort(function(t1, t2) {
+ var a = t1[si];
+ var b = t2[si];
+
+ if (!case_sensitive) {
+ if (lib.isString(a)) {
+ a = a.toUpperCase();
+ }
+ if (lib.isString(b)) {
+ b = b.toUpperCase();
+ }
+ }
+
+ return a > b ? 1 : (a === b ? 0 : -1);
+ });
+
+ return array;
+ },
+
+ dump: function(obj) {
+ return JSON.stringify(obj);
+ },
+
+ escape: function(str) {
+ if(typeof str === 'string' ||
+ str instanceof r.SafeString) {
+ return lib.escape(str);
+ }
+ return str;
+ },
+
+ safe: function(str) {
+ return r.markSafe(str);
+ },
+
+ first: function(arr) {
+ return arr[0];
+ },
+
+ groupby: function(arr, attr) {
+ return lib.groupBy(arr, attr);
+ },
+
+ indent: function(str, width, indentfirst) {
+ str = normalize(str, '');
+
+ if (str === '') return '';
+
+ width = width || 4;
+ var res = '';
+ var lines = str.split('\n');
+ var sp = lib.repeat(' ', width);
+
+ for(var i=0; i .a.b.c.
+ res = new_ + str.split('').join(new_) + new_;
+ return r.copySafeness(str, res);
+ }
+
+ var nextIndex = str.indexOf(old);
+ // if # of replacements to perform is 0, or the string to does
+ // not contain the old value, return the string
+ if(maxCount === 0 || nextIndex === -1){
+ return str;
+ }
+
+ var pos = 0;
+ var count = 0; // # of replacements made
+
+ while(nextIndex > -1 && (maxCount === -1 || count < maxCount)){
+ // Grab the next chunk of src string and add it with the
+ // replacement, to the result
+ res += str.substring(pos, nextIndex) + new_;
+ // Increment our pointer in the src string
+ pos = nextIndex + old.length;
+ count++;
+ // See if there are any more replacements to be made
+ nextIndex = str.indexOf(old, pos);
+ }
+
+ // We've either reached the end, or done the max # of
+ // replacements, tack on any remaining string
+ if(pos < str.length) {
+ res += str.substring(pos);
+ }
+
+ return r.copySafeness(originalStr, res);
+ },
+
+ reverse: function(val) {
+ var arr;
+ if(lib.isString(val)) {
+ arr = filters.list(val);
+ }
+ else {
+ // Copy it
+ arr = lib.map(val, function(v) { return v; });
+ }
+
+ arr.reverse();
+
+ if(lib.isString(val)) {
+ return r.copySafeness(val, arr.join(''));
+ }
+ return arr;
+ },
+
+ round: function(val, precision, method) {
+ precision = precision || 0;
+ var factor = Math.pow(10, precision);
+ var rounder;
+
+ if(method === 'ceil') {
+ rounder = Math.ceil;
+ }
+ else if(method === 'floor') {
+ rounder = Math.floor;
+ }
+ else {
+ rounder = Math.round;
+ }
+
+ return rounder(val * factor) / factor;
+ },
+
+ slice: function(arr, slices, fillWith) {
+ var sliceLength = Math.floor(arr.length / slices);
+ var extra = arr.length % slices;
+ var offset = 0;
+ var res = [];
+
+ for(var i=0; i= extra) {
+ slice.push(fillWith);
+ }
+ res.push(slice);
+ }
+
+ return res;
+ },
+
+ sort: r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], function(arr, reverse, caseSens, attr) {
+ // Copy it
+ arr = lib.map(arr, function(v) { return v; });
+
+ arr.sort(function(a, b) {
+ var x, y;
+
+ if(attr) {
+ x = a[attr];
+ y = b[attr];
+ }
+ else {
+ x = a;
+ y = b;
+ }
+
+ if(!caseSens && lib.isString(x) && lib.isString(y)) {
+ x = x.toLowerCase();
+ y = y.toLowerCase();
+ }
+
+ if(x < y) {
+ return reverse ? 1 : -1;
+ }
+ else if(x > y) {
+ return reverse ? -1: 1;
+ }
+ else {
+ return 0;
+ }
+ });
+
+ return arr;
+ }),
+
+ string: function(obj) {
+ return r.copySafeness(obj, obj);
+ },
+
+ striptags: function(input, preserve_linebreaks) {
+ input = normalize(input, '');
+ preserve_linebreaks = preserve_linebreaks || false;
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi;
+ var trimmedInput = filters.trim(input.replace(tags, ''));
+ var res = '';
+ if (preserve_linebreaks) {
+ res = trimmedInput
+ .replace(/^ +| +$/gm, '') // remove leading and trailing spaces
+ .replace(/ +/g, ' ') // squash adjacent spaces
+ .replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF)
+ .replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks
+ } else {
+ res = trimmedInput.replace(/\s+/gi, ' ');
+ }
+ return r.copySafeness(input, res);
+ },
+
+ title: function(str) {
+ str = normalize(str, '');
+ var words = str.split(' ');
+ for(var i = 0; i < words.length; i++) {
+ words[i] = filters.capitalize(words[i]);
+ }
+ return r.copySafeness(str, words.join(' '));
+ },
+
+ trim: function(str) {
+ return r.copySafeness(str, str.replace(/^\s*|\s*$/g, ''));
+ },
+
+ truncate: function(input, length, killwords, end) {
+ var orig = input;
+ input = normalize(input, '');
+ length = length || 255;
+
+ if (input.length <= length)
+ return input;
+
+ if (killwords) {
+ input = input.substring(0, length);
+ } else {
+ var idx = input.lastIndexOf(' ', length);
+ if(idx === -1) {
+ idx = length;
+ }
+
+ input = input.substring(0, idx);
+ }
+
+ input += (end !== undefined && end !== null) ? end : '...';
+ return r.copySafeness(orig, input);
+ },
+
+ upper: function(str) {
+ str = normalize(str, '');
+ return str.toUpperCase();
+ },
+
+ urlencode: function(obj) {
+ var enc = encodeURIComponent;
+ if (lib.isString(obj)) {
+ return enc(obj);
+ } else {
+ var parts;
+ if (lib.isArray(obj)) {
+ parts = obj.map(function(item) {
+ return enc(item[0]) + '=' + enc(item[1]);
+ });
+ } else {
+ parts = [];
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ parts.push(enc(k) + '=' + enc(obj[k]));
+ }
+ }
+ }
+ return parts.join('&');
+ }
+ },
+
+ urlize: function(str, length, nofollow) {
+ if (isNaN(length)) length = Infinity;
+
+ var noFollowAttr = (nofollow === true ? ' rel="nofollow"' : '');
+
+ // For the jinja regexp, see
+ // https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23
+ var puncRE = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/;
+ // from http://blog.gerv.net/2011/05/html5_email_address_regexp/
+ var emailRE = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i;
+ var httpHttpsRE = /^https?:\/\/.*$/;
+ var wwwRE = /^www\./;
+ var tldRE = /\.(?:org|net|com)(?:\:|\/|$)/;
+
+ var words = str.split(/\s+/).filter(function(word) {
+ // If the word has no length, bail. This can happen for str with
+ // trailing whitespace.
+ return word && word.length;
+ }).map(function(word) {
+ var matches = word.match(puncRE);
+ var possibleUrl = matches && matches[1] || word;
+
+ // url that starts with http or https
+ if (httpHttpsRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ // url that starts with www.
+ if (wwwRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ // an email address of the form username@domain.tld
+ if (emailRE.test(possibleUrl))
+ return '' + possibleUrl + '';
+
+ // url that ends in .com, .org or .net that is not an email address
+ if (tldRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ return word;
+
+ });
+
+ return words.join(' ');
+ },
+
+ wordcount: function(str) {
+ str = normalize(str, '');
+ var words = (str) ? str.match(/\w+/g) : null;
+ return (words) ? words.length : null;
+ },
+
+ 'float': function(val, def) {
+ var res = parseFloat(val);
+ return isNaN(res) ? def : res;
+ },
+
+ 'int': function(val, def) {
+ var res = parseInt(val, 10);
+ return isNaN(res) ? def : res;
+ }
+ };
+
+ // Aliases
+ filters.d = filters['default'];
+ filters.e = filters.escape;
+
+ module.exports = filters;
+
+
+/***/ },
+/* 8 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var Obj = __webpack_require__(6);
+
+ // Frames keep track of scoping both at compile-time and run-time so
+ // we know how to access variables. Block tags can introduce special
+ // variables, for example.
+ var Frame = Obj.extend({
+ init: function(parent) {
+ this.variables = {};
+ this.parent = parent;
+ this.topLevel = false;
+ },
+
+ set: function(name, val, resolveUp) {
+ // Allow variables with dots by automatically creating the
+ // nested structure
+ var parts = name.split('.');
+ var obj = this.variables;
+ var frame = this;
+
+ if(resolveUp) {
+ if((frame = this.resolve(parts[0]))) {
+ frame.set(name, val);
+ return;
+ }
+ frame = this;
+ }
+
+ for(var i=0; i argNames.length) {
+ args = Array.prototype.slice.call(arguments, 0, argNames.length);
+
+ // Positional arguments that should be passed in as
+ // keyword arguments (essentially default values)
+ var vals = Array.prototype.slice.call(arguments, args.length, argCount);
+ for(i = 0; i < vals.length; i++) {
+ if(i < kwargNames.length) {
+ kwargs[kwargNames[i]] = vals[i];
+ }
+ }
+
+ args.push(kwargs);
+ }
+ else if(argCount < argNames.length) {
+ args = Array.prototype.slice.call(arguments, 0, argCount);
+
+ for(i = argCount; i < argNames.length; i++) {
+ var arg = argNames[i];
+
+ // Keyword arguments that should be passed as
+ // positional arguments, i.e. the caller explicitly
+ // used the name of a positional arg
+ args.push(kwargs[arg]);
+ delete kwargs[arg];
+ }
+
+ args.push(kwargs);
+ }
+ else {
+ args = arguments;
+ }
+
+ return func.apply(this, args);
+ };
+ }
+
+ function makeKeywordArgs(obj) {
+ obj.__keywords = true;
+ return obj;
+ }
+
+ function getKeywordArgs(args) {
+ var len = args.length;
+ if(len) {
+ var lastArg = args[len - 1];
+ if(lastArg && lastArg.hasOwnProperty('__keywords')) {
+ return lastArg;
+ }
+ }
+ return {};
+ }
+
+ function numArgs(args) {
+ var len = args.length;
+ if(len === 0) {
+ return 0;
+ }
+
+ var lastArg = args[len - 1];
+ if(lastArg && lastArg.hasOwnProperty('__keywords')) {
+ return len - 1;
+ }
+ else {
+ return len;
+ }
+ }
+
+ // A SafeString object indicates that the string should not be
+ // autoescaped. This happens magically because autoescaping only
+ // occurs on primitive string objects.
+ function SafeString(val) {
+ if(typeof val !== 'string') {
+ return val;
+ }
+
+ this.val = val;
+ this.length = val.length;
+ }
+
+ SafeString.prototype = Object.create(String.prototype, {
+ length: { writable: true, configurable: true, value: 0 }
+ });
+ SafeString.prototype.valueOf = function() {
+ return this.val;
+ };
+ SafeString.prototype.toString = function() {
+ return this.val;
+ };
+
+ function copySafeness(dest, target) {
+ if(dest instanceof SafeString) {
+ return new SafeString(target);
+ }
+ return target.toString();
+ }
+
+ function markSafe(val) {
+ var type = typeof val;
+
+ if(type === 'string') {
+ return new SafeString(val);
+ }
+ else if(type !== 'function') {
+ return val;
+ }
+ else {
+ return function() {
+ var ret = val.apply(this, arguments);
+
+ if(typeof ret === 'string') {
+ return new SafeString(ret);
+ }
+
+ return ret;
+ };
+ }
+ }
+
+ function suppressValue(val, autoescape) {
+ val = (val !== undefined && val !== null) ? val : '';
+
+ if(autoescape && typeof val === 'string') {
+ val = lib.escape(val);
+ }
+
+ return val;
+ }
+
+ function ensureDefined(val, lineno, colno) {
+ if(val === null || val === undefined) {
+ throw new lib.TemplateError(
+ 'attempted to output null or undefined value',
+ lineno + 1,
+ colno + 1
+ );
+ }
+ return val;
+ }
+
+ function memberLookup(obj, val) {
+ obj = obj || {};
+
+ if(typeof obj[val] === 'function') {
+ return function() {
+ return obj[val].apply(obj, arguments);
+ };
+ }
+
+ return obj[val];
+ }
+
+ function callWrap(obj, name, context, args) {
+ if(!obj) {
+ throw new Error('Unable to call `' + name + '`, which is undefined or falsey');
+ }
+ else if(typeof obj !== 'function') {
+ throw new Error('Unable to call `' + name + '`, which is not a function');
+ }
+
+ // jshint validthis: true
+ return obj.apply(context, args);
+ }
+
+ function contextOrFrameLookup(context, frame, name) {
+ var val = frame.lookup(name);
+ return (val !== undefined && val !== null) ?
+ val :
+ context.lookup(name);
+ }
+
+ function handleError(error, lineno, colno) {
+ if(error.lineno) {
+ return error;
+ }
+ else {
+ return new lib.TemplateError(error, lineno, colno);
+ }
+ }
+
+ function asyncEach(arr, dimen, iter, cb) {
+ if(lib.isArray(arr)) {
+ var len = arr.length;
+
+ lib.asyncIter(arr, function(item, i, next) {
+ switch(dimen) {
+ case 1: iter(item, i, len, next); break;
+ case 2: iter(item[0], item[1], i, len, next); break;
+ case 3: iter(item[0], item[1], item[2], i, len, next); break;
+ default:
+ item.push(i, next);
+ iter.apply(this, item);
+ }
+ }, cb);
+ }
+ else {
+ lib.asyncFor(arr, function(key, val, i, len, next) {
+ iter(key, val, i, len, next);
+ }, cb);
+ }
+ }
+
+ function asyncAll(arr, dimen, func, cb) {
+ var finished = 0;
+ var len, i;
+ var outputArr;
+
+ function done(i, output) {
+ finished++;
+ outputArr[i] = output;
+
+ if(finished === len) {
+ cb(null, outputArr.join(''));
+ }
+ }
+
+ if(lib.isArray(arr)) {
+ len = arr.length;
+ outputArr = new Array(len);
+
+ if(len === 0) {
+ cb(null, '');
+ }
+ else {
+ for(i = 0; i < arr.length; i++) {
+ var item = arr[i];
+
+ switch(dimen) {
+ case 1: func(item, i, len, done); break;
+ case 2: func(item[0], item[1], i, len, done); break;
+ case 3: func(item[0], item[1], item[2], i, len, done); break;
+ default:
+ item.push(i, done);
+ // jshint validthis: true
+ func.apply(this, item);
+ }
+ }
+ }
+ }
+ else {
+ var keys = lib.keys(arr);
+ len = keys.length;
+ outputArr = new Array(len);
+
+ if(len === 0) {
+ cb(null, '');
+ }
+ else {
+ for(i = 0; i < keys.length; i++) {
+ var k = keys[i];
+ func(k, arr[k], i, len, done);
+ }
+ }
+ }
+ }
+
+ module.exports = {
+ Frame: Frame,
+ makeMacro: makeMacro,
+ makeKeywordArgs: makeKeywordArgs,
+ numArgs: numArgs,
+ suppressValue: suppressValue,
+ ensureDefined: ensureDefined,
+ memberLookup: memberLookup,
+ contextOrFrameLookup: contextOrFrameLookup,
+ callWrap: callWrap,
+ handleError: handleError,
+ isArray: lib.isArray,
+ keys: lib.keys,
+ SafeString: SafeString,
+ copySafeness: copySafeness,
+ markSafe: markSafe,
+ asyncEach: asyncEach,
+ asyncAll: asyncAll
+ };
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ function cycler(items) {
+ var index = -1;
+
+ return {
+ current: null,
+ reset: function() {
+ index = -1;
+ this.current = null;
+ },
+
+ next: function() {
+ index++;
+ if(index >= items.length) {
+ index = 0;
+ }
+
+ this.current = items[index];
+ return this.current;
+ },
+ };
+
+ }
+
+ function joiner(sep) {
+ sep = sep || ',';
+ var first = true;
+
+ return function() {
+ var val = first ? '' : sep;
+ first = false;
+ return val;
+ };
+ }
+
+ // Making this a function instead so it returns a new object
+ // each time it's called. That way, if something like an environment
+ // uses it, they will each have their own copy.
+ function globals() {
+ return {
+ range: function(start, stop, step) {
+ if(!stop) {
+ stop = start;
+ start = 0;
+ step = 1;
+ }
+ else if(!step) {
+ step = 1;
+ }
+
+ var arr = [];
+ var i;
+ if (step > 0) {
+ for (i=start; istop; i+=step) {
+ arr.push(i);
+ }
+ }
+ return arr;
+ },
+
+ // lipsum: function(n, html, min, max) {
+ // },
+
+ cycler: function() {
+ return cycler(Array.prototype.slice.call(arguments));
+ },
+
+ joiner: function(sep) {
+ return joiner(sep);
+ }
+ };
+ }
+
+ module.exports = globals;
+
+
+/***/ },
+/* 10 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Loader = __webpack_require__(11);
+
+ var PrecompiledLoader = Loader.extend({
+ init: function(compiledTemplates) {
+ this.precompiled = compiledTemplates || {};
+ },
+
+ getSource: function(name) {
+ if (this.precompiled[name]) {
+ return {
+ src: { type: 'code',
+ obj: this.precompiled[name] },
+ path: name
+ };
+ }
+ return null;
+ }
+ });
+
+ module.exports = PrecompiledLoader;
+
+
+/***/ },
+/* 11 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var Obj = __webpack_require__(6);
+ var lib = __webpack_require__(1);
+
+ var Loader = Obj.extend({
+ on: function(name, func) {
+ this.listeners = this.listeners || {};
+ this.listeners[name] = this.listeners[name] || [];
+ this.listeners[name].push(func);
+ },
+
+ emit: function(name /*, arg1, arg2, ...*/) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if(this.listeners && this.listeners[name]) {
+ lib.each(this.listeners[name], function(listener) {
+ listener.apply(null, args);
+ });
+ }
+ },
+
+ resolve: function(from, to) {
+ return path.resolve(path.dirname(from), to);
+ },
+
+ isRelative: function(filename) {
+ return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
+ }
+ });
+
+ module.exports = Loader;
+
+
+/***/ },
+/* 12 */
+/***/ function(module, exports) {
+
+ function installCompat() {
+ 'use strict';
+
+ // This must be called like `nunjucks.installCompat` so that `this`
+ // references the nunjucks instance
+ var runtime = this.runtime; // jshint ignore:line
+ var lib = this.lib; // jshint ignore:line
+
+ var orig_contextOrFrameLookup = runtime.contextOrFrameLookup;
+ runtime.contextOrFrameLookup = function(context, frame, key) {
+ var val = orig_contextOrFrameLookup.apply(this, arguments);
+ if (val === undefined) {
+ switch (key) {
+ case 'True':
+ return true;
+ case 'False':
+ return false;
+ case 'None':
+ return null;
+ }
+ }
+
+ return val;
+ };
+
+ var orig_memberLookup = runtime.memberLookup;
+ var ARRAY_MEMBERS = {
+ pop: function(index) {
+ if (index === undefined) {
+ return this.pop();
+ }
+ if (index >= this.length || index < 0) {
+ throw new Error('KeyError');
+ }
+ return this.splice(index, 1);
+ },
+ remove: function(element) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ return this.splice(i, 1);
+ }
+ }
+ throw new Error('ValueError');
+ },
+ count: function(element) {
+ var count = 0;
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ count++;
+ }
+ }
+ return count;
+ },
+ index: function(element) {
+ var i;
+ if ((i = this.indexOf(element)) === -1) {
+ throw new Error('ValueError');
+ }
+ return i;
+ },
+ find: function(element) {
+ return this.indexOf(element);
+ },
+ insert: function(index, elem) {
+ return this.splice(index, 0, elem);
+ }
+ };
+ var OBJECT_MEMBERS = {
+ items: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push([k, this[k]]);
+ }
+ return ret;
+ },
+ values: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(this[k]);
+ }
+ return ret;
+ },
+ keys: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(k);
+ }
+ return ret;
+ },
+ get: function(key, def) {
+ var output = this[key];
+ if (output === undefined) {
+ output = def;
+ }
+ return output;
+ },
+ has_key: function(key) {
+ return this.hasOwnProperty(key);
+ },
+ pop: function(key, def) {
+ var output = this[key];
+ if (output === undefined && def !== undefined) {
+ output = def;
+ } else if (output === undefined) {
+ throw new Error('KeyError');
+ } else {
+ delete this[key];
+ }
+ return output;
+ },
+ popitem: function() {
+ for (var k in this) {
+ // Return the first object pair.
+ var val = this[k];
+ delete this[k];
+ return [k, val];
+ }
+ throw new Error('KeyError');
+ },
+ setdefault: function(key, def) {
+ if (key in this) {
+ return this[key];
+ }
+ if (def === undefined) {
+ def = null;
+ }
+ return this[key] = def;
+ },
+ update: function(kwargs) {
+ for (var k in kwargs) {
+ this[k] = kwargs[k];
+ }
+ return null; // Always returns None
+ }
+ };
+ OBJECT_MEMBERS.iteritems = OBJECT_MEMBERS.items;
+ OBJECT_MEMBERS.itervalues = OBJECT_MEMBERS.values;
+ OBJECT_MEMBERS.iterkeys = OBJECT_MEMBERS.keys;
+ runtime.memberLookup = function(obj, val, autoescape) { // jshint ignore:line
+ obj = obj || {};
+
+ // If the object is an object, return any of the methods that Python would
+ // otherwise provide.
+ if (lib.isArray(obj) && ARRAY_MEMBERS.hasOwnProperty(val)) {
+ return function() {return ARRAY_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ if (lib.isObject(obj) && OBJECT_MEMBERS.hasOwnProperty(val)) {
+ return function() {return OBJECT_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ return orig_memberLookup.apply(this, arguments);
+ };
+ }
+
+ module.exports = installCompat;
+
+
+/***/ }
+/******/ ]);
\ No newline at end of file
diff --git a/certidude/static/js/nunjucks-slim.min.js b/certidude/static/js/nunjucks-slim.min.js
new file mode 100644
index 0000000..08bde32
--- /dev/null
+++ b/certidude/static/js/nunjucks-slim.min.js
@@ -0,0 +1,2 @@
+/*! Browser bundle of nunjucks 2.3.0 (slim, only works with precompiled templates) */
+var nunjucks=function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return t[n].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var r={};return e.m=t,e.c=r,e.p="",e(0)}([function(t,e,r){"use strict";var n=r(1),i=r(2),o=r(11),s=r(3),u=r(3);t.exports={},t.exports.Environment=i.Environment,t.exports.Template=i.Template,t.exports.Loader=o,t.exports.FileSystemLoader=s.FileSystemLoader,t.exports.PrecompiledLoader=s.PrecompiledLoader,t.exports.WebLoader=s.WebLoader,t.exports.compiler=r(3),t.exports.parser=r(3),t.exports.lexer=r(3),t.exports.runtime=r(8),t.exports.lib=n,t.exports.nodes=r(3),t.exports.installJinjaCompat=r(12);var a;t.exports.configure=function(t,e){e=e||{},n.isObject(t)&&(e=t,t=null);var r;return s.FileSystemLoader?r=new s.FileSystemLoader(t,{watch:e.watch,noCache:e.noCache}):s.WebLoader&&(r=new s.WebLoader(t,{useCache:e.web&&e.web.useCache,async:e.web&&e.web.async})),a=new i.Environment(r,e),e&&e.express&&a.express(e.express),a},t.exports.compile=function(e,r,n,i){return a||t.exports.configure(),new t.exports.Template(e,r,n,i)},t.exports.render=function(e,r,n){return a||t.exports.configure(),a.render(e,r,n)},t.exports.renderString=function(e,r,n){return a||t.exports.configure(),a.renderString(e,r,n)},u&&(t.exports.precompile=u.precompile,t.exports.precompileString=u.precompileString)},function(t,e){"use strict";var r=Array.prototype,n=Object.prototype,i={"&":"&",'"':""","'":"'","<":"<",">":">"},o=/[&"'<>]/g,s=function(t){return i[t]},e=t.exports={};e.prettifyError=function(t,r,n){if(n.Update||(n=new e.TemplateError(n)),n.Update(t),!r){var i=n;n=new Error(i.message),n.name=i.name}return n},e.TemplateError=function(t,e,r){var n=this;if(t instanceof Error){n=t,t=t.name+": "+t.message;try{n.name=""}catch(i){n=this}}else Error.captureStackTrace&&Error.captureStackTrace(n);return n.name="Template render error",n.message=t,n.lineno=e,n.colno=r,n.firstUpdate=!0,n.Update=function(t){var e="("+(t||"unknown path")+")";return this.firstUpdate&&(this.lineno&&this.colno?e+=" [Line "+this.lineno+", Column "+this.colno+"]":this.lineno&&(e+=" [Line "+this.lineno+"]")),e+="\n ",this.firstUpdate&&(e+=" "),this.message=e+(this.message||""),this.firstUpdate=!1,this},n},e.TemplateError.prototype=Error.prototype,e.escape=function(t){return t.replace(o,s)},e.isFunction=function(t){return"[object Function]"===n.toString.call(t)},e.isArray=Array.isArray||function(t){return"[object Array]"===n.toString.call(t)},e.isString=function(t){return"[object String]"===n.toString.call(t)},e.isObject=function(t){return"[object Object]"===n.toString.call(t)},e.groupBy=function(t,r){for(var n={},i=e.isFunction(r)?r:function(t){return t[r]},o=0;on;n++)r+=t;return r},e.each=function(t,e,n){if(null!=t)if(r.each&&t.each===r.each)t.forEach(e,n);else if(t.length===+t.length)for(var i=0,o=t.length;o>i;i++)e.call(n,t[i],i,t)},e.map=function(t,e){var n=[];if(null==t)return n;if(r.map&&t.map===r.map)return t.map(e);for(var i=0;iu?r(e,t[e],u,s,i):n()}var o=e.keys(t),s=o.length,u=-1;i()},e.indexOf=Array.prototype.indexOf?function(t,e,r){return Array.prototype.indexOf.call(t,e,r)}:function(t,e,r){var n=this.length>>>0;for(r=+r||0,Math.abs(r)===1/0&&(r=0),0>r&&(r+=n,0>r&&(r=0));n>r;r++)if(t[r]===e)return r;return-1},Array.prototype.map||(Array.prototype.map=function(){throw new Error("map is unimplemented for this js engine")}),e.keys=function(t){if(Object.prototype.keys)return t.keys();var e=[];for(var r in t)t.hasOwnProperty(r)&&e.push(r);return e}},function(t,e,r){"use strict";function n(t,e,r){s(function(){t(e,r)})}var i,o=r(3),s=r(4),u=r(1),a=r(6),c=r(3),l=r(7),f=r(3),p=r(8),h=r(9),v=p.Frame;f.PrecompiledLoader=r(10);var d=a.extend({init:function(t,e){e=this.opts=e||{},this.opts.dev=!!e.dev,this.opts.autoescape=null!=e.autoescape?e.autoescape:!0,this.opts.throwOnUndefined=!!e.throwOnUndefined,this.opts.trimBlocks=!!e.trimBlocks,this.opts.lstripBlocks=!!e.lstripBlocks,this.loaders=[],t?this.loaders=u.isArray(t)?t:[t]:f.FileSystemLoader?this.loaders=[new f.FileSystemLoader("views")]:f.WebLoader&&(this.loaders=[new f.WebLoader("/views")]),window.nunjucksPrecompiled&&this.loaders.unshift(new f.PrecompiledLoader(window.nunjucksPrecompiled)),this.initCache(),this.globals=h(),this.filters={},this.asyncFilters=[],this.extensions={},this.extensionsList=[];for(var r in l)this.addFilter(r,l[r])},initCache:function(){u.each(this.loaders,function(t){t.cache={},"function"==typeof t.on&&t.on("update",function(e){t.cache[e]=null})})},addExtension:function(t,e){return e._name=t,this.extensions[t]=e,this.extensionsList.push(e),this},removeExtension:function(t){var e=this.getExtension(t);e&&(this.extensionsList=u.without(this.extensionsList,e),delete this.extensions[t])},getExtension:function(t){return this.extensions[t]},hasExtension:function(t){return!!this.extensions[t]},addGlobal:function(t,e){return this.globals[t]=e,this},getGlobal:function(t){if(!this.globals[t])throw new Error("global not found: "+t);return this.globals[t]},addFilter:function(t,e,r){var n=e;return r&&this.asyncFilters.push(t),this.filters[t]=n,this},getFilter:function(t){if(!this.filters[t])throw new Error("filter not found: "+t);return this.filters[t]},resolveTemplate:function(t,e,r){var n=t.isRelative&&e?t.isRelative(r):!1;return n&&t.resolve?t.resolve(e,r):r},getTemplate:function(t,e,r,n,o){var s=this,a=null;if(t&&t.raw&&(t=t.raw),u.isFunction(r)&&(o=r,r=null,e=e||!1),u.isFunction(e)&&(o=e,e=!1),t instanceof i)a=t;else{if("string"!=typeof t)throw new Error("template names must be a string: "+t);for(var c=0;cl){for(var e=0,r=u.length-c;r>e;e++)u[e]=u[e+c];u.length-=c,c=0}}u.length=0,c=0,a=!1}function i(t){var e=1,r=new f(t),n=document.createTextNode("");return r.observe(n,{characterData:!0}),function(){e=-e,n.data=e}}function o(t){return function(){function e(){clearTimeout(r),clearInterval(n),t()}var r=setTimeout(e,0),n=setInterval(e,50)}}t.exports=r;var s,u=[],a=!1,c=0,l=1024,f=e.MutationObserver||e.WebKitMutationObserver;s="function"==typeof f?i(n):o(n),r.requestFlush=s,r.makeRequestCallFromTimer=o}).call(e,function(){return this}())},function(t,e){"use strict";function r(t,e,n){var i=function(){};i.prototype=t.prototype;var o=new i,s=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;n=n||{};for(var u in n){var a=n[u],c=o[u];"function"==typeof c&&"function"==typeof a&&s.test(a)?o[u]=function(t,e){return function(){var r=this.parent;this.parent=e;var n=t.apply(this,arguments);return this.parent=r,n}}(a,c):o[u]=a}o.typename=e;var l=function(){o.init&&o.init.apply(this,arguments)};return l.prototype=o,l.prototype.constructor=l,l.extend=function(t,e){return"object"==typeof t&&(e=t,t="anonymous"),r(l,t,e)},l}t.exports=r(Object,"Object",{})},function(t,e,r){"use strict";function n(t,e){return null===t||void 0===t||t===!1?e:t}var i=r(1),o=r(8),s={abs:function(t){return Math.abs(t)},batch:function(t,e,r){var n,i=[],o=[];for(n=0;nn;n++)o.push(r);i.push(o)}return i},capitalize:function(t){t=n(t,"");var e=t.toLowerCase();return o.copySafeness(t,e.charAt(0).toUpperCase()+e.slice(1))},center:function(t,e){if(t=n(t,""),e=e||80,t.length>=e)return t;var r=e-t.length,s=i.repeat(" ",r/2-r%2),u=i.repeat(" ",r/2);return o.copySafeness(t,s+t+u)},"default":function(t,e,r){return r?t?t:e:void 0!==t?t:e},dictsort:function(t,e,r){if(!i.isObject(t))throw new i.TemplateError("dictsort filter: val must be an object");var n=[];for(var o in t)n.push([o,t[o]]);var s;if(void 0===r||"key"===r)s=0;else{if("value"!==r)throw new i.TemplateError("dictsort filter: You can only sort by either key or value");s=1}return n.sort(function(t,r){var n=t[s],o=r[s];return e||(i.isString(n)&&(n=n.toUpperCase()),i.isString(o)&&(o=o.toUpperCase())),n>o?1:n===o?0:-1}),n},dump:function(t){return JSON.stringify(t)},escape:function(t){return"string"==typeof t||t instanceof o.SafeString?i.escape(t):t},safe:function(t){return o.markSafe(t)},first:function(t){return t[0]},groupby:function(t,e){return i.groupBy(t,e)},indent:function(t,e,r){if(t=n(t,""),""===t)return"";e=e||4;for(var s="",u=t.split("\n"),a=i.repeat(" ",e),c=0;c-1&&(-1===n||n>c);)s+=t.substring(a,u)+r,a=u+e.length,c++,u=t.indexOf(e,a);return au;u++){var a=o+u*n;i>u&&o++;var c=o+(u+1)*n,l=t.slice(a,c);r&&u>=i&&l.push(r),s.push(l)}return s},sort:o.makeMacro(["value","reverse","case_sensitive","attribute"],[],function(t,e,r,n){return t=i.map(t,function(t){return t}),t.sort(function(t,o){var s,u;return n?(s=t[n],u=o[n]):(s=t,u=o),!r&&i.isString(s)&&i.isString(u)&&(s=s.toLowerCase(),u=u.toLowerCase()),u>s?e?1:-1:s>u?e?-1:1:0}),t}),string:function(t){return o.copySafeness(t,t)},striptags:function(t,e){t=n(t,""),e=e||!1;var r=/<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi,i=s.trim(t.replace(r,"")),u="";return u=e?i.replace(/^ +| +$/gm,"").replace(/ +/g," ").replace(/(\r\n)/g,"\n").replace(/\n\n\n+/g,"\n\n"):i.replace(/\s+/gi," "),o.copySafeness(t,u)},title:function(t){t=n(t,"");for(var e=t.split(" "),r=0;r"+c.substr(0,e)+"":u.test(c)?'"+c.substr(0,e)+"":o.test(c)?''+c+"":a.test(c)?'"+c.substr(0,e)+"":t});return c.join(" ")},wordcount:function(t){t=n(t,"");var e=t?t.match(/\w+/g):null;return e?e.length:null},"float":function(t,e){var r=parseFloat(t);return isNaN(r)?e:r},"int":function(t,e){var r=parseInt(t,10);return isNaN(r)?e:r}};s.d=s["default"],s.e=s.escape,t.exports=s},function(t,e,r){"use strict";function n(t,e,r){return function(){var n,i,u=s(arguments),a=o(arguments);if(u>t.length){n=Array.prototype.slice.call(arguments,0,t.length);var c=Array.prototype.slice.call(arguments,n.length,u);for(i=0;i=t.length&&(e=0),this.current=t[e],this.current}}}function n(t){t=t||",";var e=!0;return function(){var r=e?"":t;return e=!1,r}}function i(){return{range:function(t,e,r){e?r||(r=1):(e=t,t=0,r=1);var n,i=[];if(r>0)for(n=t;e>n;n+=r)i.push(n);else for(n=t;n>e;n+=r)i.push(n);return i},cycler:function(){return r(Array.prototype.slice.call(arguments))},joiner:function(t){return n(t)}}}t.exports=i},function(t,e,r){"use strict";var n=r(11),i=n.extend({init:function(t){this.precompiled=t||{}},getSource:function(t){return this.precompiled[t]?{src:{type:"code",obj:this.precompiled[t]},path:t}:null}});t.exports=i},function(t,e,r){"use strict";var n=r(3),i=r(6),o=r(1),s=i.extend({on:function(t,e){this.listeners=this.listeners||{},this.listeners[t]=this.listeners[t]||[],this.listeners[t].push(e)},emit:function(t){var e=Array.prototype.slice.call(arguments,1);this.listeners&&this.listeners[t]&&o.each(this.listeners[t],function(t){t.apply(null,e)})},resolve:function(t,e){return n.resolve(n.dirname(t),e)},isRelative:function(t){return 0===t.indexOf("./")||0===t.indexOf("../")}});t.exports=s},function(t,e){function r(){"use strict";var t=this.runtime,e=this.lib,r=t.contextOrFrameLookup;t.contextOrFrameLookup=function(t,e,n){var i=r.apply(this,arguments);if(void 0===i)switch(n){case"True":return!0;case"False":return!1;case"None":return null}return i};var n=t.memberLookup,i={pop:function(t){if(void 0===t)return this.pop();if(t>=this.length||0>t)throw new Error("KeyError");return this.splice(t,1)},remove:function(t){for(var e=0;e': '>'
+ };
+
+ var escapeRegex = /[&"'<>]/g;
+
+ var lookupEscape = function(ch) {
+ return escapeMap[ch];
+ };
+
+ var exports = module.exports = {};
+
+ exports.prettifyError = function(path, withInternals, err) {
+ // jshint -W022
+ // http://jslinterrors.com/do-not-assign-to-the-exception-parameter
+ if (!err.Update) {
+ // not one of ours, cast it
+ err = new exports.TemplateError(err);
+ }
+ err.Update(path);
+
+ // Unless they marked the dev flag, show them a trace from here
+ if (!withInternals) {
+ var old = err;
+ err = new Error(old.message);
+ err.name = old.name;
+ }
+
+ return err;
+ };
+
+ exports.TemplateError = function(message, lineno, colno) {
+ var err = this;
+
+ if (message instanceof Error) { // for casting regular js errors
+ err = message;
+ message = message.name + ': ' + message.message;
+
+ try {
+ if(err.name = '') {}
+ }
+ catch(e) {
+ // If we can't set the name of the error object in this
+ // environment, don't use it
+ err = this;
+ }
+ } else {
+ if(Error.captureStackTrace) {
+ Error.captureStackTrace(err);
+ }
+ }
+
+ err.name = 'Template render error';
+ err.message = message;
+ err.lineno = lineno;
+ err.colno = colno;
+ err.firstUpdate = true;
+
+ err.Update = function(path) {
+ var message = '(' + (path || 'unknown path') + ')';
+
+ // only show lineno + colno next to path of template
+ // where error occurred
+ if (this.firstUpdate) {
+ if(this.lineno && this.colno) {
+ message += ' [Line ' + this.lineno + ', Column ' + this.colno + ']';
+ }
+ else if(this.lineno) {
+ message += ' [Line ' + this.lineno + ']';
+ }
+ }
+
+ message += '\n ';
+ if (this.firstUpdate) {
+ message += ' ';
+ }
+
+ this.message = message + (this.message || '');
+ this.firstUpdate = false;
+ return this;
+ };
+
+ return err;
+ };
+
+ exports.TemplateError.prototype = Error.prototype;
+
+ exports.escape = function(val) {
+ return val.replace(escapeRegex, lookupEscape);
+ };
+
+ exports.isFunction = function(obj) {
+ return ObjProto.toString.call(obj) === '[object Function]';
+ };
+
+ exports.isArray = Array.isArray || function(obj) {
+ return ObjProto.toString.call(obj) === '[object Array]';
+ };
+
+ exports.isString = function(obj) {
+ return ObjProto.toString.call(obj) === '[object String]';
+ };
+
+ exports.isObject = function(obj) {
+ return ObjProto.toString.call(obj) === '[object Object]';
+ };
+
+ exports.groupBy = function(obj, val) {
+ var result = {};
+ var iterator = exports.isFunction(val) ? val : function(obj) { return obj[val]; };
+ for(var i=0; i>> 0; // Hack to convert object.length to a UInt32
+
+ fromIndex = +fromIndex || 0;
+
+ if(Math.abs(fromIndex) === Infinity) {
+ fromIndex = 0;
+ }
+
+ if(fromIndex < 0) {
+ fromIndex += length;
+ if (fromIndex < 0) {
+ fromIndex = 0;
+ }
+ }
+
+ for(;fromIndex < length; fromIndex++) {
+ if (arr[fromIndex] === searchElement) {
+ return fromIndex;
+ }
+ }
+
+ return -1;
+ };
+
+ if(!Array.prototype.map) {
+ Array.prototype.map = function() {
+ throw new Error('map is unimplemented for this js engine');
+ };
+ }
+
+ exports.keys = function(obj) {
+ if(Object.prototype.keys) {
+ return obj.keys();
+ }
+ else {
+ var keys = [];
+ for(var k in obj) {
+ if(obj.hasOwnProperty(k)) {
+ keys.push(k);
+ }
+ }
+ return keys;
+ }
+ };
+
+
+/***/ },
+/* 2 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var asap = __webpack_require__(4);
+ var lib = __webpack_require__(1);
+ var Obj = __webpack_require__(6);
+ var compiler = __webpack_require__(7);
+ var builtin_filters = __webpack_require__(13);
+ var builtin_loaders = __webpack_require__(14);
+ var runtime = __webpack_require__(12);
+ var globals = __webpack_require__(17);
+ var Frame = runtime.Frame;
+ var Template;
+
+ // Unconditionally load in this loader, even if no other ones are
+ // included (possible in the slim browser build)
+ builtin_loaders.PrecompiledLoader = __webpack_require__(16);
+
+ // If the user is using the async API, *always* call it
+ // asynchronously even if the template was synchronous.
+ function callbackAsap(cb, err, res) {
+ asap(function() { cb(err, res); });
+ }
+
+ var Environment = Obj.extend({
+ init: function(loaders, opts) {
+ // The dev flag determines the trace that'll be shown on errors.
+ // If set to true, returns the full trace from the error point,
+ // otherwise will return trace starting from Template.render
+ // (the full trace from within nunjucks may confuse developers using
+ // the library)
+ // defaults to false
+ opts = this.opts = opts || {};
+ this.opts.dev = !!opts.dev;
+
+ // The autoescape flag sets global autoescaping. If true,
+ // every string variable will be escaped by default.
+ // If false, strings can be manually escaped using the `escape` filter.
+ // defaults to true
+ this.opts.autoescape = opts.autoescape != null ? opts.autoescape : true;
+
+ // If true, this will make the system throw errors if trying
+ // to output a null or undefined value
+ this.opts.throwOnUndefined = !!opts.throwOnUndefined;
+ this.opts.trimBlocks = !!opts.trimBlocks;
+ this.opts.lstripBlocks = !!opts.lstripBlocks;
+
+ this.loaders = [];
+
+ if(!loaders) {
+ // The filesystem loader is only available server-side
+ if(builtin_loaders.FileSystemLoader) {
+ this.loaders = [new builtin_loaders.FileSystemLoader('views')];
+ }
+ else if(builtin_loaders.WebLoader) {
+ this.loaders = [new builtin_loaders.WebLoader('/views')];
+ }
+ }
+ else {
+ this.loaders = lib.isArray(loaders) ? loaders : [loaders];
+ }
+
+ // It's easy to use precompiled templates: just include them
+ // before you configure nunjucks and this will automatically
+ // pick it up and use it
+ if((true) && window.nunjucksPrecompiled) {
+ this.loaders.unshift(
+ new builtin_loaders.PrecompiledLoader(window.nunjucksPrecompiled)
+ );
+ }
+
+ this.initCache();
+
+ this.globals = globals();
+ this.filters = {};
+ this.asyncFilters = [];
+ this.extensions = {};
+ this.extensionsList = [];
+
+ for(var name in builtin_filters) {
+ this.addFilter(name, builtin_filters[name]);
+ }
+ },
+
+ initCache: function() {
+ // Caching and cache busting
+ lib.each(this.loaders, function(loader) {
+ loader.cache = {};
+
+ if(typeof loader.on === 'function') {
+ loader.on('update', function(template) {
+ loader.cache[template] = null;
+ });
+ }
+ });
+ },
+
+ addExtension: function(name, extension) {
+ extension._name = name;
+ this.extensions[name] = extension;
+ this.extensionsList.push(extension);
+ return this;
+ },
+
+ removeExtension: function(name) {
+ var extension = this.getExtension(name);
+ if (!extension) return;
+
+ this.extensionsList = lib.without(this.extensionsList, extension);
+ delete this.extensions[name];
+ },
+
+ getExtension: function(name) {
+ return this.extensions[name];
+ },
+
+ hasExtension: function(name) {
+ return !!this.extensions[name];
+ },
+
+ addGlobal: function(name, value) {
+ this.globals[name] = value;
+ return this;
+ },
+
+ getGlobal: function(name) {
+ if(!this.globals[name]) {
+ throw new Error('global not found: ' + name);
+ }
+ return this.globals[name];
+ },
+
+ addFilter: function(name, func, async) {
+ var wrapped = func;
+
+ if(async) {
+ this.asyncFilters.push(name);
+ }
+ this.filters[name] = wrapped;
+ return this;
+ },
+
+ getFilter: function(name) {
+ if(!this.filters[name]) {
+ throw new Error('filter not found: ' + name);
+ }
+ return this.filters[name];
+ },
+
+ resolveTemplate: function(loader, parentName, filename) {
+ var isRelative = (loader.isRelative && parentName)? loader.isRelative(filename) : false;
+ return (isRelative && loader.resolve)? loader.resolve(parentName, filename) : filename;
+ },
+
+ getTemplate: function(name, eagerCompile, parentName, ignoreMissing, cb) {
+ var that = this;
+ var tmpl = null;
+ if(name && name.raw) {
+ // this fixes autoescape for templates referenced in symbols
+ name = name.raw;
+ }
+
+ if(lib.isFunction(parentName)) {
+ cb = parentName;
+ parentName = null;
+ eagerCompile = eagerCompile || false;
+ }
+
+ if(lib.isFunction(eagerCompile)) {
+ cb = eagerCompile;
+ eagerCompile = false;
+ }
+
+ if (name instanceof Template) {
+ tmpl = name;
+ }
+ else if(typeof name !== 'string') {
+ throw new Error('template names must be a string: ' + name);
+ }
+ else {
+ for (var i = 0; i < this.loaders.length; i++) {
+ var _name = this.resolveTemplate(this.loaders[i], parentName, name);
+ tmpl = this.loaders[i].cache[_name];
+ if (tmpl) break;
+ }
+ }
+
+ if(tmpl) {
+ if(eagerCompile) {
+ tmpl.compile();
+ }
+
+ if(cb) {
+ cb(null, tmpl);
+ }
+ else {
+ return tmpl;
+ }
+ } else {
+ var syncResult;
+ var _this = this;
+
+ var createTemplate = function(err, info) {
+ if(!info && !err) {
+ if(!ignoreMissing) {
+ err = new Error('template not found: ' + name);
+ }
+ }
+
+ if (err) {
+ if(cb) {
+ cb(err);
+ }
+ else {
+ throw err;
+ }
+ }
+ else {
+ var tmpl;
+ if(info) {
+ tmpl = new Template(info.src, _this,
+ info.path, eagerCompile);
+
+ if(!info.noCache) {
+ info.loader.cache[name] = tmpl;
+ }
+ }
+ else {
+ tmpl = new Template('', _this,
+ '', eagerCompile);
+ }
+
+ if(cb) {
+ cb(null, tmpl);
+ }
+ else {
+ syncResult = tmpl;
+ }
+ }
+ };
+
+ lib.asyncIter(this.loaders, function(loader, i, next, done) {
+ function handle(err, src) {
+ if(err) {
+ done(err);
+ }
+ else if(src) {
+ src.loader = loader;
+ done(null, src);
+ }
+ else {
+ next();
+ }
+ }
+
+ // Resolve name relative to parentName
+ name = that.resolveTemplate(loader, parentName, name);
+
+ if(loader.async) {
+ loader.getSource(name, handle);
+ }
+ else {
+ handle(null, loader.getSource(name));
+ }
+ }, createTemplate);
+
+ return syncResult;
+ }
+ },
+
+ express: function(app) {
+ var env = this;
+
+ function NunjucksView(name, opts) {
+ this.name = name;
+ this.path = name;
+ this.defaultEngine = opts.defaultEngine;
+ this.ext = path.extname(name);
+ if (!this.ext && !this.defaultEngine) throw new Error('No default engine was specified and no extension was provided.');
+ if (!this.ext) this.name += (this.ext = ('.' !== this.defaultEngine[0] ? '.' : '') + this.defaultEngine);
+ }
+
+ NunjucksView.prototype.render = function(opts, cb) {
+ env.render(this.name, opts, cb);
+ };
+
+ app.set('view', NunjucksView);
+ return this;
+ },
+
+ render: function(name, ctx, cb) {
+ if(lib.isFunction(ctx)) {
+ cb = ctx;
+ ctx = null;
+ }
+
+ // We support a synchronous API to make it easier to migrate
+ // existing code to async. This works because if you don't do
+ // anything async work, the whole thing is actually run
+ // synchronously.
+ var syncResult = null;
+
+ this.getTemplate(name, function(err, tmpl) {
+ if(err && cb) {
+ callbackAsap(cb, err);
+ }
+ else if(err) {
+ throw err;
+ }
+ else {
+ syncResult = tmpl.render(ctx, cb);
+ }
+ });
+
+ return syncResult;
+ },
+
+ renderString: function(src, ctx, opts, cb) {
+ if(lib.isFunction(opts)) {
+ cb = opts;
+ opts = {};
+ }
+ opts = opts || {};
+
+ var tmpl = new Template(src, this, opts.path);
+ return tmpl.render(ctx, cb);
+ }
+ });
+
+ var Context = Obj.extend({
+ init: function(ctx, blocks, env) {
+ // Has to be tied to an environment so we can tap into its globals.
+ this.env = env || new Environment();
+
+ // Make a duplicate of ctx
+ this.ctx = {};
+ for(var k in ctx) {
+ if(ctx.hasOwnProperty(k)) {
+ this.ctx[k] = ctx[k];
+ }
+ }
+
+ this.blocks = {};
+ this.exported = [];
+
+ for(var name in blocks) {
+ this.addBlock(name, blocks[name]);
+ }
+ },
+
+ lookup: function(name) {
+ // This is one of the most called functions, so optimize for
+ // the typical case where the name isn't in the globals
+ if(name in this.env.globals && !(name in this.ctx)) {
+ return this.env.globals[name];
+ }
+ else {
+ return this.ctx[name];
+ }
+ },
+
+ setVariable: function(name, val) {
+ this.ctx[name] = val;
+ },
+
+ getVariables: function() {
+ return this.ctx;
+ },
+
+ addBlock: function(name, block) {
+ this.blocks[name] = this.blocks[name] || [];
+ this.blocks[name].push(block);
+ return this;
+ },
+
+ getBlock: function(name) {
+ if(!this.blocks[name]) {
+ throw new Error('unknown block "' + name + '"');
+ }
+
+ return this.blocks[name][0];
+ },
+
+ getSuper: function(env, name, block, frame, runtime, cb) {
+ var idx = lib.indexOf(this.blocks[name] || [], block);
+ var blk = this.blocks[name][idx + 1];
+ var context = this;
+
+ if(idx === -1 || !blk) {
+ throw new Error('no super block available for "' + name + '"');
+ }
+
+ blk(env, context, frame, runtime, cb);
+ },
+
+ addExport: function(name) {
+ this.exported.push(name);
+ },
+
+ getExported: function() {
+ var exported = {};
+ for(var i=0; i capacity) {
+ // Manually shift all values starting at the index back to the
+ // beginning of the queue.
+ for (var scan = 0, newLength = queue.length - index; scan < newLength; scan++) {
+ queue[scan] = queue[scan + index];
+ }
+ queue.length -= index;
+ index = 0;
+ }
+ }
+ queue.length = 0;
+ index = 0;
+ flushing = false;
+ }
+
+ // `requestFlush` is implemented using a strategy based on data collected from
+ // every available SauceLabs Selenium web driver worker at time of writing.
+ // https://docs.google.com/spreadsheets/d/1mG-5UYGup5qxGdEMWkhP6BWCz053NUb2E1QoUTU16uA/edit#gid=783724593
+
+ // Safari 6 and 6.1 for desktop, iPad, and iPhone are the only browsers that
+ // have WebKitMutationObserver but not un-prefixed MutationObserver.
+ // Must use `global` instead of `window` to work in both frames and web
+ // workers. `global` is a provision of Browserify, Mr, Mrs, or Mop.
+ var BrowserMutationObserver = global.MutationObserver || global.WebKitMutationObserver;
+
+ // MutationObservers are desirable because they have high priority and work
+ // reliably everywhere they are implemented.
+ // They are implemented in all modern browsers.
+ //
+ // - Android 4-4.3
+ // - Chrome 26-34
+ // - Firefox 14-29
+ // - Internet Explorer 11
+ // - iPad Safari 6-7.1
+ // - iPhone Safari 7-7.1
+ // - Safari 6-7
+ if (typeof BrowserMutationObserver === "function") {
+ requestFlush = makeRequestCallFromMutationObserver(flush);
+
+ // MessageChannels are desirable because they give direct access to the HTML
+ // task queue, are implemented in Internet Explorer 10, Safari 5.0-1, and Opera
+ // 11-12, and in web workers in many engines.
+ // Although message channels yield to any queued rendering and IO tasks, they
+ // would be better than imposing the 4ms delay of timers.
+ // However, they do not work reliably in Internet Explorer or Safari.
+
+ // Internet Explorer 10 is the only browser that has setImmediate but does
+ // not have MutationObservers.
+ // Although setImmediate yields to the browser's renderer, it would be
+ // preferrable to falling back to setTimeout since it does not have
+ // the minimum 4ms penalty.
+ // Unfortunately there appears to be a bug in Internet Explorer 10 Mobile (and
+ // Desktop to a lesser extent) that renders both setImmediate and
+ // MessageChannel useless for the purposes of ASAP.
+ // https://github.com/kriskowal/q/issues/396
+
+ // Timers are implemented universally.
+ // We fall back to timers in workers in most engines, and in foreground
+ // contexts in the following browsers.
+ // However, note that even this simple case requires nuances to operate in a
+ // broad spectrum of browsers.
+ //
+ // - Firefox 3-13
+ // - Internet Explorer 6-9
+ // - iPad Safari 4.3
+ // - Lynx 2.8.7
+ } else {
+ requestFlush = makeRequestCallFromTimer(flush);
+ }
+
+ // `requestFlush` requests that the high priority event queue be flushed as
+ // soon as possible.
+ // This is useful to prevent an error thrown in a task from stalling the event
+ // queue if the exception handled by Node.js’s
+ // `process.on("uncaughtException")` or by a domain.
+ rawAsap.requestFlush = requestFlush;
+
+ // To request a high priority event, we induce a mutation observer by toggling
+ // the text of a text node between "1" and "-1".
+ function makeRequestCallFromMutationObserver(callback) {
+ var toggle = 1;
+ var observer = new BrowserMutationObserver(callback);
+ var node = document.createTextNode("");
+ observer.observe(node, {characterData: true});
+ return function requestCall() {
+ toggle = -toggle;
+ node.data = toggle;
+ };
+ }
+
+ // The message channel technique was discovered by Malte Ubl and was the
+ // original foundation for this library.
+ // http://www.nonblocking.io/2011/06/windownexttick.html
+
+ // Safari 6.0.5 (at least) intermittently fails to create message ports on a
+ // page's first load. Thankfully, this version of Safari supports
+ // MutationObservers, so we don't need to fall back in that case.
+
+ // function makeRequestCallFromMessageChannel(callback) {
+ // var channel = new MessageChannel();
+ // channel.port1.onmessage = callback;
+ // return function requestCall() {
+ // channel.port2.postMessage(0);
+ // };
+ // }
+
+ // For reasons explained above, we are also unable to use `setImmediate`
+ // under any circumstances.
+ // Even if we were, there is another bug in Internet Explorer 10.
+ // It is not sufficient to assign `setImmediate` to `requestFlush` because
+ // `setImmediate` must be called *by name* and therefore must be wrapped in a
+ // closure.
+ // Never forget.
+
+ // function makeRequestCallFromSetImmediate(callback) {
+ // return function requestCall() {
+ // setImmediate(callback);
+ // };
+ // }
+
+ // Safari 6.0 has a problem where timers will get lost while the user is
+ // scrolling. This problem does not impact ASAP because Safari 6.0 supports
+ // mutation observers, so that implementation is used instead.
+ // However, if we ever elect to use timers in Safari, the prevalent work-around
+ // is to add a scroll event listener that calls for a flush.
+
+ // `setTimeout` does not call the passed callback if the delay is less than
+ // approximately 7 in web workers in Firefox 8 through 18, and sometimes not
+ // even then.
+
+ function makeRequestCallFromTimer(callback) {
+ return function requestCall() {
+ // We dispatch a timeout with a specified delay of 0 for engines that
+ // can reliably accommodate that request. This will usually be snapped
+ // to a 4 milisecond delay, but once we're flushing, there's no delay
+ // between events.
+ var timeoutHandle = setTimeout(handleTimer, 0);
+ // However, since this timer gets frequently dropped in Firefox
+ // workers, we enlist an interval handle that will try to fire
+ // an event 20 times per second until it succeeds.
+ var intervalHandle = setInterval(handleTimer, 50);
+
+ function handleTimer() {
+ // Whichever timer succeeds will cancel both timers and
+ // execute the callback.
+ clearTimeout(timeoutHandle);
+ clearInterval(intervalHandle);
+ callback();
+ }
+ };
+ }
+
+ // This is for `asap.js` only.
+ // Its name will be periodically randomized to break any code that depends on
+ // its existence.
+ rawAsap.makeRequestCallFromTimer = makeRequestCallFromTimer;
+
+ // ASAP was originally a nextTick shim included in Q. This was factored out
+ // into this ASAP package. It was later adapted to RSVP which made further
+ // amendments. These decisions, particularly to marginalize MessageChannel and
+ // to capture the MutationObserver implementation in a closure, were integrated
+ // back into ASAP proper.
+ // https://github.com/tildeio/rsvp.js/blob/cddf7232546a9cf858524b75cde6f9edf72620a7/lib/rsvp/asap.js
+
+ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
+
+/***/ },
+/* 6 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ // A simple class system, more documentation to come
+
+ function extend(cls, name, props) {
+ // This does that same thing as Object.create, but with support for IE8
+ var F = function() {};
+ F.prototype = cls.prototype;
+ var prototype = new F();
+
+ // jshint undef: false
+ var fnTest = /xyz/.test(function(){ xyz; }) ? /\bparent\b/ : /.*/;
+ props = props || {};
+
+ for(var k in props) {
+ var src = props[k];
+ var parent = prototype[k];
+
+ if(typeof parent === 'function' &&
+ typeof src === 'function' &&
+ fnTest.test(src)) {
+ /*jshint -W083 */
+ prototype[k] = (function (src, parent) {
+ return function() {
+ // Save the current parent method
+ var tmp = this.parent;
+
+ // Set parent to the previous method, call, and restore
+ this.parent = parent;
+ var res = src.apply(this, arguments);
+ this.parent = tmp;
+
+ return res;
+ };
+ })(src, parent);
+ }
+ else {
+ prototype[k] = src;
+ }
+ }
+
+ prototype.typename = name;
+
+ var new_cls = function() {
+ if(prototype.init) {
+ prototype.init.apply(this, arguments);
+ }
+ };
+
+ new_cls.prototype = prototype;
+ new_cls.prototype.constructor = new_cls;
+
+ new_cls.extend = function(name, props) {
+ if(typeof name === 'object') {
+ props = name;
+ name = 'anonymous';
+ }
+ return extend(new_cls, name, props);
+ };
+
+ return new_cls;
+ }
+
+ module.exports = extend(Object, 'Object', {});
+
+
+/***/ },
+/* 7 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var parser = __webpack_require__(8);
+ var transformer = __webpack_require__(11);
+ var nodes = __webpack_require__(10);
+ // jshint -W079
+ var Object = __webpack_require__(6);
+ var Frame = __webpack_require__(12).Frame;
+
+ // These are all the same for now, but shouldn't be passed straight
+ // through
+ var compareOps = {
+ '==': '==',
+ '!=': '!=',
+ '<': '<',
+ '>': '>',
+ '<=': '<=',
+ '>=': '>='
+ };
+
+ // A common pattern is to emit binary operators
+ function binOpEmitter(str) {
+ return function(node, frame) {
+ this.compile(node.left, frame);
+ this.emit(str);
+ this.compile(node.right, frame);
+ };
+ }
+
+ var Compiler = Object.extend({
+ init: function(templateName, throwOnUndefined) {
+ this.templateName = templateName;
+ this.codebuf = [];
+ this.lastId = 0;
+ this.buffer = null;
+ this.bufferStack = [];
+ this.scopeClosers = '';
+ this.inBlock = false;
+ this.throwOnUndefined = throwOnUndefined;
+ },
+
+ fail: function (msg, lineno, colno) {
+ if (lineno !== undefined) lineno += 1;
+ if (colno !== undefined) colno += 1;
+
+ throw new lib.TemplateError(msg, lineno, colno);
+ },
+
+ pushBufferId: function(id) {
+ this.bufferStack.push(this.buffer);
+ this.buffer = id;
+ this.emit('var ' + this.buffer + ' = "";');
+ },
+
+ popBufferId: function() {
+ this.buffer = this.bufferStack.pop();
+ },
+
+ emit: function(code) {
+ this.codebuf.push(code);
+ },
+
+ emitLine: function(code) {
+ this.emit(code + '\n');
+ },
+
+ emitLines: function() {
+ lib.each(lib.toArray(arguments), function(line) {
+ this.emitLine(line);
+ }, this);
+ },
+
+ emitFuncBegin: function(name) {
+ this.buffer = 'output';
+ this.scopeClosers = '';
+ this.emitLine('function ' + name + '(env, context, frame, runtime, cb) {');
+ this.emitLine('var lineno = null;');
+ this.emitLine('var colno = null;');
+ this.emitLine('var ' + this.buffer + ' = "";');
+ this.emitLine('try {');
+ },
+
+ emitFuncEnd: function(noReturn) {
+ if(!noReturn) {
+ this.emitLine('cb(null, ' + this.buffer +');');
+ }
+
+ this.closeScopeLevels();
+ this.emitLine('} catch (e) {');
+ this.emitLine(' cb(runtime.handleError(e, lineno, colno));');
+ this.emitLine('}');
+ this.emitLine('}');
+ this.buffer = null;
+ },
+
+ addScopeLevel: function() {
+ this.scopeClosers += '})';
+ },
+
+ closeScopeLevels: function() {
+ this.emitLine(this.scopeClosers + ';');
+ this.scopeClosers = '';
+ },
+
+ withScopedSyntax: function(func) {
+ var scopeClosers = this.scopeClosers;
+ this.scopeClosers = '';
+
+ func.call(this);
+
+ this.closeScopeLevels();
+ this.scopeClosers = scopeClosers;
+ },
+
+ makeCallback: function(res) {
+ var err = this.tmpid();
+
+ return 'function(' + err + (res ? ',' + res : '') + ') {\n' +
+ 'if(' + err + ') { cb(' + err + '); return; }';
+ },
+
+ tmpid: function() {
+ this.lastId++;
+ return 't_' + this.lastId;
+ },
+
+ _templateName: function() {
+ return this.templateName == null? 'undefined' : JSON.stringify(this.templateName);
+ },
+
+ _compileChildren: function(node, frame) {
+ var children = node.children;
+ for(var i=0, l=children.length; i 0) {
+ this.emit(',');
+ }
+
+ this.compile(node.children[i], frame);
+ }
+
+ if(endChar) {
+ this.emit(endChar);
+ }
+ },
+
+ _compileExpression: function(node, frame) {
+ // TODO: I'm not really sure if this type check is worth it or
+ // not.
+ this.assertType(
+ node,
+ nodes.Literal,
+ nodes.Symbol,
+ nodes.Group,
+ nodes.Array,
+ nodes.Dict,
+ nodes.FunCall,
+ nodes.Caller,
+ nodes.Filter,
+ nodes.LookupVal,
+ nodes.Compare,
+ nodes.InlineIf,
+ nodes.In,
+ nodes.And,
+ nodes.Or,
+ nodes.Not,
+ nodes.Add,
+ nodes.Concat,
+ nodes.Sub,
+ nodes.Mul,
+ nodes.Div,
+ nodes.FloorDiv,
+ nodes.Mod,
+ nodes.Pow,
+ nodes.Neg,
+ nodes.Pos,
+ nodes.Compare,
+ nodes.NodeList
+ );
+ this.compile(node, frame);
+ },
+
+ assertType: function(node /*, types */) {
+ var types = lib.toArray(arguments).slice(1);
+ var success = false;
+
+ for(var i=0; i 0) {
+ this.emit(',');
+ }
+
+ if(arg) {
+ var id = this.tmpid();
+
+ this.emitLine('function(cb) {');
+ this.emitLine('if(!cb) { cb = function(err) { if(err) { throw err; }}}');
+ this.pushBufferId(id);
+
+ this.withScopedSyntax(function() {
+ this.compile(arg, frame);
+ this.emitLine('cb(null, ' + id + ');');
+ });
+
+ this.popBufferId();
+ this.emitLine('return ' + id + ';');
+ this.emitLine('}');
+ }
+ else {
+ this.emit('null');
+ }
+ }, this);
+ }
+
+ if(async) {
+ var res = this.tmpid();
+ this.emitLine(', ' + this.makeCallback(res));
+ this.emitLine(this.buffer + ' += runtime.suppressValue(' + res + ', ' + autoescape + ' && env.opts.autoescape);');
+ this.addScopeLevel();
+ }
+ else {
+ this.emit(')');
+ this.emit(', ' + autoescape + ' && env.opts.autoescape);\n');
+ }
+ },
+
+ compileCallExtensionAsync: function(node, frame) {
+ this.compileCallExtension(node, frame, true);
+ },
+
+ compileNodeList: function(node, frame) {
+ this._compileChildren(node, frame);
+ },
+
+ compileLiteral: function(node) {
+ if(typeof node.value === 'string') {
+ var val = node.value.replace(/\\/g, '\\\\');
+ val = val.replace(/"/g, '\\"');
+ val = val.replace(/\n/g, '\\n');
+ val = val.replace(/\r/g, '\\r');
+ val = val.replace(/\t/g, '\\t');
+ this.emit('"' + val + '"');
+ }
+ else if (node.value === null) {
+ this.emit('null');
+ }
+ else {
+ this.emit(node.value.toString());
+ }
+ },
+
+ compileSymbol: function(node, frame) {
+ var name = node.value;
+ var v;
+
+ if((v = frame.lookup(name))) {
+ this.emit(v);
+ }
+ else {
+ this.emit('runtime.contextOrFrameLookup(' +
+ 'context, frame, "' + name + '")');
+ }
+ },
+
+ compileGroup: function(node, frame) {
+ this._compileAggregate(node, frame, '(', ')');
+ },
+
+ compileArray: function(node, frame) {
+ this._compileAggregate(node, frame, '[', ']');
+ },
+
+ compileDict: function(node, frame) {
+ this._compileAggregate(node, frame, '{', '}');
+ },
+
+ compilePair: function(node, frame) {
+ var key = node.key;
+ var val = node.value;
+
+ if(key instanceof nodes.Symbol) {
+ key = new nodes.Literal(key.lineno, key.colno, key.value);
+ }
+ else if(!(key instanceof nodes.Literal &&
+ typeof key.value === 'string')) {
+ this.fail('compilePair: Dict keys must be strings or names',
+ key.lineno,
+ key.colno);
+ }
+
+ this.compile(key, frame);
+ this.emit(': ');
+ this._compileExpression(val, frame);
+ },
+
+ compileInlineIf: function(node, frame) {
+ this.emit('(');
+ this.compile(node.cond, frame);
+ this.emit('?');
+ this.compile(node.body, frame);
+ this.emit(':');
+ if(node.else_ !== null)
+ this.compile(node.else_, frame);
+ else
+ this.emit('""');
+ this.emit(')');
+ },
+
+ compileIn: function(node, frame) {
+ this.emit('(');
+ this.compile(node.right, frame);
+ this.emit('.indexOf(');
+ this.compile(node.left, frame);
+ this.emit(') !== -1)');
+ },
+
+ compileOr: binOpEmitter(' || '),
+ compileAnd: binOpEmitter(' && '),
+ compileAdd: binOpEmitter(' + '),
+ // ensure concatenation instead of addition
+ // by adding empty string in between
+ compileConcat: binOpEmitter(' + "" + '),
+ compileSub: binOpEmitter(' - '),
+ compileMul: binOpEmitter(' * '),
+ compileDiv: binOpEmitter(' / '),
+ compileMod: binOpEmitter(' % '),
+
+ compileNot: function(node, frame) {
+ this.emit('!');
+ this.compile(node.target, frame);
+ },
+
+ compileFloorDiv: function(node, frame) {
+ this.emit('Math.floor(');
+ this.compile(node.left, frame);
+ this.emit(' / ');
+ this.compile(node.right, frame);
+ this.emit(')');
+ },
+
+ compilePow: function(node, frame) {
+ this.emit('Math.pow(');
+ this.compile(node.left, frame);
+ this.emit(', ');
+ this.compile(node.right, frame);
+ this.emit(')');
+ },
+
+ compileNeg: function(node, frame) {
+ this.emit('-');
+ this.compile(node.target, frame);
+ },
+
+ compilePos: function(node, frame) {
+ this.emit('+');
+ this.compile(node.target, frame);
+ },
+
+ compileCompare: function(node, frame) {
+ this.compile(node.expr, frame);
+
+ for(var i=0; i 0 && !this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseFrom: expected comma',
+ fromTok.lineno,
+ fromTok.colno);
+ }
+
+ var name = this.parsePrimary();
+ if(name.value.charAt(0) === '_') {
+ this.fail('parseFrom: names starting with an underscore ' +
+ 'cannot be imported',
+ name.lineno,
+ name.colno);
+ }
+
+ if(this.skipSymbol('as')) {
+ var alias = this.parsePrimary();
+ names.addChild(new nodes.Pair(name.lineno,
+ name.colno,
+ name,
+ alias));
+ }
+ else {
+ names.addChild(name);
+ }
+
+ withContext = this.parseWithContext();
+ }
+
+ return new nodes.FromImport(fromTok.lineno,
+ fromTok.colno,
+ template,
+ names,
+ withContext);
+ },
+
+ parseBlock: function() {
+ var tag = this.peekToken();
+ if(!this.skipSymbol('block')) {
+ this.fail('parseBlock: expected block', tag.lineno, tag.colno);
+ }
+
+ var node = new nodes.Block(tag.lineno, tag.colno);
+
+ node.name = this.parsePrimary();
+ if(!(node.name instanceof nodes.Symbol)) {
+ this.fail('parseBlock: variable name expected',
+ tag.lineno,
+ tag.colno);
+ }
+
+ this.advanceAfterBlockEnd(tag.value);
+
+ node.body = this.parseUntilBlocks('endblock');
+
+ if(!this.peekToken()) {
+ this.fail('parseBlock: expected endblock, got end of file');
+ }
+
+ this.advanceAfterBlockEnd();
+
+ return node;
+ },
+
+ parseExtends: function() {
+ var tagName = 'extends';
+ var tag = this.peekToken();
+ if(!this.skipSymbol(tagName)) {
+ this.fail('parseTemplateRef: expected '+ tagName);
+ }
+
+ var node = new nodes.Extends(tag.lineno, tag.colno);
+ node.template = this.parseExpression();
+
+ this.advanceAfterBlockEnd(tag.value);
+ return node;
+ },
+
+ parseInclude: function() {
+ var tagName = 'include';
+ var tag = this.peekToken();
+ if(!this.skipSymbol(tagName)) {
+ this.fail('parseInclude: expected '+ tagName);
+ }
+
+ var node = new nodes.Include(tag.lineno, tag.colno);
+ node.template = this.parseExpression();
+
+ if(this.skipSymbol('ignore') && this.skipSymbol('missing')) {
+ node.ignoreMissing = true;
+ }
+
+ this.advanceAfterBlockEnd(tag.value);
+ return node;
+ },
+
+ parseIf: function() {
+ var tag = this.peekToken();
+ var node;
+
+ if(this.skipSymbol('if') || this.skipSymbol('elif')) {
+ node = new nodes.If(tag.lineno, tag.colno);
+ }
+ else if(this.skipSymbol('ifAsync')) {
+ node = new nodes.IfAsync(tag.lineno, tag.colno);
+ }
+ else {
+ this.fail('parseIf: expected if or elif',
+ tag.lineno,
+ tag.colno);
+ }
+
+ node.cond = this.parseExpression();
+ this.advanceAfterBlockEnd(tag.value);
+
+ node.body = this.parseUntilBlocks('elif', 'else', 'endif');
+ var tok = this.peekToken();
+
+ switch(tok && tok.value) {
+ case 'elif':
+ node.else_ = this.parseIf();
+ break;
+ case 'else':
+ this.advanceAfterBlockEnd();
+ node.else_ = this.parseUntilBlocks('endif');
+ this.advanceAfterBlockEnd();
+ break;
+ case 'endif':
+ node.else_ = null;
+ this.advanceAfterBlockEnd();
+ break;
+ default:
+ this.fail('parseIf: expected elif, else, or endif, ' +
+ 'got end of file');
+ }
+
+ return node;
+ },
+
+ parseSet: function() {
+ var tag = this.peekToken();
+ if(!this.skipSymbol('set')) {
+ this.fail('parseSet: expected set', tag.lineno, tag.colno);
+ }
+
+ var node = new nodes.Set(tag.lineno, tag.colno, []);
+
+ var target;
+ while((target = this.parsePrimary())) {
+ node.targets.push(target);
+
+ if(!this.skip(lexer.TOKEN_COMMA)) {
+ break;
+ }
+ }
+
+ if(!this.skipValue(lexer.TOKEN_OPERATOR, '=')) {
+ this.fail('parseSet: expected = in set tag',
+ tag.lineno,
+ tag.colno);
+ }
+
+ node.value = this.parseExpression();
+ this.advanceAfterBlockEnd(tag.value);
+
+ return node;
+ },
+
+ parseStatement: function () {
+ var tok = this.peekToken();
+ var node;
+
+ if(tok.type !== lexer.TOKEN_SYMBOL) {
+ this.fail('tag name expected', tok.lineno, tok.colno);
+ }
+
+ if(this.breakOnBlocks &&
+ lib.indexOf(this.breakOnBlocks, tok.value) !== -1) {
+ return null;
+ }
+
+ switch(tok.value) {
+ case 'raw': return this.parseRaw();
+ case 'if':
+ case 'ifAsync':
+ return this.parseIf();
+ case 'for':
+ case 'asyncEach':
+ case 'asyncAll':
+ return this.parseFor();
+ case 'block': return this.parseBlock();
+ case 'extends': return this.parseExtends();
+ case 'include': return this.parseInclude();
+ case 'set': return this.parseSet();
+ case 'macro': return this.parseMacro();
+ case 'call': return this.parseCall();
+ case 'import': return this.parseImport();
+ case 'from': return this.parseFrom();
+ case 'filter': return this.parseFilterStatement();
+ default:
+ if (this.extensions.length) {
+ for (var i = 0; i < this.extensions.length; i++) {
+ var ext = this.extensions[i];
+ if (lib.indexOf(ext.tags || [], tok.value) !== -1) {
+ return ext.parse(this, nodes, lexer);
+ }
+ }
+ }
+ this.fail('unknown block tag: ' + tok.value, tok.lineno, tok.colno);
+ }
+
+ return node;
+ },
+
+ parseRaw: function() {
+ // Look for upcoming raw blocks (ignore all other kinds of blocks)
+ var rawBlockRegex = /([\s\S]*?){%\s*(raw|endraw)\s*(?=%})%}/;
+ var rawLevel = 1;
+ var str = '';
+ var matches = null;
+
+ // Skip opening raw token
+ // Keep this token to track line and column numbers
+ var begun = this.advanceAfterBlockEnd();
+
+ // Exit when there's nothing to match
+ // or when we've found the matching "endraw" block
+ while((matches = this.tokens._extractRegex(rawBlockRegex)) && rawLevel > 0) {
+ var all = matches[0];
+ var pre = matches[1];
+ var blockName = matches[2];
+
+ // Adjust rawlevel
+ if(blockName === 'raw') {
+ rawLevel += 1;
+ } else if(blockName === 'endraw') {
+ rawLevel -= 1;
+ }
+
+ // Add to str
+ if(rawLevel === 0) {
+ // We want to exclude the last "endraw"
+ str += pre;
+ // Move tokenizer to beginning of endraw block
+ this.tokens.backN(all.length - pre.length);
+ } else {
+ str += all;
+ }
+ }
+
+ return new nodes.Output(
+ begun.lineno,
+ begun.colno,
+ [new nodes.TemplateData(begun.lineno, begun.colno, str)]
+ );
+ },
+
+ parsePostfix: function(node) {
+ var lookup, tok = this.peekToken();
+
+ while(tok) {
+ if(tok.type === lexer.TOKEN_LEFT_PAREN) {
+ // Function call
+ node = new nodes.FunCall(tok.lineno,
+ tok.colno,
+ node,
+ this.parseSignature());
+ }
+ else if(tok.type === lexer.TOKEN_LEFT_BRACKET) {
+ // Reference
+ lookup = this.parseAggregate();
+ if(lookup.children.length > 1) {
+ this.fail('invalid index');
+ }
+
+ node = new nodes.LookupVal(tok.lineno,
+ tok.colno,
+ node,
+ lookup.children[0]);
+ }
+ else if(tok.type === lexer.TOKEN_OPERATOR && tok.value === '.') {
+ // Reference
+ this.nextToken();
+ var val = this.nextToken();
+
+ if(val.type !== lexer.TOKEN_SYMBOL) {
+ this.fail('expected name as lookup value, got ' + val.value,
+ val.lineno,
+ val.colno);
+ }
+
+ // Make a literal string because it's not a variable
+ // reference
+ lookup = new nodes.Literal(val.lineno,
+ val.colno,
+ val.value);
+
+ node = new nodes.LookupVal(tok.lineno,
+ tok.colno,
+ node,
+ lookup);
+ }
+ else {
+ break;
+ }
+
+ tok = this.peekToken();
+ }
+
+ return node;
+ },
+
+ parseExpression: function() {
+ var node = this.parseInlineIf();
+ return node;
+ },
+
+ parseInlineIf: function() {
+ var node = this.parseOr();
+ if(this.skipSymbol('if')) {
+ var cond_node = this.parseOr();
+ var body_node = node;
+ node = new nodes.InlineIf(node.lineno, node.colno);
+ node.body = body_node;
+ node.cond = cond_node;
+ if(this.skipSymbol('else')) {
+ node.else_ = this.parseOr();
+ } else {
+ node.else_ = null;
+ }
+ }
+
+ return node;
+ },
+
+ parseOr: function() {
+ var node = this.parseAnd();
+ while(this.skipSymbol('or')) {
+ var node2 = this.parseAnd();
+ node = new nodes.Or(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseAnd: function() {
+ var node = this.parseNot();
+ while(this.skipSymbol('and')) {
+ var node2 = this.parseNot();
+ node = new nodes.And(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseNot: function() {
+ var tok = this.peekToken();
+ if(this.skipSymbol('not')) {
+ return new nodes.Not(tok.lineno,
+ tok.colno,
+ this.parseNot());
+ }
+ return this.parseIn();
+ },
+
+ parseIn: function() {
+ var node = this.parseCompare();
+ while(1) {
+ // check if the next token is 'not'
+ var tok = this.nextToken();
+ if (!tok) { break; }
+ var invert = tok.type === lexer.TOKEN_SYMBOL && tok.value === 'not';
+ // if it wasn't 'not', put it back
+ if (!invert) { this.pushToken(tok); }
+ if (this.skipSymbol('in')) {
+ var node2 = this.parseCompare();
+ node = new nodes.In(node.lineno,
+ node.colno,
+ node,
+ node2);
+ if (invert) {
+ node = new nodes.Not(node.lineno,
+ node.colno,
+ node);
+ }
+ }
+ else {
+ // if we'd found a 'not' but this wasn't an 'in', put back the 'not'
+ if (invert) { this.pushToken(tok); }
+ break;
+ }
+ }
+ return node;
+ },
+
+ parseCompare: function() {
+ var compareOps = ['==', '!=', '<', '>', '<=', '>='];
+ var expr = this.parseConcat();
+ var ops = [];
+
+ while(1) {
+ var tok = this.nextToken();
+
+ if(!tok) {
+ break;
+ }
+ else if(lib.indexOf(compareOps, tok.value) !== -1) {
+ ops.push(new nodes.CompareOperand(tok.lineno,
+ tok.colno,
+ this.parseConcat(),
+ tok.value));
+ }
+ else {
+ this.pushToken(tok);
+ break;
+ }
+ }
+
+ if(ops.length) {
+ return new nodes.Compare(ops[0].lineno,
+ ops[0].colno,
+ expr,
+ ops);
+ }
+ else {
+ return expr;
+ }
+ },
+
+ // finds the '~' for string concatenation
+ parseConcat: function(){
+ var node = this.parseAdd();
+ while(this.skipValue(lexer.TOKEN_TILDE, '~')) {
+ var node2 = this.parseAdd();
+ node = new nodes.Concat(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseAdd: function() {
+ var node = this.parseSub();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '+')) {
+ var node2 = this.parseSub();
+ node = new nodes.Add(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseSub: function() {
+ var node = this.parseMul();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '-')) {
+ var node2 = this.parseMul();
+ node = new nodes.Sub(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseMul: function() {
+ var node = this.parseDiv();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '*')) {
+ var node2 = this.parseDiv();
+ node = new nodes.Mul(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseDiv: function() {
+ var node = this.parseFloorDiv();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '/')) {
+ var node2 = this.parseFloorDiv();
+ node = new nodes.Div(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseFloorDiv: function() {
+ var node = this.parseMod();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '//')) {
+ var node2 = this.parseMod();
+ node = new nodes.FloorDiv(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseMod: function() {
+ var node = this.parsePow();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '%')) {
+ var node2 = this.parsePow();
+ node = new nodes.Mod(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parsePow: function() {
+ var node = this.parseUnary();
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '**')) {
+ var node2 = this.parseUnary();
+ node = new nodes.Pow(node.lineno,
+ node.colno,
+ node,
+ node2);
+ }
+ return node;
+ },
+
+ parseUnary: function(noFilters) {
+ var tok = this.peekToken();
+ var node;
+
+ if(this.skipValue(lexer.TOKEN_OPERATOR, '-')) {
+ node = new nodes.Neg(tok.lineno,
+ tok.colno,
+ this.parseUnary(true));
+ }
+ else if(this.skipValue(lexer.TOKEN_OPERATOR, '+')) {
+ node = new nodes.Pos(tok.lineno,
+ tok.colno,
+ this.parseUnary(true));
+ }
+ else {
+ node = this.parsePrimary();
+ }
+
+ if(!noFilters) {
+ node = this.parseFilter(node);
+ }
+
+ return node;
+ },
+
+ parsePrimary: function (noPostfix) {
+ var tok = this.nextToken();
+ var val;
+ var node = null;
+
+ if(!tok) {
+ this.fail('expected expression, got end of file');
+ }
+ else if(tok.type === lexer.TOKEN_STRING) {
+ val = tok.value;
+ }
+ else if(tok.type === lexer.TOKEN_INT) {
+ val = parseInt(tok.value, 10);
+ }
+ else if(tok.type === lexer.TOKEN_FLOAT) {
+ val = parseFloat(tok.value);
+ }
+ else if(tok.type === lexer.TOKEN_BOOLEAN) {
+ if(tok.value === 'true') {
+ val = true;
+ }
+ else if(tok.value === 'false') {
+ val = false;
+ }
+ else {
+ this.fail('invalid boolean: ' + tok.value,
+ tok.lineno,
+ tok.colno);
+ }
+ }
+ else if(tok.type === lexer.TOKEN_NONE) {
+ val = null;
+ }
+ else if (tok.type === lexer.TOKEN_REGEX) {
+ val = new RegExp(tok.value.body, tok.value.flags);
+ }
+
+ if(val !== undefined) {
+ node = new nodes.Literal(tok.lineno, tok.colno, val);
+ }
+ else if(tok.type === lexer.TOKEN_SYMBOL) {
+ node = new nodes.Symbol(tok.lineno, tok.colno, tok.value);
+
+ if(!noPostfix) {
+ node = this.parsePostfix(node);
+ }
+ }
+ else {
+ // See if it's an aggregate type, we need to push the
+ // current delimiter token back on
+ this.pushToken(tok);
+ node = this.parseAggregate();
+ }
+
+ if(node) {
+ return node;
+ }
+ else {
+ this.fail('unexpected token: ' + tok.value,
+ tok.lineno,
+ tok.colno);
+ }
+ },
+
+ parseFilterName: function() {
+ var tok = this.expect(lexer.TOKEN_SYMBOL);
+ var name = tok.value;
+
+ while(this.skipValue(lexer.TOKEN_OPERATOR, '.')) {
+ name += '.' + this.expect(lexer.TOKEN_SYMBOL).value;
+ }
+
+ return new nodes.Symbol(tok.lineno, tok.colno, name);
+ },
+
+ parseFilterArgs: function(node) {
+ if(this.peekToken().type === lexer.TOKEN_LEFT_PAREN) {
+ // Get a FunCall node and add the parameters to the
+ // filter
+ var call = this.parsePostfix(node);
+ return call.args.children;
+ }
+ return [];
+ },
+
+ parseFilter: function(node) {
+ while(this.skip(lexer.TOKEN_PIPE)) {
+ var name = this.parseFilterName();
+
+ node = new nodes.Filter(
+ name.lineno,
+ name.colno,
+ name,
+ new nodes.NodeList(
+ name.lineno,
+ name.colno,
+ [node].concat(this.parseFilterArgs(node))
+ )
+ );
+ }
+
+ return node;
+ },
+
+ parseFilterStatement: function() {
+ var filterTok = this.peekToken();
+ if(!this.skipSymbol('filter')) {
+ this.fail('parseFilterStatement: expected filter');
+ }
+
+ var name = this.parseFilterName();
+ var args = this.parseFilterArgs(name);
+
+ this.advanceAfterBlockEnd(filterTok.value);
+ var body = this.parseUntilBlocks('endfilter');
+ this.advanceAfterBlockEnd();
+
+ var node = new nodes.Filter(
+ name.lineno,
+ name.colno,
+ name,
+ new nodes.NodeList(
+ name.lineno,
+ name.colno,
+ // Body is a NodeList with an Output node as a child,
+ // need to strip those
+ body.children[0].children.concat(args)
+ )
+ );
+
+ return new nodes.Output(
+ name.lineno,
+ name.colno,
+ [node]
+ );
+ },
+
+ parseAggregate: function() {
+ var tok = this.nextToken();
+ var node;
+
+ switch(tok.type) {
+ case lexer.TOKEN_LEFT_PAREN:
+ node = new nodes.Group(tok.lineno, tok.colno); break;
+ case lexer.TOKEN_LEFT_BRACKET:
+ node = new nodes.Array(tok.lineno, tok.colno); break;
+ case lexer.TOKEN_LEFT_CURLY:
+ node = new nodes.Dict(tok.lineno, tok.colno); break;
+ default:
+ return null;
+ }
+
+ while(1) {
+ var type = this.peekToken().type;
+ if(type === lexer.TOKEN_RIGHT_PAREN ||
+ type === lexer.TOKEN_RIGHT_BRACKET ||
+ type === lexer.TOKEN_RIGHT_CURLY) {
+ this.nextToken();
+ break;
+ }
+
+ if(node.children.length > 0) {
+ if(!this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseAggregate: expected comma after expression',
+ tok.lineno,
+ tok.colno);
+ }
+ }
+
+ if(node instanceof nodes.Dict) {
+ // TODO: check for errors
+ var key = this.parsePrimary();
+
+ // We expect a key/value pair for dicts, separated by a
+ // colon
+ if(!this.skip(lexer.TOKEN_COLON)) {
+ this.fail('parseAggregate: expected colon after dict key',
+ tok.lineno,
+ tok.colno);
+ }
+
+ // TODO: check for errors
+ var value = this.parseExpression();
+ node.addChild(new nodes.Pair(key.lineno,
+ key.colno,
+ key,
+ value));
+ }
+ else {
+ // TODO: check for errors
+ var expr = this.parseExpression();
+ node.addChild(expr);
+ }
+ }
+
+ return node;
+ },
+
+ parseSignature: function(tolerant, noParens) {
+ var tok = this.peekToken();
+ if(!noParens && tok.type !== lexer.TOKEN_LEFT_PAREN) {
+ if(tolerant) {
+ return null;
+ }
+ else {
+ this.fail('expected arguments', tok.lineno, tok.colno);
+ }
+ }
+
+ if(tok.type === lexer.TOKEN_LEFT_PAREN) {
+ tok = this.nextToken();
+ }
+
+ var args = new nodes.NodeList(tok.lineno, tok.colno);
+ var kwargs = new nodes.KeywordArgs(tok.lineno, tok.colno);
+ var checkComma = false;
+
+ while(1) {
+ tok = this.peekToken();
+ if(!noParens && tok.type === lexer.TOKEN_RIGHT_PAREN) {
+ this.nextToken();
+ break;
+ }
+ else if(noParens && tok.type === lexer.TOKEN_BLOCK_END) {
+ break;
+ }
+
+ if(checkComma && !this.skip(lexer.TOKEN_COMMA)) {
+ this.fail('parseSignature: expected comma after expression',
+ tok.lineno,
+ tok.colno);
+ }
+ else {
+ var arg = this.parseExpression();
+
+ if(this.skipValue(lexer.TOKEN_OPERATOR, '=')) {
+ kwargs.addChild(
+ new nodes.Pair(arg.lineno,
+ arg.colno,
+ arg,
+ this.parseExpression())
+ );
+ }
+ else {
+ args.addChild(arg);
+ }
+ }
+
+ checkComma = true;
+ }
+
+ if(kwargs.children.length) {
+ args.addChild(kwargs);
+ }
+
+ return args;
+ },
+
+ parseUntilBlocks: function(/* blockNames */) {
+ var prev = this.breakOnBlocks;
+ this.breakOnBlocks = lib.toArray(arguments);
+
+ var ret = this.parse();
+
+ this.breakOnBlocks = prev;
+ return ret;
+ },
+
+ parseNodes: function () {
+ var tok;
+ var buf = [];
+
+ while((tok = this.nextToken())) {
+ if(tok.type === lexer.TOKEN_DATA) {
+ var data = tok.value;
+ var nextToken = this.peekToken();
+ var nextVal = nextToken && nextToken.value;
+
+ // If the last token has "-" we need to trim the
+ // leading whitespace of the data. This is marked with
+ // the `dropLeadingWhitespace` variable.
+ if(this.dropLeadingWhitespace) {
+ // TODO: this could be optimized (don't use regex)
+ data = data.replace(/^\s*/, '');
+ this.dropLeadingWhitespace = false;
+ }
+
+ // Same for the succeding block start token
+ if(nextToken &&
+ nextToken.type === lexer.TOKEN_BLOCK_START &&
+ nextVal.charAt(nextVal.length - 1) === '-') {
+ // TODO: this could be optimized (don't use regex)
+ data = data.replace(/\s*$/, '');
+ }
+
+ buf.push(new nodes.Output(tok.lineno,
+ tok.colno,
+ [new nodes.TemplateData(tok.lineno,
+ tok.colno,
+ data)]));
+ }
+ else if(tok.type === lexer.TOKEN_BLOCK_START) {
+ var n = this.parseStatement();
+ if(!n) {
+ break;
+ }
+ buf.push(n);
+ }
+ else if(tok.type === lexer.TOKEN_VARIABLE_START) {
+ var e = this.parseExpression();
+ this.advanceAfterVariableEnd();
+ buf.push(new nodes.Output(tok.lineno, tok.colno, [e]));
+ }
+ else if(tok.type !== lexer.TOKEN_COMMENT) {
+ // Ignore comments, otherwise this should be an error
+ this.fail('Unexpected token at top-level: ' +
+ tok.type, tok.lineno, tok.colno);
+ }
+ }
+
+ return buf;
+ },
+
+ parse: function() {
+ return new nodes.NodeList(0, 0, this.parseNodes());
+ },
+
+ parseAsRoot: function() {
+ return new nodes.Root(0, 0, this.parseNodes());
+ }
+ });
+
+ // var util = require('util');
+
+ // var l = lexer.lex('{%- if x -%}\n hello {% endif %}');
+ // var t;
+ // while((t = l.nextToken())) {
+ // console.log(util.inspect(t));
+ // }
+
+ // var p = new Parser(lexer.lex('hello {% filter title %}' +
+ // 'Hello madam how are you' +
+ // '{% endfilter %}'));
+ // var n = p.parseAsRoot();
+ // nodes.printNodes(n);
+
+ module.exports = {
+ parse: function(src, extensions, opts) {
+ var p = new Parser(lexer.lex(src, opts));
+ if (extensions !== undefined) {
+ p.extensions = extensions;
+ }
+ return p.parseAsRoot();
+ }
+ };
+
+
+/***/ },
+/* 9 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+
+ var whitespaceChars = ' \n\t\r\u00A0';
+ var delimChars = '()[]{}%*-+~/#,:|.<>=!';
+ var intChars = '0123456789';
+
+ var BLOCK_START = '{%';
+ var BLOCK_END = '%}';
+ var VARIABLE_START = '{{';
+ var VARIABLE_END = '}}';
+ var COMMENT_START = '{#';
+ var COMMENT_END = '#}';
+
+ var TOKEN_STRING = 'string';
+ var TOKEN_WHITESPACE = 'whitespace';
+ var TOKEN_DATA = 'data';
+ var TOKEN_BLOCK_START = 'block-start';
+ var TOKEN_BLOCK_END = 'block-end';
+ var TOKEN_VARIABLE_START = 'variable-start';
+ var TOKEN_VARIABLE_END = 'variable-end';
+ var TOKEN_COMMENT = 'comment';
+ var TOKEN_LEFT_PAREN = 'left-paren';
+ var TOKEN_RIGHT_PAREN = 'right-paren';
+ var TOKEN_LEFT_BRACKET = 'left-bracket';
+ var TOKEN_RIGHT_BRACKET = 'right-bracket';
+ var TOKEN_LEFT_CURLY = 'left-curly';
+ var TOKEN_RIGHT_CURLY = 'right-curly';
+ var TOKEN_OPERATOR = 'operator';
+ var TOKEN_COMMA = 'comma';
+ var TOKEN_COLON = 'colon';
+ var TOKEN_TILDE = 'tilde';
+ var TOKEN_PIPE = 'pipe';
+ var TOKEN_INT = 'int';
+ var TOKEN_FLOAT = 'float';
+ var TOKEN_BOOLEAN = 'boolean';
+ var TOKEN_NONE = 'none';
+ var TOKEN_SYMBOL = 'symbol';
+ var TOKEN_SPECIAL = 'special';
+ var TOKEN_REGEX = 'regex';
+
+ function token(type, value, lineno, colno) {
+ return {
+ type: type,
+ value: value,
+ lineno: lineno,
+ colno: colno
+ };
+ }
+
+ function Tokenizer(str, opts) {
+ this.str = str;
+ this.index = 0;
+ this.len = str.length;
+ this.lineno = 0;
+ this.colno = 0;
+
+ this.in_code = false;
+
+ opts = opts || {};
+
+ var tags = opts.tags || {};
+ this.tags = {
+ BLOCK_START: tags.blockStart || BLOCK_START,
+ BLOCK_END: tags.blockEnd || BLOCK_END,
+ VARIABLE_START: tags.variableStart || VARIABLE_START,
+ VARIABLE_END: tags.variableEnd || VARIABLE_END,
+ COMMENT_START: tags.commentStart || COMMENT_START,
+ COMMENT_END: tags.commentEnd || COMMENT_END
+ };
+
+ this.trimBlocks = !!opts.trimBlocks;
+ this.lstripBlocks = !!opts.lstripBlocks;
+ }
+
+ Tokenizer.prototype.nextToken = function() {
+ var lineno = this.lineno;
+ var colno = this.colno;
+ var tok;
+
+ if(this.in_code) {
+ // Otherwise, if we are in a block parse it as code
+ var cur = this.current();
+
+ if(this.is_finished()) {
+ // We have nothing else to parse
+ return null;
+ }
+ else if(cur === '"' || cur === '\'') {
+ // We've hit a string
+ return token(TOKEN_STRING, this.parseString(cur), lineno, colno);
+ }
+ else if((tok = this._extract(whitespaceChars))) {
+ // We hit some whitespace
+ return token(TOKEN_WHITESPACE, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.BLOCK_END)) ||
+ (tok = this._extractString('-' + this.tags.BLOCK_END))) {
+ // Special check for the block end tag
+ //
+ // It is a requirement that start and end tags are composed of
+ // delimiter characters (%{}[] etc), and our code always
+ // breaks on delimiters so we can assume the token parsing
+ // doesn't consume these elsewhere
+ this.in_code = false;
+ if(this.trimBlocks) {
+ cur = this.current();
+ if(cur === '\n') {
+ // Skip newline
+ this.forward();
+ }else if(cur === '\r'){
+ // Skip CRLF newline
+ this.forward();
+ cur = this.current();
+ if(cur === '\n'){
+ this.forward();
+ }else{
+ // Was not a CRLF, so go back
+ this.back();
+ }
+ }
+ }
+ return token(TOKEN_BLOCK_END, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.VARIABLE_END))) {
+ // Special check for variable end tag (see above)
+ this.in_code = false;
+ return token(TOKEN_VARIABLE_END, tok, lineno, colno);
+ }
+ else if (cur === 'r' && this.str.charAt(this.index + 1) === '/') {
+ // Skip past 'r/'.
+ this.forwardN(2);
+
+ // Extract until the end of the regex -- / ends it, \/ does not.
+ var regexBody = '';
+ while (!this.is_finished()) {
+ if (this.current() === '/' && this.previous() !== '\\') {
+ this.forward();
+ break;
+ } else {
+ regexBody += this.current();
+ this.forward();
+ }
+ }
+
+ // Check for flags.
+ // The possible flags are according to https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp)
+ var POSSIBLE_FLAGS = ['g', 'i', 'm', 'y'];
+ var regexFlags = '';
+ while (!this.is_finished()) {
+ var isCurrentAFlag = POSSIBLE_FLAGS.indexOf(this.current()) !== -1;
+ if (isCurrentAFlag) {
+ regexFlags += this.current();
+ this.forward();
+ } else {
+ break;
+ }
+ }
+
+ return token(TOKEN_REGEX, {body: regexBody, flags: regexFlags}, lineno, colno);
+ }
+ else if(delimChars.indexOf(cur) !== -1) {
+ // We've hit a delimiter (a special char like a bracket)
+ this.forward();
+ var complexOps = ['==', '!=', '<=', '>=', '//', '**'];
+ var curComplex = cur + this.current();
+ var type;
+
+ if(lib.indexOf(complexOps, curComplex) !== -1) {
+ this.forward();
+ cur = curComplex;
+ }
+
+ switch(cur) {
+ case '(': type = TOKEN_LEFT_PAREN; break;
+ case ')': type = TOKEN_RIGHT_PAREN; break;
+ case '[': type = TOKEN_LEFT_BRACKET; break;
+ case ']': type = TOKEN_RIGHT_BRACKET; break;
+ case '{': type = TOKEN_LEFT_CURLY; break;
+ case '}': type = TOKEN_RIGHT_CURLY; break;
+ case ',': type = TOKEN_COMMA; break;
+ case ':': type = TOKEN_COLON; break;
+ case '~': type = TOKEN_TILDE; break;
+ case '|': type = TOKEN_PIPE; break;
+ default: type = TOKEN_OPERATOR;
+ }
+
+ return token(type, cur, lineno, colno);
+ }
+ else {
+ // We are not at whitespace or a delimiter, so extract the
+ // text and parse it
+ tok = this._extractUntil(whitespaceChars + delimChars);
+
+ if(tok.match(/^[-+]?[0-9]+$/)) {
+ if(this.current() === '.') {
+ this.forward();
+ var dec = this._extract(intChars);
+ return token(TOKEN_FLOAT, tok + '.' + dec, lineno, colno);
+ }
+ else {
+ return token(TOKEN_INT, tok, lineno, colno);
+ }
+ }
+ else if(tok.match(/^(true|false)$/)) {
+ return token(TOKEN_BOOLEAN, tok, lineno, colno);
+ }
+ else if(tok === 'none') {
+ return token(TOKEN_NONE, tok, lineno, colno);
+ }
+ else if(tok) {
+ return token(TOKEN_SYMBOL, tok, lineno, colno);
+ }
+ else {
+ throw new Error('Unexpected value while parsing: ' + tok);
+ }
+ }
+ }
+ else {
+ // Parse out the template text, breaking on tag
+ // delimiters because we need to look for block/variable start
+ // tags (don't use the full delimChars for optimization)
+ var beginChars = (this.tags.BLOCK_START.charAt(0) +
+ this.tags.VARIABLE_START.charAt(0) +
+ this.tags.COMMENT_START.charAt(0) +
+ this.tags.COMMENT_END.charAt(0));
+
+ if(this.is_finished()) {
+ return null;
+ }
+ else if((tok = this._extractString(this.tags.BLOCK_START + '-')) ||
+ (tok = this._extractString(this.tags.BLOCK_START))) {
+ this.in_code = true;
+ return token(TOKEN_BLOCK_START, tok, lineno, colno);
+ }
+ else if((tok = this._extractString(this.tags.VARIABLE_START))) {
+ this.in_code = true;
+ return token(TOKEN_VARIABLE_START, tok, lineno, colno);
+ }
+ else {
+ tok = '';
+ var data;
+ var in_comment = false;
+
+ if(this._matches(this.tags.COMMENT_START)) {
+ in_comment = true;
+ tok = this._extractString(this.tags.COMMENT_START);
+ }
+
+ // Continually consume text, breaking on the tag delimiter
+ // characters and checking to see if it's a start tag.
+ //
+ // We could hit the end of the template in the middle of
+ // our looping, so check for the null return value from
+ // _extractUntil
+ while((data = this._extractUntil(beginChars)) !== null) {
+ tok += data;
+
+ if((this._matches(this.tags.BLOCK_START) ||
+ this._matches(this.tags.VARIABLE_START) ||
+ this._matches(this.tags.COMMENT_START)) &&
+ !in_comment) {
+ if(this.lstripBlocks &&
+ this._matches(this.tags.BLOCK_START) &&
+ this.colno > 0 &&
+ this.colno <= tok.length) {
+ var lastLine = tok.slice(-this.colno);
+ if(/^\s+$/.test(lastLine)) {
+ // Remove block leading whitespace from beginning of the string
+ tok = tok.slice(0, -this.colno);
+ if(!tok.length) {
+ // All data removed, collapse to avoid unnecessary nodes
+ // by returning next token (block start)
+ return this.nextToken();
+ }
+ }
+ }
+ // If it is a start tag, stop looping
+ break;
+ }
+ else if(this._matches(this.tags.COMMENT_END)) {
+ if(!in_comment) {
+ throw new Error('unexpected end of comment');
+ }
+ tok += this._extractString(this.tags.COMMENT_END);
+ break;
+ }
+ else {
+ // It does not match any tag, so add the character and
+ // carry on
+ tok += this.current();
+ this.forward();
+ }
+ }
+
+ if(data === null && in_comment) {
+ throw new Error('expected end of comment, got end of file');
+ }
+
+ return token(in_comment ? TOKEN_COMMENT : TOKEN_DATA,
+ tok,
+ lineno,
+ colno);
+ }
+ }
+
+ throw new Error('Could not parse text');
+ };
+
+ Tokenizer.prototype.parseString = function(delimiter) {
+ this.forward();
+
+ var str = '';
+
+ while(!this.is_finished() && this.current() !== delimiter) {
+ var cur = this.current();
+
+ if(cur === '\\') {
+ this.forward();
+ switch(this.current()) {
+ case 'n': str += '\n'; break;
+ case 't': str += '\t'; break;
+ case 'r': str += '\r'; break;
+ default:
+ str += this.current();
+ }
+ this.forward();
+ }
+ else {
+ str += cur;
+ this.forward();
+ }
+ }
+
+ this.forward();
+ return str;
+ };
+
+ Tokenizer.prototype._matches = function(str) {
+ if(this.index + str.length > this.len) {
+ return null;
+ }
+
+ var m = this.str.slice(this.index, this.index + str.length);
+ return m === str;
+ };
+
+ Tokenizer.prototype._extractString = function(str) {
+ if(this._matches(str)) {
+ this.index += str.length;
+ return str;
+ }
+ return null;
+ };
+
+ Tokenizer.prototype._extractUntil = function(charString) {
+ // Extract all non-matching chars, with the default matching set
+ // to everything
+ return this._extractMatching(true, charString || '');
+ };
+
+ Tokenizer.prototype._extract = function(charString) {
+ // Extract all matching chars (no default, so charString must be
+ // explicit)
+ return this._extractMatching(false, charString);
+ };
+
+ Tokenizer.prototype._extractMatching = function (breakOnMatch, charString) {
+ // Pull out characters until a breaking char is hit.
+ // If breakOnMatch is false, a non-matching char stops it.
+ // If breakOnMatch is true, a matching char stops it.
+
+ if(this.is_finished()) {
+ return null;
+ }
+
+ var first = charString.indexOf(this.current());
+
+ // Only proceed if the first character doesn't meet our condition
+ if((breakOnMatch && first === -1) ||
+ (!breakOnMatch && first !== -1)) {
+ var t = this.current();
+ this.forward();
+
+ // And pull out all the chars one at a time until we hit a
+ // breaking char
+ var idx = charString.indexOf(this.current());
+
+ while(((breakOnMatch && idx === -1) ||
+ (!breakOnMatch && idx !== -1)) && !this.is_finished()) {
+ t += this.current();
+ this.forward();
+
+ idx = charString.indexOf(this.current());
+ }
+
+ return t;
+ }
+
+ return '';
+ };
+
+ Tokenizer.prototype._extractRegex = function(regex) {
+ var matches = this.currentStr().match(regex);
+ if(!matches) {
+ return null;
+ }
+
+ // Move forward whatever was matched
+ this.forwardN(matches[0].length);
+
+ return matches;
+ };
+
+ Tokenizer.prototype.is_finished = function() {
+ return this.index >= this.len;
+ };
+
+ Tokenizer.prototype.forwardN = function(n) {
+ for(var i=0; i 0) || !inline) {
+ for(var j=0; j argNames.length) {
+ args = Array.prototype.slice.call(arguments, 0, argNames.length);
+
+ // Positional arguments that should be passed in as
+ // keyword arguments (essentially default values)
+ var vals = Array.prototype.slice.call(arguments, args.length, argCount);
+ for(i = 0; i < vals.length; i++) {
+ if(i < kwargNames.length) {
+ kwargs[kwargNames[i]] = vals[i];
+ }
+ }
+
+ args.push(kwargs);
+ }
+ else if(argCount < argNames.length) {
+ args = Array.prototype.slice.call(arguments, 0, argCount);
+
+ for(i = argCount; i < argNames.length; i++) {
+ var arg = argNames[i];
+
+ // Keyword arguments that should be passed as
+ // positional arguments, i.e. the caller explicitly
+ // used the name of a positional arg
+ args.push(kwargs[arg]);
+ delete kwargs[arg];
+ }
+
+ args.push(kwargs);
+ }
+ else {
+ args = arguments;
+ }
+
+ return func.apply(this, args);
+ };
+ }
+
+ function makeKeywordArgs(obj) {
+ obj.__keywords = true;
+ return obj;
+ }
+
+ function getKeywordArgs(args) {
+ var len = args.length;
+ if(len) {
+ var lastArg = args[len - 1];
+ if(lastArg && lastArg.hasOwnProperty('__keywords')) {
+ return lastArg;
+ }
+ }
+ return {};
+ }
+
+ function numArgs(args) {
+ var len = args.length;
+ if(len === 0) {
+ return 0;
+ }
+
+ var lastArg = args[len - 1];
+ if(lastArg && lastArg.hasOwnProperty('__keywords')) {
+ return len - 1;
+ }
+ else {
+ return len;
+ }
+ }
+
+ // A SafeString object indicates that the string should not be
+ // autoescaped. This happens magically because autoescaping only
+ // occurs on primitive string objects.
+ function SafeString(val) {
+ if(typeof val !== 'string') {
+ return val;
+ }
+
+ this.val = val;
+ this.length = val.length;
+ }
+
+ SafeString.prototype = Object.create(String.prototype, {
+ length: { writable: true, configurable: true, value: 0 }
+ });
+ SafeString.prototype.valueOf = function() {
+ return this.val;
+ };
+ SafeString.prototype.toString = function() {
+ return this.val;
+ };
+
+ function copySafeness(dest, target) {
+ if(dest instanceof SafeString) {
+ return new SafeString(target);
+ }
+ return target.toString();
+ }
+
+ function markSafe(val) {
+ var type = typeof val;
+
+ if(type === 'string') {
+ return new SafeString(val);
+ }
+ else if(type !== 'function') {
+ return val;
+ }
+ else {
+ return function() {
+ var ret = val.apply(this, arguments);
+
+ if(typeof ret === 'string') {
+ return new SafeString(ret);
+ }
+
+ return ret;
+ };
+ }
+ }
+
+ function suppressValue(val, autoescape) {
+ val = (val !== undefined && val !== null) ? val : '';
+
+ if(autoescape && typeof val === 'string') {
+ val = lib.escape(val);
+ }
+
+ return val;
+ }
+
+ function ensureDefined(val, lineno, colno) {
+ if(val === null || val === undefined) {
+ throw new lib.TemplateError(
+ 'attempted to output null or undefined value',
+ lineno + 1,
+ colno + 1
+ );
+ }
+ return val;
+ }
+
+ function memberLookup(obj, val) {
+ obj = obj || {};
+
+ if(typeof obj[val] === 'function') {
+ return function() {
+ return obj[val].apply(obj, arguments);
+ };
+ }
+
+ return obj[val];
+ }
+
+ function callWrap(obj, name, context, args) {
+ if(!obj) {
+ throw new Error('Unable to call `' + name + '`, which is undefined or falsey');
+ }
+ else if(typeof obj !== 'function') {
+ throw new Error('Unable to call `' + name + '`, which is not a function');
+ }
+
+ // jshint validthis: true
+ return obj.apply(context, args);
+ }
+
+ function contextOrFrameLookup(context, frame, name) {
+ var val = frame.lookup(name);
+ return (val !== undefined && val !== null) ?
+ val :
+ context.lookup(name);
+ }
+
+ function handleError(error, lineno, colno) {
+ if(error.lineno) {
+ return error;
+ }
+ else {
+ return new lib.TemplateError(error, lineno, colno);
+ }
+ }
+
+ function asyncEach(arr, dimen, iter, cb) {
+ if(lib.isArray(arr)) {
+ var len = arr.length;
+
+ lib.asyncIter(arr, function(item, i, next) {
+ switch(dimen) {
+ case 1: iter(item, i, len, next); break;
+ case 2: iter(item[0], item[1], i, len, next); break;
+ case 3: iter(item[0], item[1], item[2], i, len, next); break;
+ default:
+ item.push(i, next);
+ iter.apply(this, item);
+ }
+ }, cb);
+ }
+ else {
+ lib.asyncFor(arr, function(key, val, i, len, next) {
+ iter(key, val, i, len, next);
+ }, cb);
+ }
+ }
+
+ function asyncAll(arr, dimen, func, cb) {
+ var finished = 0;
+ var len, i;
+ var outputArr;
+
+ function done(i, output) {
+ finished++;
+ outputArr[i] = output;
+
+ if(finished === len) {
+ cb(null, outputArr.join(''));
+ }
+ }
+
+ if(lib.isArray(arr)) {
+ len = arr.length;
+ outputArr = new Array(len);
+
+ if(len === 0) {
+ cb(null, '');
+ }
+ else {
+ for(i = 0; i < arr.length; i++) {
+ var item = arr[i];
+
+ switch(dimen) {
+ case 1: func(item, i, len, done); break;
+ case 2: func(item[0], item[1], i, len, done); break;
+ case 3: func(item[0], item[1], item[2], i, len, done); break;
+ default:
+ item.push(i, done);
+ // jshint validthis: true
+ func.apply(this, item);
+ }
+ }
+ }
+ }
+ else {
+ var keys = lib.keys(arr);
+ len = keys.length;
+ outputArr = new Array(len);
+
+ if(len === 0) {
+ cb(null, '');
+ }
+ else {
+ for(i = 0; i < keys.length; i++) {
+ var k = keys[i];
+ func(k, arr[k], i, len, done);
+ }
+ }
+ }
+ }
+
+ module.exports = {
+ Frame: Frame,
+ makeMacro: makeMacro,
+ makeKeywordArgs: makeKeywordArgs,
+ numArgs: numArgs,
+ suppressValue: suppressValue,
+ ensureDefined: ensureDefined,
+ memberLookup: memberLookup,
+ contextOrFrameLookup: contextOrFrameLookup,
+ callWrap: callWrap,
+ handleError: handleError,
+ isArray: lib.isArray,
+ keys: lib.keys,
+ SafeString: SafeString,
+ copySafeness: copySafeness,
+ markSafe: markSafe,
+ asyncEach: asyncEach,
+ asyncAll: asyncAll
+ };
+
+
+/***/ },
+/* 13 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var lib = __webpack_require__(1);
+ var r = __webpack_require__(12);
+
+ function normalize(value, defaultValue) {
+ if(value === null || value === undefined || value === false) {
+ return defaultValue;
+ }
+ return value;
+ }
+
+ var filters = {
+ abs: function(n) {
+ return Math.abs(n);
+ },
+
+ batch: function(arr, linecount, fill_with) {
+ var i;
+ var res = [];
+ var tmp = [];
+
+ for(i = 0; i < arr.length; i++) {
+ if(i % linecount === 0 && tmp.length) {
+ res.push(tmp);
+ tmp = [];
+ }
+
+ tmp.push(arr[i]);
+ }
+
+ if(tmp.length) {
+ if(fill_with) {
+ for(i = tmp.length; i < linecount; i++) {
+ tmp.push(fill_with);
+ }
+ }
+
+ res.push(tmp);
+ }
+
+ return res;
+ },
+
+ capitalize: function(str) {
+ str = normalize(str, '');
+ var ret = str.toLowerCase();
+ return r.copySafeness(str, ret.charAt(0).toUpperCase() + ret.slice(1));
+ },
+
+ center: function(str, width) {
+ str = normalize(str, '');
+ width = width || 80;
+
+ if(str.length >= width) {
+ return str;
+ }
+
+ var spaces = width - str.length;
+ var pre = lib.repeat(' ', spaces/2 - spaces % 2);
+ var post = lib.repeat(' ', spaces/2);
+ return r.copySafeness(str, pre + str + post);
+ },
+
+ 'default': function(val, def, bool) {
+ if(bool) {
+ return val ? val : def;
+ }
+ else {
+ return (val !== undefined) ? val : def;
+ }
+ },
+
+ dictsort: function(val, case_sensitive, by) {
+ if (!lib.isObject(val)) {
+ throw new lib.TemplateError('dictsort filter: val must be an object');
+ }
+
+ var array = [];
+ for (var k in val) {
+ // deliberately include properties from the object's prototype
+ array.push([k,val[k]]);
+ }
+
+ var si;
+ if (by === undefined || by === 'key') {
+ si = 0;
+ } else if (by === 'value') {
+ si = 1;
+ } else {
+ throw new lib.TemplateError(
+ 'dictsort filter: You can only sort by either key or value');
+ }
+
+ array.sort(function(t1, t2) {
+ var a = t1[si];
+ var b = t2[si];
+
+ if (!case_sensitive) {
+ if (lib.isString(a)) {
+ a = a.toUpperCase();
+ }
+ if (lib.isString(b)) {
+ b = b.toUpperCase();
+ }
+ }
+
+ return a > b ? 1 : (a === b ? 0 : -1);
+ });
+
+ return array;
+ },
+
+ dump: function(obj) {
+ return JSON.stringify(obj);
+ },
+
+ escape: function(str) {
+ if(typeof str === 'string' ||
+ str instanceof r.SafeString) {
+ return lib.escape(str);
+ }
+ return str;
+ },
+
+ safe: function(str) {
+ return r.markSafe(str);
+ },
+
+ first: function(arr) {
+ return arr[0];
+ },
+
+ groupby: function(arr, attr) {
+ return lib.groupBy(arr, attr);
+ },
+
+ indent: function(str, width, indentfirst) {
+ str = normalize(str, '');
+
+ if (str === '') return '';
+
+ width = width || 4;
+ var res = '';
+ var lines = str.split('\n');
+ var sp = lib.repeat(' ', width);
+
+ for(var i=0; i .a.b.c.
+ res = new_ + str.split('').join(new_) + new_;
+ return r.copySafeness(str, res);
+ }
+
+ var nextIndex = str.indexOf(old);
+ // if # of replacements to perform is 0, or the string to does
+ // not contain the old value, return the string
+ if(maxCount === 0 || nextIndex === -1){
+ return str;
+ }
+
+ var pos = 0;
+ var count = 0; // # of replacements made
+
+ while(nextIndex > -1 && (maxCount === -1 || count < maxCount)){
+ // Grab the next chunk of src string and add it with the
+ // replacement, to the result
+ res += str.substring(pos, nextIndex) + new_;
+ // Increment our pointer in the src string
+ pos = nextIndex + old.length;
+ count++;
+ // See if there are any more replacements to be made
+ nextIndex = str.indexOf(old, pos);
+ }
+
+ // We've either reached the end, or done the max # of
+ // replacements, tack on any remaining string
+ if(pos < str.length) {
+ res += str.substring(pos);
+ }
+
+ return r.copySafeness(originalStr, res);
+ },
+
+ reverse: function(val) {
+ var arr;
+ if(lib.isString(val)) {
+ arr = filters.list(val);
+ }
+ else {
+ // Copy it
+ arr = lib.map(val, function(v) { return v; });
+ }
+
+ arr.reverse();
+
+ if(lib.isString(val)) {
+ return r.copySafeness(val, arr.join(''));
+ }
+ return arr;
+ },
+
+ round: function(val, precision, method) {
+ precision = precision || 0;
+ var factor = Math.pow(10, precision);
+ var rounder;
+
+ if(method === 'ceil') {
+ rounder = Math.ceil;
+ }
+ else if(method === 'floor') {
+ rounder = Math.floor;
+ }
+ else {
+ rounder = Math.round;
+ }
+
+ return rounder(val * factor) / factor;
+ },
+
+ slice: function(arr, slices, fillWith) {
+ var sliceLength = Math.floor(arr.length / slices);
+ var extra = arr.length % slices;
+ var offset = 0;
+ var res = [];
+
+ for(var i=0; i= extra) {
+ slice.push(fillWith);
+ }
+ res.push(slice);
+ }
+
+ return res;
+ },
+
+ sort: r.makeMacro(['value', 'reverse', 'case_sensitive', 'attribute'], [], function(arr, reverse, caseSens, attr) {
+ // Copy it
+ arr = lib.map(arr, function(v) { return v; });
+
+ arr.sort(function(a, b) {
+ var x, y;
+
+ if(attr) {
+ x = a[attr];
+ y = b[attr];
+ }
+ else {
+ x = a;
+ y = b;
+ }
+
+ if(!caseSens && lib.isString(x) && lib.isString(y)) {
+ x = x.toLowerCase();
+ y = y.toLowerCase();
+ }
+
+ if(x < y) {
+ return reverse ? 1 : -1;
+ }
+ else if(x > y) {
+ return reverse ? -1: 1;
+ }
+ else {
+ return 0;
+ }
+ });
+
+ return arr;
+ }),
+
+ string: function(obj) {
+ return r.copySafeness(obj, obj);
+ },
+
+ striptags: function(input, preserve_linebreaks) {
+ input = normalize(input, '');
+ preserve_linebreaks = preserve_linebreaks || false;
+ var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi;
+ var trimmedInput = filters.trim(input.replace(tags, ''));
+ var res = '';
+ if (preserve_linebreaks) {
+ res = trimmedInput
+ .replace(/^ +| +$/gm, '') // remove leading and trailing spaces
+ .replace(/ +/g, ' ') // squash adjacent spaces
+ .replace(/(\r\n)/g, '\n') // normalize linebreaks (CRLF -> LF)
+ .replace(/\n\n\n+/g, '\n\n'); // squash abnormal adjacent linebreaks
+ } else {
+ res = trimmedInput.replace(/\s+/gi, ' ');
+ }
+ return r.copySafeness(input, res);
+ },
+
+ title: function(str) {
+ str = normalize(str, '');
+ var words = str.split(' ');
+ for(var i = 0; i < words.length; i++) {
+ words[i] = filters.capitalize(words[i]);
+ }
+ return r.copySafeness(str, words.join(' '));
+ },
+
+ trim: function(str) {
+ return r.copySafeness(str, str.replace(/^\s*|\s*$/g, ''));
+ },
+
+ truncate: function(input, length, killwords, end) {
+ var orig = input;
+ input = normalize(input, '');
+ length = length || 255;
+
+ if (input.length <= length)
+ return input;
+
+ if (killwords) {
+ input = input.substring(0, length);
+ } else {
+ var idx = input.lastIndexOf(' ', length);
+ if(idx === -1) {
+ idx = length;
+ }
+
+ input = input.substring(0, idx);
+ }
+
+ input += (end !== undefined && end !== null) ? end : '...';
+ return r.copySafeness(orig, input);
+ },
+
+ upper: function(str) {
+ str = normalize(str, '');
+ return str.toUpperCase();
+ },
+
+ urlencode: function(obj) {
+ var enc = encodeURIComponent;
+ if (lib.isString(obj)) {
+ return enc(obj);
+ } else {
+ var parts;
+ if (lib.isArray(obj)) {
+ parts = obj.map(function(item) {
+ return enc(item[0]) + '=' + enc(item[1]);
+ });
+ } else {
+ parts = [];
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) {
+ parts.push(enc(k) + '=' + enc(obj[k]));
+ }
+ }
+ }
+ return parts.join('&');
+ }
+ },
+
+ urlize: function(str, length, nofollow) {
+ if (isNaN(length)) length = Infinity;
+
+ var noFollowAttr = (nofollow === true ? ' rel="nofollow"' : '');
+
+ // For the jinja regexp, see
+ // https://github.com/mitsuhiko/jinja2/blob/f15b814dcba6aa12bc74d1f7d0c881d55f7126be/jinja2/utils.py#L20-L23
+ var puncRE = /^(?:\(|<|<)?(.*?)(?:\.|,|\)|\n|>)?$/;
+ // from http://blog.gerv.net/2011/05/html5_email_address_regexp/
+ var emailRE = /^[\w.!#$%&'*+\-\/=?\^`{|}~]+@[a-z\d\-]+(\.[a-z\d\-]+)+$/i;
+ var httpHttpsRE = /^https?:\/\/.*$/;
+ var wwwRE = /^www\./;
+ var tldRE = /\.(?:org|net|com)(?:\:|\/|$)/;
+
+ var words = str.split(/\s+/).filter(function(word) {
+ // If the word has no length, bail. This can happen for str with
+ // trailing whitespace.
+ return word && word.length;
+ }).map(function(word) {
+ var matches = word.match(puncRE);
+ var possibleUrl = matches && matches[1] || word;
+
+ // url that starts with http or https
+ if (httpHttpsRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ // url that starts with www.
+ if (wwwRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ // an email address of the form username@domain.tld
+ if (emailRE.test(possibleUrl))
+ return '' + possibleUrl + '';
+
+ // url that ends in .com, .org or .net that is not an email address
+ if (tldRE.test(possibleUrl))
+ return '' + possibleUrl.substr(0, length) + '';
+
+ return word;
+
+ });
+
+ return words.join(' ');
+ },
+
+ wordcount: function(str) {
+ str = normalize(str, '');
+ var words = (str) ? str.match(/\w+/g) : null;
+ return (words) ? words.length : null;
+ },
+
+ 'float': function(val, def) {
+ var res = parseFloat(val);
+ return isNaN(res) ? def : res;
+ },
+
+ 'int': function(val, def) {
+ var res = parseInt(val, 10);
+ return isNaN(res) ? def : res;
+ }
+ };
+
+ // Aliases
+ filters.d = filters['default'];
+ filters.e = filters.escape;
+
+ module.exports = filters;
+
+
+/***/ },
+/* 14 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Loader = __webpack_require__(15);
+ var PrecompiledLoader = __webpack_require__(16);
+
+ var WebLoader = Loader.extend({
+ init: function(baseURL, opts) {
+ this.baseURL = baseURL || '.';
+ opts = opts || {};
+
+ // By default, the cache is turned off because there's no way
+ // to "watch" templates over HTTP, so they are re-downloaded
+ // and compiled each time. (Remember, PRECOMPILE YOUR
+ // TEMPLATES in production!)
+ this.useCache = !!opts.useCache;
+
+ // We default `async` to false so that the simple synchronous
+ // API can be used when you aren't doing anything async in
+ // your templates (which is most of the time). This performs a
+ // sync ajax request, but that's ok because it should *only*
+ // happen in development. PRECOMPILE YOUR TEMPLATES.
+ this.async = !!opts.async;
+ },
+
+ resolve: function(from, to) { // jshint ignore:line
+ throw new Error('relative templates not support in the browser yet');
+ },
+
+ getSource: function(name, cb) {
+ var useCache = this.useCache;
+ var result;
+ this.fetch(this.baseURL + '/' + name, function(err, src) {
+ if(err) {
+ if(cb) {
+ cb(err.content);
+ } else {
+ if (err.status === 404) {
+ result = null;
+ } else {
+ throw err.content;
+ }
+ }
+ }
+ else {
+ result = { src: src,
+ path: name,
+ noCache: !useCache };
+ if(cb) {
+ cb(null, result);
+ }
+ }
+ });
+
+ // if this WebLoader isn't running asynchronously, the
+ // fetch above would actually run sync and we'll have a
+ // result here
+ return result;
+ },
+
+ fetch: function(url, cb) {
+ // Only in the browser please
+ var ajax;
+ var loading = true;
+
+ if(window.XMLHttpRequest) { // Mozilla, Safari, ...
+ ajax = new XMLHttpRequest();
+ }
+ else if(window.ActiveXObject) { // IE 8 and older
+ /* global ActiveXObject */
+ ajax = new ActiveXObject('Microsoft.XMLHTTP');
+ }
+
+ ajax.onreadystatechange = function() {
+ if(ajax.readyState === 4 && loading) {
+ loading = false;
+ if(ajax.status === 0 || ajax.status === 200) {
+ cb(null, ajax.responseText);
+ }
+ else {
+ cb({ status: ajax.status, content: ajax.responseText });
+ }
+ }
+ };
+
+ url += (url.indexOf('?') === -1 ? '?' : '&') + 's=' +
+ (new Date().getTime());
+
+ ajax.open('GET', url, this.async);
+ ajax.send();
+ }
+ });
+
+ module.exports = {
+ WebLoader: WebLoader,
+ PrecompiledLoader: PrecompiledLoader
+ };
+
+
+/***/ },
+/* 15 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var path = __webpack_require__(3);
+ var Obj = __webpack_require__(6);
+ var lib = __webpack_require__(1);
+
+ var Loader = Obj.extend({
+ on: function(name, func) {
+ this.listeners = this.listeners || {};
+ this.listeners[name] = this.listeners[name] || [];
+ this.listeners[name].push(func);
+ },
+
+ emit: function(name /*, arg1, arg2, ...*/) {
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if(this.listeners && this.listeners[name]) {
+ lib.each(this.listeners[name], function(listener) {
+ listener.apply(null, args);
+ });
+ }
+ },
+
+ resolve: function(from, to) {
+ return path.resolve(path.dirname(from), to);
+ },
+
+ isRelative: function(filename) {
+ return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
+ }
+ });
+
+ module.exports = Loader;
+
+
+/***/ },
+/* 16 */
+/***/ function(module, exports, __webpack_require__) {
+
+ 'use strict';
+
+ var Loader = __webpack_require__(15);
+
+ var PrecompiledLoader = Loader.extend({
+ init: function(compiledTemplates) {
+ this.precompiled = compiledTemplates || {};
+ },
+
+ getSource: function(name) {
+ if (this.precompiled[name]) {
+ return {
+ src: { type: 'code',
+ obj: this.precompiled[name] },
+ path: name
+ };
+ }
+ return null;
+ }
+ });
+
+ module.exports = PrecompiledLoader;
+
+
+/***/ },
+/* 17 */
+/***/ function(module, exports) {
+
+ 'use strict';
+
+ function cycler(items) {
+ var index = -1;
+
+ return {
+ current: null,
+ reset: function() {
+ index = -1;
+ this.current = null;
+ },
+
+ next: function() {
+ index++;
+ if(index >= items.length) {
+ index = 0;
+ }
+
+ this.current = items[index];
+ return this.current;
+ },
+ };
+
+ }
+
+ function joiner(sep) {
+ sep = sep || ',';
+ var first = true;
+
+ return function() {
+ var val = first ? '' : sep;
+ first = false;
+ return val;
+ };
+ }
+
+ // Making this a function instead so it returns a new object
+ // each time it's called. That way, if something like an environment
+ // uses it, they will each have their own copy.
+ function globals() {
+ return {
+ range: function(start, stop, step) {
+ if(!stop) {
+ stop = start;
+ start = 0;
+ step = 1;
+ }
+ else if(!step) {
+ step = 1;
+ }
+
+ var arr = [];
+ var i;
+ if (step > 0) {
+ for (i=start; istop; i+=step) {
+ arr.push(i);
+ }
+ }
+ return arr;
+ },
+
+ // lipsum: function(n, html, min, max) {
+ // },
+
+ cycler: function() {
+ return cycler(Array.prototype.slice.call(arguments));
+ },
+
+ joiner: function(sep) {
+ return joiner(sep);
+ }
+ };
+ }
+
+ module.exports = globals;
+
+
+/***/ },
+/* 18 */
+/***/ function(module, exports) {
+
+ function installCompat() {
+ 'use strict';
+
+ // This must be called like `nunjucks.installCompat` so that `this`
+ // references the nunjucks instance
+ var runtime = this.runtime; // jshint ignore:line
+ var lib = this.lib; // jshint ignore:line
+
+ var orig_contextOrFrameLookup = runtime.contextOrFrameLookup;
+ runtime.contextOrFrameLookup = function(context, frame, key) {
+ var val = orig_contextOrFrameLookup.apply(this, arguments);
+ if (val === undefined) {
+ switch (key) {
+ case 'True':
+ return true;
+ case 'False':
+ return false;
+ case 'None':
+ return null;
+ }
+ }
+
+ return val;
+ };
+
+ var orig_memberLookup = runtime.memberLookup;
+ var ARRAY_MEMBERS = {
+ pop: function(index) {
+ if (index === undefined) {
+ return this.pop();
+ }
+ if (index >= this.length || index < 0) {
+ throw new Error('KeyError');
+ }
+ return this.splice(index, 1);
+ },
+ remove: function(element) {
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ return this.splice(i, 1);
+ }
+ }
+ throw new Error('ValueError');
+ },
+ count: function(element) {
+ var count = 0;
+ for (var i = 0; i < this.length; i++) {
+ if (this[i] === element) {
+ count++;
+ }
+ }
+ return count;
+ },
+ index: function(element) {
+ var i;
+ if ((i = this.indexOf(element)) === -1) {
+ throw new Error('ValueError');
+ }
+ return i;
+ },
+ find: function(element) {
+ return this.indexOf(element);
+ },
+ insert: function(index, elem) {
+ return this.splice(index, 0, elem);
+ }
+ };
+ var OBJECT_MEMBERS = {
+ items: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push([k, this[k]]);
+ }
+ return ret;
+ },
+ values: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(this[k]);
+ }
+ return ret;
+ },
+ keys: function() {
+ var ret = [];
+ for(var k in this) {
+ ret.push(k);
+ }
+ return ret;
+ },
+ get: function(key, def) {
+ var output = this[key];
+ if (output === undefined) {
+ output = def;
+ }
+ return output;
+ },
+ has_key: function(key) {
+ return this.hasOwnProperty(key);
+ },
+ pop: function(key, def) {
+ var output = this[key];
+ if (output === undefined && def !== undefined) {
+ output = def;
+ } else if (output === undefined) {
+ throw new Error('KeyError');
+ } else {
+ delete this[key];
+ }
+ return output;
+ },
+ popitem: function() {
+ for (var k in this) {
+ // Return the first object pair.
+ var val = this[k];
+ delete this[k];
+ return [k, val];
+ }
+ throw new Error('KeyError');
+ },
+ setdefault: function(key, def) {
+ if (key in this) {
+ return this[key];
+ }
+ if (def === undefined) {
+ def = null;
+ }
+ return this[key] = def;
+ },
+ update: function(kwargs) {
+ for (var k in kwargs) {
+ this[k] = kwargs[k];
+ }
+ return null; // Always returns None
+ }
+ };
+ OBJECT_MEMBERS.iteritems = OBJECT_MEMBERS.items;
+ OBJECT_MEMBERS.itervalues = OBJECT_MEMBERS.values;
+ OBJECT_MEMBERS.iterkeys = OBJECT_MEMBERS.keys;
+ runtime.memberLookup = function(obj, val, autoescape) { // jshint ignore:line
+ obj = obj || {};
+
+ // If the object is an object, return any of the methods that Python would
+ // otherwise provide.
+ if (lib.isArray(obj) && ARRAY_MEMBERS.hasOwnProperty(val)) {
+ return function() {return ARRAY_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ if (lib.isObject(obj) && OBJECT_MEMBERS.hasOwnProperty(val)) {
+ return function() {return OBJECT_MEMBERS[val].apply(obj, arguments);};
+ }
+
+ return orig_memberLookup.apply(this, arguments);
+ };
+ }
+
+ module.exports = installCompat;
+
+
+/***/ }
+/******/ ]);
\ No newline at end of file
diff --git a/certidude/static/js/nunjucks.min.js b/certidude/static/js/nunjucks.min.js
index 0e7c3ee..12870b4 100644
--- a/certidude/static/js/nunjucks.min.js
+++ b/certidude/static/js/nunjucks.min.js
@@ -1,4 +1,4 @@
-/*! Browser bundle of nunjucks 2.1.0 */
-var nunjucks=function(e){function t(i){if(n[i])return n[i].exports;var r=n[i]={exports:{},id:i,loaded:!1};return e[i].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";var i=n(4),r=n(10),s=n(15),o=n(14),a=n(3);e.exports={},e.exports.Environment=r.Environment,e.exports.Template=r.Template,e.exports.Loader=s,e.exports.FileSystemLoader=o.FileSystemLoader,e.exports.PrecompiledLoader=o.PrecompiledLoader,e.exports.WebLoader=o.WebLoader,e.exports.compiler=n(1),e.exports.parser=n(6),e.exports.lexer=n(7),e.exports.runtime=n(9),e.exports.lib=i,e.exports.installJinjaCompat=n(18);var l;e.exports.configure=function(e,t){t=t||{},i.isObject(e)&&(t=e,e=null);var n;return o.FileSystemLoader?n=new o.FileSystemLoader(e,{watch:t.watch,noCache:t.noCache}):o.WebLoader&&(n=new o.WebLoader(e,{useCache:t.web&&t.web.useCache,async:t.web&&t.web.async})),l=new r.Environment(n,t),t&&t.express&&l.express(t.express),l},e.exports.compile=function(t,n,i,r){return l||e.exports.configure(),new e.exports.Template(t,n,i,r)},e.exports.render=function(t,n,i){return l||e.exports.configure(),l.render(t,n,i)},e.exports.renderString=function(t,n,i){return l||e.exports.configure(),l.renderString(t,n,i)},a&&(e.exports.precompile=a.precompile,e.exports.precompileString=a.precompileString)},function(e,t,n){"use strict";function i(e){return function(t,n){this.compile(t.left,n),this.emit(e),this.compile(t.right,n)}}var r=n(4),s=n(6),o=n(8),a=n(2),l=n(5),c=n(9).Frame,h={"==":"==","!=":"!=","<":"<",">":">","<=":"<=",">=":">="},u=l.extend({init:function(e,t){this.templateName=e,this.codebuf=[],this.lastId=0,this.buffer=null,this.bufferStack=[],this.scopeClosers="",this.inBlock=!1,this.throwOnUndefined=t},fail:function(e,t,n){throw void 0!==t&&(t+=1),void 0!==n&&(n+=1),new r.TemplateError(e,t,n)},pushBufferId:function(e){this.bufferStack.push(this.buffer),this.buffer=e,this.emit("var "+this.buffer+' = "";')},popBufferId:function(){this.buffer=this.bufferStack.pop()},emit:function(e){this.codebuf.push(e)},emitLine:function(e){this.emit(e+"\n")},emitLines:function(){r.each(r.toArray(arguments),function(e){this.emitLine(e)},this)},emitFuncBegin:function(e){this.buffer="output",this.scopeClosers="",this.emitLine("function "+e+"(env, context, frame, runtime, cb) {"),this.emitLine("var lineno = null;"),this.emitLine("var colno = null;"),this.emitLine("var "+this.buffer+' = "";'),this.emitLine("try {")},emitFuncEnd:function(e){e||this.emitLine("cb(null, "+this.buffer+");"),this.closeScopeLevels(),this.emitLine("} catch (e) {"),this.emitLine(" cb(runtime.handleError(e, lineno, colno));"),this.emitLine("}"),this.emitLine("}"),this.buffer=null},addScopeLevel:function(){this.scopeClosers+="})"},closeScopeLevels:function(){this.emitLine(this.scopeClosers+";"),this.scopeClosers=""},withScopedSyntax:function(e){var t=this.scopeClosers;this.scopeClosers="",e.call(this),this.closeScopeLevels(),this.scopeClosers=t},makeCallback:function(e){var t=this.tmpid();return"function("+t+(e?","+e:"")+") {\nif("+t+") { cb("+t+"); return; }"},tmpid:function(){return this.lastId++,"t_"+this.lastId},_templateName:function(){return null==this.templateName?"undefined":JSON.stringify(this.templateName)},_compileChildren:function(e,t){for(var n=e.children,i=0,r=n.length;r>i;i++)this.compile(n[i],t)},_compileAggregate:function(e,t,n,i){n&&this.emit(n);for(var r=0;r0&&this.emit(","),this.compile(e.children[r],t);i&&this.emit(i)},_compileExpression:function(e,t){this.assertType(e,a.Literal,a.Symbol,a.Group,a.Array,a.Dict,a.FunCall,a.Caller,a.Filter,a.LookupVal,a.Compare,a.InlineIf,a.In,a.And,a.Or,a.Not,a.Add,a.Concat,a.Sub,a.Mul,a.Div,a.FloorDiv,a.Mod,a.Pow,a.Neg,a.Pos,a.Compare,a.NodeList),this.compile(e,t)},assertType:function(e){for(var t=r.toArray(arguments).slice(1),n=!1,i=0;i0&&this.emit(","),e){var i=this.tmpid();this.emitLine("function(cb) {"),this.emitLine("if(!cb) { cb = function(err) { if(err) { throw err; }}}"),this.pushBufferId(i),this.withScopedSyntax(function(){this.compile(e,t),this.emitLine("cb(null, "+i+");")}),this.popBufferId(),this.emitLine("return "+i+";"),this.emitLine("}")}else this.emit("null")},this),n){var l=this.tmpid();this.emitLine(", "+this.makeCallback(l)),this.emitLine(this.buffer+" += runtime.suppressValue("+l+", "+o+" && env.opts.autoescape);"),this.addScopeLevel()}else this.emit(")"),this.emit(", "+o+" && env.opts.autoescape);\n")},compileCallExtensionAsync:function(e,t){this.compileCallExtension(e,t,!0)},compileNodeList:function(e,t){this._compileChildren(e,t)},compileLiteral:function(e){if("string"==typeof e.value){var t=e.value.replace(/\\/g,"\\\\");t=t.replace(/"/g,'\\"'),t=t.replace(/\n/g,"\\n"),t=t.replace(/\r/g,"\\r"),t=t.replace(/\t/g,"\\t"),this.emit('"'+t+'"')}else null===e.value?this.emit("null"):this.emit(e.value.toString())},compileSymbol:function(e,t){var n,i=e.value;(n=t.lookup(i))?this.emit(n):this.emit('runtime.contextOrFrameLookup(context, frame, "'+i+'")')},compileGroup:function(e,t){this._compileAggregate(e,t,"(",")")},compileArray:function(e,t){this._compileAggregate(e,t,"[","]")},compileDict:function(e,t){this._compileAggregate(e,t,"{","}")},compilePair:function(e,t){var n=e.key,i=e.value;n instanceof a.Symbol?n=new a.Literal(n.lineno,n.colno,n.value):n instanceof a.Literal&&"string"==typeof n.value||this.fail("compilePair: Dict keys must be strings or names",n.lineno,n.colno),this.compile(n,t),this.emit(": "),this._compileExpression(i,t)},compileInlineIf:function(e,t){this.emit("("),this.compile(e.cond,t),this.emit("?"),this.compile(e.body,t),this.emit(":"),null!==e.else_?this.compile(e.else_,t):this.emit('""'),this.emit(")")},compileIn:function(e,t){this.emit("("),this.compile(e.right,t),this.emit(".indexOf("),this.compile(e.left,t),this.emit(") !== -1)")},compileOr:i(" || "),compileAnd:i(" && "),compileAdd:i(" + "),compileConcat:i(' + "" + '),compileSub:i(" - "),compileMul:i(" * "),compileDiv:i(" / "),compileMod:i(" % "),compileNot:function(e,t){this.emit("!"),this.compile(e.target,t)},compileFloorDiv:function(e,t){this.emit("Math.floor("),this.compile(e.left,t),this.emit(" / "),this.compile(e.right,t),this.emit(")")},compilePow:function(e,t){this.emit("Math.pow("),this.compile(e.left,t),this.emit(", "),this.compile(e.right,t),this.emit(")")},compileNeg:function(e,t){this.emit("-"),this.compile(e.target,t)},compilePos:function(e,t){this.emit("+"),this.compile(e.target,t)},compileCompare:function(e,t){this.compile(e.expr,t);for(var n=0;ni;i++)n[i]instanceof a.TemplateData?n[i].value&&(this.emit(this.buffer+" += "),this.compileLiteral(n[i],t),this.emitLine(";")):(this.emit(this.buffer+" += runtime.suppressValue("),this.throwOnUndefined&&this.emit("runtime.ensureDefined("),this.compile(n[i],t),this.throwOnUndefined&&this.emit(","+e.lineno+","+e.colno+")"),this.emit(", env.opts.autoescape);\n"))},compileRoot:function(e,t){t&&this.fail("compileRoot: root node can't have frame"),t=new c,this.emitFuncBegin("root"),this.emitLine("var parentTemplate = null;"),this._compileChildren(e,t),this.emitLine("if(parentTemplate) {"),this.emitLine("parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);"),this.emitLine("} else {"),this.emitLine("cb(null, "+this.buffer+");"),this.emitLine("}"),this.emitFuncEnd(!0),this.inBlock=!0;var n,i,r,s=e.findAll(a.Block);for(n=0;n0||!i))for(var o=0;n>o;o++)t.stdout.write(" ");s===r.length-1?t.stdout.write(r[s]):t.stdout.write(r[s]+"\n")}}if(n=n||0,i(e.typename+": ",n),e instanceof c)i("\n"),s.each(e.children,function(e){r(e,n+2)});else if(e instanceof re)i(e.extName+"."+e.prop),i("\n"),e.args&&r(e.args,n+2),e.contentArgs&&s.each(e.contentArgs,function(e){r(e,n+2)});else{var o=null,l=null;if(e.iterFields(function(e,t){e instanceof a?(o=o||{},o[t]=e):(l=l||{},l[t]=e)}),l?i(JSON.stringify(l,null,2)+"\n",null,!0):i("\n"),o)for(var h in o)r(o[h],n+2)}}var s=n(4),o=n(5),a=o.extend("Node",{init:function(e,t){this.lineno=e,this.colno=t;for(var n=this.fields,i=0,r=n.length;r>i;i++){var s=n[i],o=arguments[i+2];void 0===o&&(o=null),this[s]=o}},findAll:function(e,t){t=t||[];var n,r;if(this instanceof c){var s=this.children;for(n=0,r=s.length;r>n;n++)i(s[n],e,t)}else{var o=this.fields;for(n=0,r=o.length;r>n;n++)i(this[o[n]],e,t)}return t},iterFields:function(e){s.each(this.fields,function(t){e(this[t],t)},this)}}),l=a.extend("Value",{fields:["value"]}),c=a.extend("NodeList",{fields:["children"],init:function(e,t,n){this.parent(e,t,n||[])},addChild:function(e){this.children.push(e)}}),h=c.extend("Root"),u=l.extend("Literal"),p=l.extend("Symbol"),f=c.extend("Group"),m=c.extend("Array"),d=a.extend("Pair",{fields:["key","value"]}),v=c.extend("Dict"),g=a.extend("LookupVal",{fields:["target","val"]}),y=a.extend("If",{fields:["cond","body","else_"]}),k=y.extend("IfAsync"),x=a.extend("InlineIf",{fields:["cond","body","else_"]}),b=a.extend("For",{fields:["arr","name","body","else_"]}),E=b.extend("AsyncEach"),w=b.extend("AsyncAll"),T=a.extend("Macro",{fields:["name","args","body"]}),L=T.extend("Caller"),_=a.extend("Import",{fields:["template","target","withContext"]}),O=a.extend("FromImport",{fields:["template","names","withContext"],init:function(e,t,n,i,r){this.parent(e,t,n,i||new c,r)}}),A=a.extend("FunCall",{fields:["name","args"]}),S=A.extend("Filter"),N=S.extend("FilterAsync",{fields:["name","args","symbol"]}),C=v.extend("KeywordArgs"),B=a.extend("Block",{fields:["name","body"]}),F=a.extend("Super",{fields:["blockName","symbol"]}),R=a.extend("TemplateRef",{fields:["template"]}),K=R.extend("Extends"),I=R.extend("Include"),M=a.extend("Set",{fields:["targets","value"]}),P=c.extend("Output"),D=u.extend("TemplateData"),V=a.extend("UnaryOp",{fields:["target"]}),j=a.extend("BinOp",{fields:["left","right"]}),U=j.extend("In"),W=j.extend("Or"),G=j.extend("And"),Y=V.extend("Not"),H=j.extend("Add"),$=j.extend("Concat"),z=j.extend("Sub"),X=j.extend("Mul"),q=j.extend("Div"),J=j.extend("FloorDiv"),Q=j.extend("Mod"),Z=j.extend("Pow"),ee=V.extend("Neg"),te=V.extend("Pos"),ne=a.extend("Compare",{fields:["expr","ops"]}),ie=a.extend("CompareOperand",{fields:["expr","type"]}),re=a.extend("CallExtension",{fields:["extName","prop","args","contentArgs"],init:function(e,t,n,i){this.extName=e._name||e,this.prop=t,this.args=n||new c,this.contentArgs=i||[],this.autoescape=e.autoescape}}),se=re.extend("CallExtensionAsync");e.exports={Node:a,Root:h,NodeList:c,Value:l,Literal:u,Symbol:p,Group:f,Array:m,Pair:d,Dict:v,Output:P,TemplateData:D,If:y,IfAsync:k,InlineIf:x,For:b,AsyncEach:E,AsyncAll:w,Macro:T,Caller:L,Import:_,FromImport:O,FunCall:A,Filter:S,FilterAsync:N,KeywordArgs:C,Block:B,Super:F,Extends:K,Include:I,Set:M,LookupVal:g,BinOp:j,In:U,Or:W,And:G,Not:Y,Add:H,Concat:$,Sub:z,Mul:X,Div:q,FloorDiv:J,Mod:Q,Pow:Z,Neg:ee,Pos:te,Compare:ne,CompareOperand:ie,CallExtension:re,CallExtensionAsync:se,printNodes:r}}).call(t,n(3))},function(e,t){},function(e,t){"use strict";var n=Array.prototype,i=Object.prototype,r={"&":"&",'"':""","'":"'","<":"<",">":">"},s=/[&"'<>]/g,o=function(e){return r[e]},t=e.exports={};t.prettifyError=function(e,n,i){if(i.Update||(i=new t.TemplateError(i)),i.Update(e),!n){var r=i;i=new Error(r.message),i.name=r.name}return i},t.TemplateError=function(e,t,n){var i=this;if(e instanceof Error){i=e,e=e.name+": "+e.message;try{i.name=""}catch(r){i=this}}else Error.captureStackTrace&&Error.captureStackTrace(i);return i.name="Template render error",i.message=e,i.lineno=t,i.colno=n,i.firstUpdate=!0,i.Update=function(e){var t="("+(e||"unknown path")+")";return this.firstUpdate&&(this.lineno&&this.colno?t+=" [Line "+this.lineno+", Column "+this.colno+"]":this.lineno&&(t+=" [Line "+this.lineno+"]")),t+="\n ",this.firstUpdate&&(t+=" "),this.message=t+(this.message||""),this.firstUpdate=!1,this},i},t.TemplateError.prototype=Error.prototype,t.escape=function(e){return e.replace(s,o)},t.isFunction=function(e){return"[object Function]"===i.toString.call(e)},t.isArray=Array.isArray||function(e){return"[object Array]"===i.toString.call(e)},t.isString=function(e){return"[object String]"===i.toString.call(e)},t.isObject=function(e){return"[object Object]"===i.toString.call(e)},t.groupBy=function(e,n){for(var i={},r=t.isFunction(n)?n:function(e){return e[n]},s=0;si;i++)n+=e;return n},t.each=function(e,t,i){if(null!=e)if(n.each&&e.each===n.each)e.forEach(t,i);else if(e.length===+e.length)for(var r=0,s=e.length;s>r;r++)t.call(i,e[r],r,e)},t.map=function(e,t){var i=[];if(null==e)return i;if(n.map&&e.map===n.map)return e.map(t);for(var r=0;ra?n(t,e[t],a,o,r):i()}var s=t.keys(e),o=s.length,a=-1;r()},t.indexOf=Array.prototype.indexOf?function(e,t,n){return Array.prototype.indexOf.call(e,t,n)}:function(e,t,n){var i=this.length>>>0;for(n=+n||0,Math.abs(n)===1/0&&(n=0),0>n&&(n+=i,0>n&&(n=0));i>n;n++)if(e[n]===t)return n;return-1},Array.prototype.map||(Array.prototype.map=function(){throw new Error("map is unimplemented for this js engine")}),t.keys=function(e){if(Object.prototype.keys)return e.keys();var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t}},function(e,t){"use strict";function n(e,t,i){var r=function(){};r.prototype=e.prototype;var s=new r,o=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;i=i||{};for(var a in i){var l=i[a],c=s[a];"function"==typeof c&&"function"==typeof l&&o.test(l)?s[a]=function(e,t){return function(){var n=this.parent;this.parent=t;var i=e.apply(this,arguments);return this.parent=n,i}}(l,c):s[a]=l}s.typename=t;var h=function(){s.init&&s.init.apply(this,arguments)};return h.prototype=s,h.prototype.constructor=h,h.extend=function(e,t){return"object"==typeof e&&(t=e,e="anonymous"),n(h,e,t)},h}e.exports=n(Object,"Object",{})},function(e,t,n){"use strict";var i=n(7),r=n(2),s=n(5),o=n(4),a=s.extend({init:function(e){this.tokens=e,this.peeked=null,this.breakOnBlocks=null,this.dropLeadingWhitespace=!1,this.extensions=[]},nextToken:function(e){var t;if(this.peeked){if(e||this.peeked.type!==i.TOKEN_WHITESPACE)return t=this.peeked,this.peeked=null,t;this.peeked=null}if(t=this.tokens.nextToken(),!e)for(;t&&t.type===i.TOKEN_WHITESPACE;)t=this.tokens.nextToken();return t},peekToken:function(){return this.peeked=this.peeked||this.nextToken(),this.peeked},pushToken:function(e){if(this.peeked)throw new Error("pushToken: can only push one token on between reads");this.peeked=e},fail:function(e,t,n){if((void 0===t||void 0===n)&&this.peekToken()){var i=this.peekToken();t=i.lineno,n=i.colno}throw void 0!==t&&(t+=1),void 0!==n&&(n+=1),new o.TemplateError(e,t,n)},skip:function(e){var t=this.nextToken();return t&&t.type===e?!0:(this.pushToken(t),!1)},expect:function(e){var t=this.nextToken();return t.type!==e&&this.fail("expected "+e+", got "+t.type,t.lineno,t.colno),t},skipValue:function(e,t){var n=this.nextToken();return n&&n.type===e&&n.value===t?!0:(this.pushToken(n),!1)},skipSymbol:function(e){return this.skipValue(i.TOKEN_SYMBOL,e)},advanceAfterBlockEnd:function(e){var t;return e||(t=this.peekToken(),t||this.fail("unexpected end of file"),t.type!==i.TOKEN_SYMBOL&&this.fail("advanceAfterBlockEnd: expected symbol token or explicit name to be passed"),e=this.nextToken().value),t=this.nextToken(),t&&t.type===i.TOKEN_BLOCK_END?"-"===t.value.charAt(0)&&(this.dropLeadingWhitespace=!0):this.fail("expected block end in "+e+" statement"),t},advanceAfterVariableEnd:function(){this.skip(i.TOKEN_VARIABLE_END)||this.fail("expected variable end")},parseFor:function(){var e,t,n=this.peekToken();this.skipSymbol("for")?(e=new r.For(n.lineno,n.colno),t="endfor"):this.skipSymbol("asyncEach")?(e=new r.AsyncEach(n.lineno,n.colno),t="endeach"):this.skipSymbol("asyncAll")?(e=new r.AsyncAll(n.lineno,n.colno),t="endall"):this.fail("parseFor: expected for{Async}",n.lineno,n.colno),e.name=this.parsePrimary(),e.name instanceof r.Symbol||this.fail("parseFor: variable name expected for loop");var s=this.peekToken().type;if(s===i.TOKEN_COMMA){var o=e.name;for(e.name=new r.Array(o.lineno,o.colno),e.name.addChild(o);this.skip(i.TOKEN_COMMA);){var a=this.parsePrimary();e.name.addChild(a)}}return this.skipSymbol("in")||this.fail('parseFor: expected "in" keyword for loop',n.lineno,n.colno),e.arr=this.parseExpression(),this.advanceAfterBlockEnd(n.value),e.body=this.parseUntilBlocks(t,"else"),this.skipSymbol("else")&&(this.advanceAfterBlockEnd("else"),e.else_=this.parseUntilBlocks(t)),this.advanceAfterBlockEnd(),e},parseMacro:function(){var e=this.peekToken();this.skipSymbol("macro")||this.fail("expected macro");var t=this.parsePrimary(!0),n=this.parseSignature(),i=new r.Macro(e.lineno,e.colno,t,n);return this.advanceAfterBlockEnd(e.value),i.body=this.parseUntilBlocks("endmacro"),this.advanceAfterBlockEnd(),i},parseCall:function(){var e=this.peekToken();this.skipSymbol("call")||this.fail("expected call");var t=this.parseSignature(!0)||new r.NodeList,n=this.parsePrimary();this.advanceAfterBlockEnd(e.value);var i=this.parseUntilBlocks("endcall");this.advanceAfterBlockEnd();var s=new r.Symbol(e.lineno,e.colno,"caller"),o=new r.Caller(e.lineno,e.colno,s,t,i),a=n.args.children;a[a.length-1]instanceof r.KeywordArgs||a.push(new r.KeywordArgs);var l=a[a.length-1];return l.addChild(new r.Pair(e.lineno,e.colno,s,o)),new r.Output(e.lineno,e.colno,[n])},parseWithContext:function(){var e=this.peekToken(),t=null;return this.skipSymbol("with")?t=!0:this.skipSymbol("without")&&(t=!1),null!==t&&(this.skipSymbol("context")||this.fail("parseFrom: expected context after with/without",e.lineno,e.colno)),t},parseImport:function(){var e=this.peekToken();this.skipSymbol("import")||this.fail("parseImport: expected import",e.lineno,e.colno);var t=this.parseExpression();this.skipSymbol("as")||this.fail('parseImport: expected "as" keyword',e.lineno,e.colno);var n=this.parsePrimary(),i=this.parseWithContext(),s=new r.Import(e.lineno,e.colno,t,n,i);return this.advanceAfterBlockEnd(e.value),s},parseFrom:function(){var e=this.peekToken();this.skipSymbol("from")||this.fail("parseFrom: expected from");var t=this.parsePrimary();this.skipSymbol("import")||this.fail("parseFrom: expected import",e.lineno,e.colno);for(var n,s=new r.NodeList;;){var o=this.peekToken();if(o.type===i.TOKEN_BLOCK_END){s.children.length||this.fail("parseFrom: Expected at least one import name",e.lineno,e.colno),"-"===o.value.charAt(0)&&(this.dropLeadingWhitespace=!0),this.nextToken();break}s.children.length>0&&!this.skip(i.TOKEN_COMMA)&&this.fail("parseFrom: expected comma",e.lineno,e.colno);var a=this.parsePrimary();if("_"===a.value.charAt(0)&&this.fail("parseFrom: names starting with an underscore cannot be imported",a.lineno,a.colno),this.skipSymbol("as")){var l=this.parsePrimary();s.addChild(new r.Pair(a.lineno,a.colno,a,l))}else s.addChild(a);n=this.parseWithContext()}return new r.FromImport(e.lineno,e.colno,t,s,n)},parseBlock:function(){var e=this.peekToken();this.skipSymbol("block")||this.fail("parseBlock: expected block",e.lineno,e.colno);var t=new r.Block(e.lineno,e.colno);return t.name=this.parsePrimary(),t.name instanceof r.Symbol||this.fail("parseBlock: variable name expected",e.lineno,e.colno),this.advanceAfterBlockEnd(e.value),t.body=this.parseUntilBlocks("endblock"),this.peekToken()||this.fail("parseBlock: expected endblock, got end of file"),this.advanceAfterBlockEnd(),t},parseTemplateRef:function(e,t){var n=this.peekToken();this.skipSymbol(e)||this.fail("parseTemplateRef: expected "+e);var i=new t(n.lineno,n.colno);return i.template=this.parseExpression(),this.advanceAfterBlockEnd(n.value),i},parseExtends:function(){return this.parseTemplateRef("extends",r.Extends);
-},parseInclude:function(){return this.parseTemplateRef("include",r.Include)},parseIf:function(){var e,t=this.peekToken();this.skipSymbol("if")||this.skipSymbol("elif")?e=new r.If(t.lineno,t.colno):this.skipSymbol("ifAsync")?e=new r.IfAsync(t.lineno,t.colno):this.fail("parseIf: expected if or elif",t.lineno,t.colno),e.cond=this.parseExpression(),this.advanceAfterBlockEnd(t.value),e.body=this.parseUntilBlocks("elif","else","endif");var n=this.peekToken();switch(n&&n.value){case"elif":e.else_=this.parseIf();break;case"else":this.advanceAfterBlockEnd(),e.else_=this.parseUntilBlocks("endif"),this.advanceAfterBlockEnd();break;case"endif":e.else_=null,this.advanceAfterBlockEnd();break;default:this.fail("parseIf: expected endif, else, or endif, got end of file")}return e},parseSet:function(){var e=this.peekToken();this.skipSymbol("set")||this.fail("parseSet: expected set",e.lineno,e.colno);for(var t,n=new r.Set(e.lineno,e.colno,[]);(t=this.parsePrimary())&&(n.targets.push(t),this.skip(i.TOKEN_COMMA)););return this.skipValue(i.TOKEN_OPERATOR,"=")||this.fail("parseSet: expected = in set tag",e.lineno,e.colno),n.value=this.parseExpression(),this.advanceAfterBlockEnd(e.value),n},parseStatement:function(){var e,t=this.peekToken();if(t.type!==i.TOKEN_SYMBOL&&this.fail("tag name expected",t.lineno,t.colno),this.breakOnBlocks&&-1!==o.indexOf(this.breakOnBlocks,t.value))return null;switch(t.value){case"raw":return this.parseRaw();case"if":case"ifAsync":return this.parseIf();case"for":case"asyncEach":case"asyncAll":return this.parseFor();case"block":return this.parseBlock();case"extends":return this.parseExtends();case"include":return this.parseInclude();case"set":return this.parseSet();case"macro":return this.parseMacro();case"call":return this.parseCall();case"import":return this.parseImport();case"from":return this.parseFrom();case"filter":return this.parseFilterStatement();default:if(this.extensions.length)for(var n=0;n0;){var o=i[0],a=i[1],l=i[2];"raw"===l?t+=1:"endraw"===l&&(t-=1),0===t?(n+=a,this.tokens.backN(o.length-a.length)):n+=o}return new r.Output(s.lineno,s.colno,[new r.TemplateData(s.lineno,s.colno,n)])},parsePostfix:function(e){for(var t,n=this.peekToken();n;){if(n.type===i.TOKEN_LEFT_PAREN)e=new r.FunCall(n.lineno,n.colno,e,this.parseSignature());else if(n.type===i.TOKEN_LEFT_BRACKET)t=this.parseAggregate(),t.children.length>1&&this.fail("invalid index"),e=new r.LookupVal(n.lineno,n.colno,e,t.children[0]);else{if(n.type!==i.TOKEN_OPERATOR||"."!==n.value)break;this.nextToken();var s=this.nextToken();s.type!==i.TOKEN_SYMBOL&&this.fail("expected name as lookup value, got "+s.value,s.lineno,s.colno),t=new r.Literal(s.lineno,s.colno,s.value),e=new r.LookupVal(n.lineno,n.colno,e,t)}n=this.peekToken()}return e},parseExpression:function(){var e=this.parseInlineIf();return e},parseInlineIf:function(){var e=this.parseOr();if(this.skipSymbol("if")){var t=this.parseOr(),n=e;e=new r.InlineIf(e.lineno,e.colno),e.body=n,e.cond=t,this.skipSymbol("else")?e.else_=this.parseOr():e.else_=null}return e},parseOr:function(){for(var e=this.parseAnd();this.skipSymbol("or");){var t=this.parseAnd();e=new r.Or(e.lineno,e.colno,e,t)}return e},parseAnd:function(){for(var e=this.parseNot();this.skipSymbol("and");){var t=this.parseNot();e=new r.And(e.lineno,e.colno,e,t)}return e},parseNot:function(){var e=this.peekToken();return this.skipSymbol("not")?new r.Not(e.lineno,e.colno,this.parseNot()):this.parseIn()},parseIn:function(){for(var e=this.parseCompare();;){var t=this.nextToken();if(!t)break;var n=t.type===i.TOKEN_SYMBOL&&"not"===t.value;if(n||this.pushToken(t),!this.skipSymbol("in")){n&&this.pushToken(t);break}var s=this.parseCompare();e=new r.In(e.lineno,e.colno,e,s),n&&(e=new r.Not(e.lineno,e.colno,e))}return e},parseCompare:function(){for(var e=["==","!=","<",">","<=",">="],t=this.parseConcat(),n=[];;){var i=this.nextToken();if(!i)break;if(-1===o.indexOf(e,i.value)){this.pushToken(i);break}n.push(new r.CompareOperand(i.lineno,i.colno,this.parseConcat(),i.value))}return n.length?new r.Compare(n[0].lineno,n[0].colno,t,n):t},parseConcat:function(){for(var e=this.parseAdd();this.skipValue(i.TOKEN_TILDE,"~");){var t=this.parseAdd();e=new r.Concat(e.lineno,e.colno,e,t)}return e},parseAdd:function(){for(var e=this.parseSub();this.skipValue(i.TOKEN_OPERATOR,"+");){var t=this.parseSub();e=new r.Add(e.lineno,e.colno,e,t)}return e},parseSub:function(){for(var e=this.parseMul();this.skipValue(i.TOKEN_OPERATOR,"-");){var t=this.parseMul();e=new r.Sub(e.lineno,e.colno,e,t)}return e},parseMul:function(){for(var e=this.parseDiv();this.skipValue(i.TOKEN_OPERATOR,"*");){var t=this.parseDiv();e=new r.Mul(e.lineno,e.colno,e,t)}return e},parseDiv:function(){for(var e=this.parseFloorDiv();this.skipValue(i.TOKEN_OPERATOR,"/");){var t=this.parseFloorDiv();e=new r.Div(e.lineno,e.colno,e,t)}return e},parseFloorDiv:function(){for(var e=this.parseMod();this.skipValue(i.TOKEN_OPERATOR,"//");){var t=this.parseMod();e=new r.FloorDiv(e.lineno,e.colno,e,t)}return e},parseMod:function(){for(var e=this.parsePow();this.skipValue(i.TOKEN_OPERATOR,"%");){var t=this.parsePow();e=new r.Mod(e.lineno,e.colno,e,t)}return e},parsePow:function(){for(var e=this.parseUnary();this.skipValue(i.TOKEN_OPERATOR,"**");){var t=this.parseUnary();e=new r.Pow(e.lineno,e.colno,e,t)}return e},parseUnary:function(e){var t,n=this.peekToken();return t=this.skipValue(i.TOKEN_OPERATOR,"-")?new r.Neg(n.lineno,n.colno,this.parseUnary(!0)):this.skipValue(i.TOKEN_OPERATOR,"+")?new r.Pos(n.lineno,n.colno,this.parseUnary(!0)):this.parsePrimary(),e||(t=this.parseFilter(t)),t},parsePrimary:function(e){var t,n=this.nextToken(),s=null;return n?n.type===i.TOKEN_STRING?t=n.value:n.type===i.TOKEN_INT?t=parseInt(n.value,10):n.type===i.TOKEN_FLOAT?t=parseFloat(n.value):n.type===i.TOKEN_BOOLEAN?"true"===n.value?t=!0:"false"===n.value?t=!1:this.fail("invalid boolean: "+n.value,n.lineno,n.colno):n.type===i.TOKEN_NONE?t=null:n.type===i.TOKEN_REGEX&&(t=new RegExp(n.value.body,n.value.flags)):this.fail("expected expression, got end of file"),void 0!==t?s=new r.Literal(n.lineno,n.colno,t):n.type===i.TOKEN_SYMBOL?(s=new r.Symbol(n.lineno,n.colno,n.value),e||(s=this.parsePostfix(s))):(this.pushToken(n),s=this.parseAggregate()),s?s:void this.fail("unexpected token: "+n.value,n.lineno,n.colno)},parseFilterName:function(){for(var e=this.expect(i.TOKEN_SYMBOL),t=e.value;this.skipValue(i.TOKEN_OPERATOR,".");)t+="."+this.expect(i.TOKEN_SYMBOL).value;return new r.Symbol(e.lineno,e.colno,t)},parseFilterArgs:function(e){if(this.peekToken().type===i.TOKEN_LEFT_PAREN){var t=this.parsePostfix(e);return t.args.children}return[]},parseFilter:function(e){for(;this.skip(i.TOKEN_PIPE);){var t=this.parseFilterName();e=new r.Filter(t.lineno,t.colno,t,new r.NodeList(t.lineno,t.colno,[e].concat(this.parseFilterArgs(e))))}return e},parseFilterStatement:function(){var e=this.peekToken();this.skipSymbol("filter")||this.fail("parseFilterStatement: expected filter");var t=this.parseFilterName(),n=this.parseFilterArgs(t);this.advanceAfterBlockEnd(e.value);var i=this.parseUntilBlocks("endfilter");this.advanceAfterBlockEnd();var s=new r.Filter(t.lineno,t.colno,t,new r.NodeList(t.lineno,t.colno,i.children[0].children.concat(n)));return new r.Output(t.lineno,t.colno,[s])},parseAggregate:function(){var e,t=this.nextToken();switch(t.type){case i.TOKEN_LEFT_PAREN:e=new r.Group(t.lineno,t.colno);break;case i.TOKEN_LEFT_BRACKET:e=new r.Array(t.lineno,t.colno);break;case i.TOKEN_LEFT_CURLY:e=new r.Dict(t.lineno,t.colno);break;default:return null}for(;;){var n=this.peekToken().type;if(n===i.TOKEN_RIGHT_PAREN||n===i.TOKEN_RIGHT_BRACKET||n===i.TOKEN_RIGHT_CURLY){this.nextToken();break}if(e.children.length>0&&(this.skip(i.TOKEN_COMMA)||this.fail("parseAggregate: expected comma after expression",t.lineno,t.colno)),e instanceof r.Dict){var s=this.parsePrimary();this.skip(i.TOKEN_COLON)||this.fail("parseAggregate: expected colon after dict key",t.lineno,t.colno);var o=this.parseExpression();e.addChild(new r.Pair(s.lineno,s.colno,s,o))}else{var a=this.parseExpression();e.addChild(a)}}return e},parseSignature:function(e,t){var n=this.peekToken();if(!t&&n.type!==i.TOKEN_LEFT_PAREN){if(e)return null;this.fail("expected arguments",n.lineno,n.colno)}n.type===i.TOKEN_LEFT_PAREN&&(n=this.nextToken());for(var s=new r.NodeList(n.lineno,n.colno),o=new r.KeywordArgs(n.lineno,n.colno),a=!1;;){if(n=this.peekToken(),!t&&n.type===i.TOKEN_RIGHT_PAREN){this.nextToken();break}if(t&&n.type===i.TOKEN_BLOCK_END)break;if(a&&!this.skip(i.TOKEN_COMMA))this.fail("parseSignature: expected comma after expression",n.lineno,n.colno);else{var l=this.parseExpression();this.skipValue(i.TOKEN_OPERATOR,"=")?o.addChild(new r.Pair(l.lineno,l.colno,l,this.parseExpression())):s.addChild(l)}a=!0}return o.children.length&&s.addChild(o),s},parseUntilBlocks:function(){var e=this.breakOnBlocks;this.breakOnBlocks=o.toArray(arguments);var t=this.parse();return this.breakOnBlocks=e,t},parseNodes:function(){for(var e,t=[];e=this.nextToken();)if(e.type===i.TOKEN_DATA){var n=e.value,s=this.peekToken(),o=s&&s.value;this.dropLeadingWhitespace&&(n=n.replace(/^\s*/,""),this.dropLeadingWhitespace=!1),s&&s.type===i.TOKEN_BLOCK_START&&"-"===o.charAt(o.length-1)&&(n=n.replace(/\s*$/,"")),t.push(new r.Output(e.lineno,e.colno,[new r.TemplateData(e.lineno,e.colno,n)]))}else if(e.type===i.TOKEN_BLOCK_START){var a=this.parseStatement();if(!a)break;t.push(a)}else if(e.type===i.TOKEN_VARIABLE_START){var l=this.parseExpression();this.advanceAfterVariableEnd(),t.push(new r.Output(e.lineno,e.colno,[l]))}else e.type!==i.TOKEN_COMMENT&&this.fail("Unexpected token at top-level: "+e.type,e.lineno,e.colno);return t},parse:function(){return new r.NodeList(0,0,this.parseNodes())},parseAsRoot:function(){return new r.Root(0,0,this.parseNodes())}});e.exports={parse:function(e,t,n){var r=new a(i.lex(e,n));return void 0!==t&&(r.extensions=t),r.parseAsRoot()}}},function(e,t,n){"use strict";function i(e,t,n,i){return{type:e,value:t,lineno:n,colno:i}}function r(e,t){this.str=e,this.index=0,this.len=e.length,this.lineno=0,this.colno=0,this.in_code=!1,t=t||{};var n=t.tags||{};this.tags={BLOCK_START:n.blockStart||c,BLOCK_END:n.blockEnd||h,VARIABLE_START:n.variableStart||u,VARIABLE_END:n.variableEnd||p,COMMENT_START:n.commentStart||f,COMMENT_END:n.commentEnd||m},this.trimBlocks=!!t.trimBlocks,this.lstripBlocks=!!t.lstripBlocks}var s=n(4),o=" \n \r ",a="()[]{}%*-+~/#,:|.<>=!",l="0123456789",c="{%",h="%}",u="{{",p="}}",f="{#",m="#}",d="string",v="whitespace",g="data",y="block-start",k="block-end",x="variable-start",b="variable-end",E="comment",w="left-paren",T="right-paren",L="left-bracket",_="right-bracket",O="left-curly",A="right-curly",S="operator",N="comma",C="colon",B="tilde",F="pipe",R="int",K="float",I="boolean",M="none",P="symbol",D="special",V="regex";r.prototype.nextToken=function(){var e,t=this.lineno,n=this.colno;if(this.in_code){var r=this.current();if(this.is_finished())return null;if('"'===r||"'"===r)return i(d,this.parseString(r),t,n);if(e=this._extract(o))return i(v,e,t,n);if((e=this._extractString(this.tags.BLOCK_END))||(e=this._extractString("-"+this.tags.BLOCK_END)))return this.in_code=!1,this.trimBlocks&&(r=this.current(),"\n"===r&&this.forward()),i(k,e,t,n);if(e=this._extractString(this.tags.VARIABLE_END))return this.in_code=!1,i(b,e,t,n);if("r"===r&&"/"===this.str.charAt(this.index+1)){this.forwardN(2);for(var c="";!this.is_finished();){if("/"===this.current()&&"\\"!==this.previous()){this.forward();break}c+=this.current(),this.forward()}for(var h=["g","i","m","y"],u="";!this.is_finished();){var p=-1!==h.indexOf(this.current());if(!p)break;u+=this.current(),this.forward()}return i(V,{body:c,flags:u},t,n)}if(-1!==a.indexOf(r)){this.forward();var f,m=["==","!=","<=",">=","//","**"],D=r+this.current();switch(-1!==s.indexOf(m,D)&&(this.forward(),r=D),r){case"(":f=w;break;case")":f=T;break;case"[":f=L;break;case"]":f=_;break;case"{":f=O;break;case"}":f=A;break;case",":f=N;break;case":":f=C;break;case"~":f=B;break;case"|":f=F;break;default:f=S}return i(f,r,t,n)}if(e=this._extractUntil(o+a),e.match(/^[-+]?[0-9]+$/)){if("."===this.current()){this.forward();var j=this._extract(l);return i(K,e+"."+j,t,n)}return i(R,e,t,n)}if(e.match(/^(true|false)$/))return i(I,e,t,n);if("none"===e)return i(M,e,t,n);if(e)return i(P,e,t,n);throw new Error("Unexpected value while parsing: "+e)}var U=this.tags.BLOCK_START.charAt(0)+this.tags.VARIABLE_START.charAt(0)+this.tags.COMMENT_START.charAt(0)+this.tags.COMMENT_END.charAt(0);if(this.is_finished())return null;if((e=this._extractString(this.tags.BLOCK_START+"-"))||(e=this._extractString(this.tags.BLOCK_START)))return this.in_code=!0,i(y,e,t,n);if(e=this._extractString(this.tags.VARIABLE_START))return this.in_code=!0,i(x,e,t,n);e="";var W,G=!1;for(this._matches(this.tags.COMMENT_START)&&(G=!0,e=this._extractString(this.tags.COMMENT_START));null!==(W=this._extractUntil(U));){if(e+=W,(this._matches(this.tags.BLOCK_START)||this._matches(this.tags.VARIABLE_START)||this._matches(this.tags.COMMENT_START))&&!G){if(this.lstripBlocks&&this._matches(this.tags.BLOCK_START)&&this.colno>0&&this.colno<=e.length){var Y=e.slice(-this.colno);if(/^\s+$/.test(Y)&&(e=e.slice(0,-this.colno),!e.length))return this.nextToken()}break}if(this._matches(this.tags.COMMENT_END)){if(!G)throw new Error("unexpected end of comment");e+=this._extractString(this.tags.COMMENT_END);break}e+=this.current(),this.forward()}if(null===W&&G)throw new Error("expected end of comment, got end of file");return i(G?E:g,e,t,n)},r.prototype.parseString=function(e){this.forward();for(var t="";!this.is_finished()&&this.current()!==e;){var n=this.current();if("\\"===n){switch(this.forward(),this.current()){case"n":t+="\n";break;case"t":t+=" ";break;case"r":t+="\r";break;default:t+=this.current()}this.forward()}else t+=n,this.forward()}return this.forward(),t},r.prototype._matches=function(e){if(this.index+e.length>this.len)return null;var t=this.str.slice(this.index,this.index+e.length);return t===e},r.prototype._extractString=function(e){return this._matches(e)?(this.index+=e.length,e):null},r.prototype._extractUntil=function(e){return this._extractMatching(!0,e||"")},r.prototype._extract=function(e){return this._extractMatching(!1,e)},r.prototype._extractMatching=function(e,t){if(this.is_finished())return null;var n=t.indexOf(this.current());if(e&&-1===n||!e&&-1!==n){var i=this.current();this.forward();for(var r=t.indexOf(this.current());(e&&-1===r||!e&&-1!==r)&&!this.is_finished();)i+=this.current(),this.forward(),r=t.indexOf(this.current());return i}return""},r.prototype._extractRegex=function(e){var t=this.currentStr().match(e);return t?(this.forwardN(t[0].length),t):null},r.prototype.is_finished=function(){return this.index>=this.len},r.prototype.forwardN=function(e){for(var t=0;e>t;t++)this.forward()},r.prototype.forward=function(){this.index++,"\n"===this.previous()?(this.lineno++,this.colno=0):this.colno++},r.prototype.backN=function(e){for(var t=0;e>t;t++)this.back()},r.prototype.back=function(){if(this.index--,"\n"===this.current()){this.lineno--;var e=this.src.lastIndexOf("\n",this.index-1);-1===e?this.colno=this.index:this.colno=this.index-e}else this.colno--},r.prototype.current=function(){return this.is_finished()?"":this.str.charAt(this.index)},r.prototype.currentStr=function(){return this.is_finished()?"":this.str.substr(this.index)},r.prototype.previous=function(){return this.str.charAt(this.index-1)},e.exports={lex:function(e,t){return new r(e,t)},TOKEN_STRING:d,TOKEN_WHITESPACE:v,TOKEN_DATA:g,TOKEN_BLOCK_START:y,TOKEN_BLOCK_END:k,TOKEN_VARIABLE_START:x,TOKEN_VARIABLE_END:b,TOKEN_COMMENT:E,TOKEN_LEFT_PAREN:w,TOKEN_RIGHT_PAREN:T,TOKEN_LEFT_BRACKET:L,TOKEN_RIGHT_BRACKET:_,TOKEN_LEFT_CURLY:O,TOKEN_RIGHT_CURLY:A,TOKEN_OPERATOR:S,TOKEN_COMMA:N,TOKEN_COLON:C,TOKEN_TILDE:B,TOKEN_PIPE:F,TOKEN_INT:R,TOKEN_FLOAT:K,TOKEN_BOOLEAN:I,TOKEN_NONE:M,TOKEN_SYMBOL:P,TOKEN_SPECIAL:D,TOKEN_REGEX:V}},function(e,t,n){"use strict";function i(){return"hole_"+d++}function r(e,t){for(var n=null,i=0;ie.length){i=Array.prototype.slice.call(arguments,0,e.length);var c=Array.prototype.slice.call(arguments,i.length,a);for(r=0;ri;i++)s.push(n);r.push(s)}return r},capitalize:function(e){e=i(e,"");var t=e.toLowerCase();return s.copySafeness(e,t.charAt(0).toUpperCase()+t.slice(1))},center:function(e,t){if(e=i(e,""),t=t||80,e.length>=t)return e;var n=t-e.length,o=r.repeat(" ",n/2-n%2),a=r.repeat(" ",n/2);return s.copySafeness(e,o+e+a)},"default":function(e,t,n){return n===!0||n===!1||o||(o=!0,console.log('[nunjucks] Warning: the "default" filter was used without specifying the type of comparison. 2.0 changed the default behavior from boolean (val ? val : def) to strictly undefined, so you should make sure that doesn\'t break anything. Be explicit about this to make this warning go away, or wait until 2.1. See http://mozilla.github.io/nunjucks/templating.html#defaultvalue-default-boolean')),n?e?e:t:void 0!==e?e:t},dictsort:function(e,t,n){if(!r.isObject(e))throw new r.TemplateError("dictsort filter: val must be an object");var i=[];for(var s in e)i.push([s,e[s]]);var o;if(void 0===n||"key"===n)o=0;else{if("value"!==n)throw new r.TemplateError("dictsort filter: You can only sort by either key or value");o=1}return i.sort(function(e,n){var i=e[o],s=n[o];return t||(r.isString(i)&&(i=i.toUpperCase()),r.isString(s)&&(s=s.toUpperCase())),i>s?1:i===s?0:-1}),i},dump:function(e){return JSON.stringify(e)},escape:function(e){return"string"==typeof e||e instanceof s.SafeString?r.escape(e):e},safe:function(e){return s.markSafe(e)},first:function(e){return e[0]},groupby:function(e,t){return r.groupBy(e,t)},indent:function(e,t,n){if(e=i(e,""),""===e)return"";t=t||4;for(var o="",a=e.split("\n"),l=r.repeat(" ",t),c=0;c-1&&(-1===i||i>c);)o+=e.substring(l,a)+n,l=a+t.length,c++,a=e.indexOf(t,l);return la;a++){var l=s+a*i;r>a&&s++;var c=s+(a+1)*i,h=e.slice(l,c);n&&a>=r&&h.push(n),o.push(h)}return o},sort:s.makeMacro(["value","reverse","case_sensitive","attribute"],[],function(e,t,n,i){return e=r.map(e,function(e){return e}),e.sort(function(e,s){var o,a;return i?(o=e[i],a=s[i]):(o=e,a=s),!n&&r.isString(o)&&r.isString(a)&&(o=o.toLowerCase(),a=a.toLowerCase()),a>o?t?1:-1:o>a?t?-1:1:0}),e}),string:function(e){return s.copySafeness(e,e)},title:function(e){e=i(e,"");for(var t=e.split(" "),n=0;n"+c.substr(0,t)+"":a.test(c)?'"+c.substr(0,t)+"":s.test(c)?''+c+"":l.test(c)?'"+c.substr(0,t)+"":e});return c.join(" ")},wordcount:function(e){e=i(e,"");var t=e?e.match(/\w+/g):null;return t?t.length:null},"float":function(e,t){var n=parseFloat(e);return isNaN(n)?t:n},"int":function(e,t){var n=parseInt(e,10);return isNaN(n)?t:n}};a.d=a["default"],a.e=a.escape,e.exports=a},function(e,t,n){"use strict";function i(){if(l.length)throw l.shift()}function r(e){var t;t=a.length?a.pop():new s,t.task=e,o(t)}function s(){this.task=null}var o=n(13),a=[],l=[],c=o.makeRequestCallFromTimer(i);e.exports=r,s.prototype.call=function(){try{this.task.call()}catch(e){r.onerror?r.onerror(e):(l.push(e),c())}finally{this.task=null,a[a.length]=this}}},function(e,t){(function(t){"use strict";function n(e){a.length||(o(),l=!0),a[a.length]=e}function i(){for(;ch){for(var t=0,n=a.length-c;n>t;t++)a[t]=a[t+c];a.length-=c,c=0}}a.length=0,c=0,l=!1}function r(e){var t=1,n=new u(e),i=document.createTextNode("");return n.observe(i,{characterData:!0}),function(){t=-t,i.data=t}}function s(e){return function(){function t(){clearTimeout(n),clearInterval(i),e()}var n=setTimeout(t,0),i=setInterval(t,50)}}e.exports=n;var o,a=[],l=!1,c=0,h=1024,u=t.MutationObserver||t.WebKitMutationObserver;o="function"==typeof u?r(i):s(i),n.requestFlush=o,n.makeRequestCallFromTimer=s}).call(t,function(){return this}())},function(e,t,n){"use strict";var i=n(15),r=n(16),s=i.extend({init:function(e,t){this.baseURL=e||".",t=t||{},this.useCache=!!t.useCache,this.async=!!t.async},resolve:function(e,t){throw new Error("relative templates not support in the browser yet")},getSource:function(e,t){var n,i=this.useCache;return this.fetch(this.baseURL+"/"+e,function(r,s){if(r){if(!t)throw r;t(r)}else n={src:s,path:e,noCache:!i},t&&t(null,n)}),n},fetch:function(e,t){var n,i=!0;window.XMLHttpRequest?n=new XMLHttpRequest:window.ActiveXObject&&(n=new ActiveXObject("Microsoft.XMLHTTP")),n.onreadystatechange=function(){4===n.readyState&&i&&(i=!1,0===n.status||200===n.status?t(null,n.responseText):t(n.responseText))},e+=(-1===e.indexOf("?")?"?":"&")+"s="+(new Date).getTime(),n.open("GET",e,this.async),n.send()}});e.exports={WebLoader:s,PrecompiledLoader:r}},function(e,t,n){"use strict";var i=n(3),r=n(5),s=n(4),o=r.extend({on:function(e,t){this.listeners=this.listeners||{},this.listeners[e]=this.listeners[e]||[],this.listeners[e].push(t)},emit:function(e){var t=Array.prototype.slice.call(arguments,1);this.listeners&&this.listeners[e]&&s.each(this.listeners[e],function(e){e.apply(null,t)})},resolve:function(e,t){return i.resolve(i.dirname(e),t)},isRelative:function(e){return 0===e.indexOf("./")||0===e.indexOf("../")}});e.exports=o},function(e,t,n){"use strict";var i=n(15),r=i.extend({init:function(e){this.precompiled=e||{}},getSource:function(e){return this.precompiled[e]?{src:{type:"code",obj:this.precompiled[e]},path:e}:null}});e.exports=r},function(e,t){"use strict";function n(e){var t=-1;return{current:null,reset:function(){t=-1,this.current=null},next:function(){return t++,t>=e.length&&(t=0),this.current=e[t],this.current}}}function i(e){e=e||",";var t=!0;return function(){var n=t?"":e;return t=!1,n}}var r={range:function(e,t,n){t?n||(n=1):(t=e,e=0,n=1);for(var i=[],r=e;t>r;r+=n)i.push(r);return i},cycler:function(){return n(Array.prototype.slice.call(arguments))},joiner:function(e){return i(e)}};e.exports=r},function(e,t){function n(){"use strict";var e=this.runtime,t=this.lib,n=e.contextOrFrameLookup;e.contextOrFrameLookup=function(e,t,i){var r=n.apply(this,arguments);if(void 0===r)switch(i){case"True":return!0;case"False":return!1;case"None":return null}return r};var i=e.memberLookup,r={pop:function(e){if(void 0===e)return this.pop();if(e>=this.length||0>e)throw new Error("KeyError");return this.splice(e,1)},remove:function(e){for(var t=0;t":">"},s=/[&"'<>]/g,o=function(e){return r[e]},t=e.exports={};t.prettifyError=function(e,n,i){if(i.Update||(i=new t.TemplateError(i)),i.Update(e),!n){var r=i;i=new Error(r.message),i.name=r.name}return i},t.TemplateError=function(e,t,n){var i=this;if(e instanceof Error){i=e,e=e.name+": "+e.message;try{i.name=""}catch(r){i=this}}else Error.captureStackTrace&&Error.captureStackTrace(i);return i.name="Template render error",i.message=e,i.lineno=t,i.colno=n,i.firstUpdate=!0,i.Update=function(e){var t="("+(e||"unknown path")+")";return this.firstUpdate&&(this.lineno&&this.colno?t+=" [Line "+this.lineno+", Column "+this.colno+"]":this.lineno&&(t+=" [Line "+this.lineno+"]")),t+="\n ",this.firstUpdate&&(t+=" "),this.message=t+(this.message||""),this.firstUpdate=!1,this},i},t.TemplateError.prototype=Error.prototype,t.escape=function(e){return e.replace(s,o)},t.isFunction=function(e){return"[object Function]"===i.toString.call(e)},t.isArray=Array.isArray||function(e){return"[object Array]"===i.toString.call(e)},t.isString=function(e){return"[object String]"===i.toString.call(e)},t.isObject=function(e){return"[object Object]"===i.toString.call(e)},t.groupBy=function(e,n){for(var i={},r=t.isFunction(n)?n:function(e){return e[n]},s=0;si;i++)n+=e;return n},t.each=function(e,t,i){if(null!=e)if(n.each&&e.each===n.each)e.forEach(t,i);else if(e.length===+e.length)for(var r=0,s=e.length;s>r;r++)t.call(i,e[r],r,e)},t.map=function(e,t){var i=[];if(null==e)return i;if(n.map&&e.map===n.map)return e.map(t);for(var r=0;ra?n(t,e[t],a,o,r):i()}var s=t.keys(e),o=s.length,a=-1;r()},t.indexOf=Array.prototype.indexOf?function(e,t,n){return Array.prototype.indexOf.call(e,t,n)}:function(e,t,n){var i=this.length>>>0;for(n=+n||0,Math.abs(n)===1/0&&(n=0),0>n&&(n+=i,0>n&&(n=0));i>n;n++)if(e[n]===t)return n;return-1},Array.prototype.map||(Array.prototype.map=function(){throw new Error("map is unimplemented for this js engine")}),t.keys=function(e){if(Object.prototype.keys)return e.keys();var t=[];for(var n in e)e.hasOwnProperty(n)&&t.push(n);return t}},function(e,t,n){"use strict";function i(e,t,n){o(function(){e(t,n)})}var r,s=n(3),o=n(4),a=n(1),l=n(6),c=n(7),h=n(13),u=n(14),p=n(12),f=n(17),m=p.Frame;u.PrecompiledLoader=n(16);var d=l.extend({init:function(e,t){t=this.opts=t||{},this.opts.dev=!!t.dev,this.opts.autoescape=null!=t.autoescape?t.autoescape:!0,this.opts.throwOnUndefined=!!t.throwOnUndefined,this.opts.trimBlocks=!!t.trimBlocks,this.opts.lstripBlocks=!!t.lstripBlocks,this.loaders=[],e?this.loaders=a.isArray(e)?e:[e]:u.FileSystemLoader?this.loaders=[new u.FileSystemLoader("views")]:u.WebLoader&&(this.loaders=[new u.WebLoader("/views")]),window.nunjucksPrecompiled&&this.loaders.unshift(new u.PrecompiledLoader(window.nunjucksPrecompiled)),this.initCache(),this.globals=f(),this.filters={},this.asyncFilters=[],this.extensions={},this.extensionsList=[];for(var n in h)this.addFilter(n,h[n])},initCache:function(){a.each(this.loaders,function(e){e.cache={},"function"==typeof e.on&&e.on("update",function(t){e.cache[t]=null})})},addExtension:function(e,t){return t._name=e,this.extensions[e]=t,this.extensionsList.push(t),this},removeExtension:function(e){var t=this.getExtension(e);t&&(this.extensionsList=a.without(this.extensionsList,t),delete this.extensions[e])},getExtension:function(e){return this.extensions[e]},hasExtension:function(e){return!!this.extensions[e]},addGlobal:function(e,t){return this.globals[e]=t,this},getGlobal:function(e){if(!this.globals[e])throw new Error("global not found: "+e);return this.globals[e]},addFilter:function(e,t,n){var i=t;return n&&this.asyncFilters.push(e),this.filters[e]=i,this},getFilter:function(e){if(!this.filters[e])throw new Error("filter not found: "+e);return this.filters[e]},resolveTemplate:function(e,t,n){var i=e.isRelative&&t?e.isRelative(n):!1;return i&&e.resolve?e.resolve(t,n):n},getTemplate:function(e,t,n,i,s){var o=this,l=null;if(e&&e.raw&&(e=e.raw),a.isFunction(n)&&(s=n,n=null,t=t||!1),a.isFunction(t)&&(s=t,t=!1),e instanceof r)l=e;else{if("string"!=typeof e)throw new Error("template names must be a string: "+e);for(var c=0;ch){for(var t=0,n=a.length-c;n>t;t++)a[t]=a[t+c];a.length-=c,c=0}}a.length=0,c=0,l=!1}function r(e){var t=1,n=new u(e),i=document.createTextNode("");return n.observe(i,{characterData:!0}),function(){t=-t,i.data=t}}function s(e){return function(){function t(){clearTimeout(n),clearInterval(i),e()}var n=setTimeout(t,0),i=setInterval(t,50)}}e.exports=n;var o,a=[],l=!1,c=0,h=1024,u=t.MutationObserver||t.WebKitMutationObserver;o="function"==typeof u?r(i):s(i),n.requestFlush=o,n.makeRequestCallFromTimer=s}).call(t,function(){return this}())},function(e,t){"use strict";function n(e,t,i){var r=function(){};r.prototype=e.prototype;var s=new r,o=/xyz/.test(function(){xyz})?/\bparent\b/:/.*/;i=i||{};for(var a in i){var l=i[a],c=s[a];"function"==typeof c&&"function"==typeof l&&o.test(l)?s[a]=function(e,t){return function(){var n=this.parent;this.parent=t;var i=e.apply(this,arguments);return this.parent=n,i}}(l,c):s[a]=l}s.typename=t;var h=function(){s.init&&s.init.apply(this,arguments)};return h.prototype=s,h.prototype.constructor=h,h.extend=function(e,t){return"object"==typeof e&&(t=e,e="anonymous"),n(h,e,t)},h}e.exports=n(Object,"Object",{})},function(e,t,n){"use strict";function i(e){return function(t,n){this.compile(t.left,n),this.emit(e),this.compile(t.right,n)}}var r=n(1),s=n(8),o=n(11),a=n(10),l=n(6),c=n(12).Frame,h={"==":"==","!=":"!=","<":"<",">":">","<=":"<=",">=":">="},u=l.extend({init:function(e,t){this.templateName=e,this.codebuf=[],this.lastId=0,this.buffer=null,this.bufferStack=[],this.scopeClosers="",this.inBlock=!1,this.throwOnUndefined=t},fail:function(e,t,n){throw void 0!==t&&(t+=1),void 0!==n&&(n+=1),new r.TemplateError(e,t,n)},pushBufferId:function(e){this.bufferStack.push(this.buffer),this.buffer=e,this.emit("var "+this.buffer+' = "";')},popBufferId:function(){this.buffer=this.bufferStack.pop()},emit:function(e){this.codebuf.push(e)},emitLine:function(e){this.emit(e+"\n")},emitLines:function(){r.each(r.toArray(arguments),function(e){this.emitLine(e)},this)},emitFuncBegin:function(e){this.buffer="output",this.scopeClosers="",this.emitLine("function "+e+"(env, context, frame, runtime, cb) {"),this.emitLine("var lineno = null;"),this.emitLine("var colno = null;"),this.emitLine("var "+this.buffer+' = "";'),this.emitLine("try {")},emitFuncEnd:function(e){e||this.emitLine("cb(null, "+this.buffer+");"),this.closeScopeLevels(),this.emitLine("} catch (e) {"),this.emitLine(" cb(runtime.handleError(e, lineno, colno));"),this.emitLine("}"),this.emitLine("}"),this.buffer=null},addScopeLevel:function(){this.scopeClosers+="})"},closeScopeLevels:function(){this.emitLine(this.scopeClosers+";"),this.scopeClosers=""},withScopedSyntax:function(e){var t=this.scopeClosers;this.scopeClosers="",e.call(this),this.closeScopeLevels(),this.scopeClosers=t},makeCallback:function(e){var t=this.tmpid();return"function("+t+(e?","+e:"")+") {\nif("+t+") { cb("+t+"); return; }"},tmpid:function(){return this.lastId++,"t_"+this.lastId},_templateName:function(){return null==this.templateName?"undefined":JSON.stringify(this.templateName)},_compileChildren:function(e,t){for(var n=e.children,i=0,r=n.length;r>i;i++)this.compile(n[i],t)},_compileAggregate:function(e,t,n,i){n&&this.emit(n);for(var r=0;r0&&this.emit(","),this.compile(e.children[r],t);i&&this.emit(i)},_compileExpression:function(e,t){this.assertType(e,a.Literal,a.Symbol,a.Group,a.Array,a.Dict,a.FunCall,a.Caller,a.Filter,a.LookupVal,a.Compare,a.InlineIf,a.In,a.And,a.Or,a.Not,a.Add,a.Concat,a.Sub,a.Mul,a.Div,a.FloorDiv,a.Mod,a.Pow,a.Neg,a.Pos,a.Compare,a.NodeList),this.compile(e,t)},assertType:function(e){for(var t=r.toArray(arguments).slice(1),n=!1,i=0;i0&&this.emit(","),e){var i=this.tmpid();this.emitLine("function(cb) {"),this.emitLine("if(!cb) { cb = function(err) { if(err) { throw err; }}}"),this.pushBufferId(i),this.withScopedSyntax(function(){this.compile(e,t),this.emitLine("cb(null, "+i+");")}),this.popBufferId(),this.emitLine("return "+i+";"),this.emitLine("}")}else this.emit("null")},this),n){var l=this.tmpid();this.emitLine(", "+this.makeCallback(l)),this.emitLine(this.buffer+" += runtime.suppressValue("+l+", "+o+" && env.opts.autoescape);"),this.addScopeLevel()}else this.emit(")"),this.emit(", "+o+" && env.opts.autoescape);\n")},compileCallExtensionAsync:function(e,t){this.compileCallExtension(e,t,!0)},compileNodeList:function(e,t){this._compileChildren(e,t)},compileLiteral:function(e){if("string"==typeof e.value){var t=e.value.replace(/\\/g,"\\\\");t=t.replace(/"/g,'\\"'),t=t.replace(/\n/g,"\\n"),t=t.replace(/\r/g,"\\r"),t=t.replace(/\t/g,"\\t"),this.emit('"'+t+'"')}else null===e.value?this.emit("null"):this.emit(e.value.toString())},compileSymbol:function(e,t){var n,i=e.value;(n=t.lookup(i))?this.emit(n):this.emit('runtime.contextOrFrameLookup(context, frame, "'+i+'")')},compileGroup:function(e,t){this._compileAggregate(e,t,"(",")")},compileArray:function(e,t){this._compileAggregate(e,t,"[","]")},compileDict:function(e,t){this._compileAggregate(e,t,"{","}")},compilePair:function(e,t){var n=e.key,i=e.value;n instanceof a.Symbol?n=new a.Literal(n.lineno,n.colno,n.value):n instanceof a.Literal&&"string"==typeof n.value||this.fail("compilePair: Dict keys must be strings or names",n.lineno,n.colno),this.compile(n,t),this.emit(": "),this._compileExpression(i,t)},compileInlineIf:function(e,t){this.emit("("),this.compile(e.cond,t),this.emit("?"),this.compile(e.body,t),this.emit(":"),null!==e.else_?this.compile(e.else_,t):this.emit('""'),this.emit(")")},compileIn:function(e,t){this.emit("("),this.compile(e.right,t),this.emit(".indexOf("),this.compile(e.left,t),this.emit(") !== -1)")},compileOr:i(" || "),compileAnd:i(" && "),compileAdd:i(" + "),compileConcat:i(' + "" + '),compileSub:i(" - "),compileMul:i(" * "),compileDiv:i(" / "),compileMod:i(" % "),compileNot:function(e,t){this.emit("!"),this.compile(e.target,t)},compileFloorDiv:function(e,t){this.emit("Math.floor("),this.compile(e.left,t),this.emit(" / "),this.compile(e.right,t),this.emit(")")},compilePow:function(e,t){this.emit("Math.pow("),this.compile(e.left,t),this.emit(", "),this.compile(e.right,t),this.emit(")")},compileNeg:function(e,t){this.emit("-"),this.compile(e.target,t)},compilePos:function(e,t){this.emit("+"),this.compile(e.target,t)},compileCompare:function(e,t){this.compile(e.expr,t);for(var n=0;ni;i++)n[i]instanceof a.TemplateData?n[i].value&&(this.emit(this.buffer+" += "),this.compileLiteral(n[i],t),this.emitLine(";")):(this.emit(this.buffer+" += runtime.suppressValue("),this.throwOnUndefined&&this.emit("runtime.ensureDefined("),this.compile(n[i],t),this.throwOnUndefined&&this.emit(","+e.lineno+","+e.colno+")"),this.emit(", env.opts.autoescape);\n"))},compileRoot:function(e,t){t&&this.fail("compileRoot: root node can't have frame"),t=new c,this.emitFuncBegin("root"),this.emitLine("var parentTemplate = null;"),this._compileChildren(e,t),this.emitLine("if(parentTemplate) {"),this.emitLine("parentTemplate.rootRenderFunc(env, context, frame, runtime, cb);"),this.emitLine("} else {"),this.emitLine("cb(null, "+this.buffer+");"),this.emitLine("}"),this.emitFuncEnd(!0),this.inBlock=!0;var n,i,r,s=e.findAll(a.Block);for(n=0;n0&&!this.skip(i.TOKEN_COMMA)&&this.fail("parseFrom: expected comma",e.lineno,e.colno);var a=this.parsePrimary();if("_"===a.value.charAt(0)&&this.fail("parseFrom: names starting with an underscore cannot be imported",a.lineno,a.colno),this.skipSymbol("as")){var l=this.parsePrimary();s.addChild(new r.Pair(a.lineno,a.colno,a,l))}else s.addChild(a);n=this.parseWithContext()}return new r.FromImport(e.lineno,e.colno,t,s,n)},parseBlock:function(){var e=this.peekToken();this.skipSymbol("block")||this.fail("parseBlock: expected block",e.lineno,e.colno);var t=new r.Block(e.lineno,e.colno);return t.name=this.parsePrimary(),t.name instanceof r.Symbol||this.fail("parseBlock: variable name expected",e.lineno,e.colno),this.advanceAfterBlockEnd(e.value),t.body=this.parseUntilBlocks("endblock"),this.peekToken()||this.fail("parseBlock: expected endblock, got end of file"),this.advanceAfterBlockEnd(),t},parseExtends:function(){var e="extends",t=this.peekToken();this.skipSymbol(e)||this.fail("parseTemplateRef: expected "+e);var n=new r.Extends(t.lineno,t.colno);return n.template=this.parseExpression(),this.advanceAfterBlockEnd(t.value),n},parseInclude:function(){var e="include",t=this.peekToken();this.skipSymbol(e)||this.fail("parseInclude: expected "+e);var n=new r.Include(t.lineno,t.colno);return n.template=this.parseExpression(),this.skipSymbol("ignore")&&this.skipSymbol("missing")&&(n.ignoreMissing=!0),this.advanceAfterBlockEnd(t.value),n},parseIf:function(){var e,t=this.peekToken();this.skipSymbol("if")||this.skipSymbol("elif")?e=new r.If(t.lineno,t.colno):this.skipSymbol("ifAsync")?e=new r.IfAsync(t.lineno,t.colno):this.fail("parseIf: expected if or elif",t.lineno,t.colno),e.cond=this.parseExpression(),this.advanceAfterBlockEnd(t.value),e.body=this.parseUntilBlocks("elif","else","endif");var n=this.peekToken();switch(n&&n.value){case"elif":e.else_=this.parseIf();break;case"else":this.advanceAfterBlockEnd(),e.else_=this.parseUntilBlocks("endif"),this.advanceAfterBlockEnd();break;case"endif":e.else_=null,this.advanceAfterBlockEnd();break;default:this.fail("parseIf: expected elif, else, or endif, got end of file")}return e},parseSet:function(){var e=this.peekToken();this.skipSymbol("set")||this.fail("parseSet: expected set",e.lineno,e.colno);for(var t,n=new r.Set(e.lineno,e.colno,[]);(t=this.parsePrimary())&&(n.targets.push(t),this.skip(i.TOKEN_COMMA)););return this.skipValue(i.TOKEN_OPERATOR,"=")||this.fail("parseSet: expected = in set tag",e.lineno,e.colno),n.value=this.parseExpression(),this.advanceAfterBlockEnd(e.value),n},parseStatement:function(){var e,t=this.peekToken();if(t.type!==i.TOKEN_SYMBOL&&this.fail("tag name expected",t.lineno,t.colno),this.breakOnBlocks&&-1!==o.indexOf(this.breakOnBlocks,t.value))return null;switch(t.value){case"raw":return this.parseRaw();case"if":case"ifAsync":return this.parseIf();case"for":case"asyncEach":case"asyncAll":return this.parseFor();case"block":return this.parseBlock();case"extends":return this.parseExtends();case"include":return this.parseInclude();case"set":return this.parseSet();case"macro":return this.parseMacro();case"call":return this.parseCall();case"import":return this.parseImport();case"from":return this.parseFrom();case"filter":return this.parseFilterStatement();default:if(this.extensions.length)for(var n=0;n0;){var o=i[0],a=i[1],l=i[2];"raw"===l?t+=1:"endraw"===l&&(t-=1),0===t?(n+=a,this.tokens.backN(o.length-a.length)):n+=o}return new r.Output(s.lineno,s.colno,[new r.TemplateData(s.lineno,s.colno,n)])},parsePostfix:function(e){for(var t,n=this.peekToken();n;){if(n.type===i.TOKEN_LEFT_PAREN)e=new r.FunCall(n.lineno,n.colno,e,this.parseSignature());else if(n.type===i.TOKEN_LEFT_BRACKET)t=this.parseAggregate(),t.children.length>1&&this.fail("invalid index"),e=new r.LookupVal(n.lineno,n.colno,e,t.children[0]);else{if(n.type!==i.TOKEN_OPERATOR||"."!==n.value)break;this.nextToken();var s=this.nextToken();s.type!==i.TOKEN_SYMBOL&&this.fail("expected name as lookup value, got "+s.value,s.lineno,s.colno),t=new r.Literal(s.lineno,s.colno,s.value),e=new r.LookupVal(n.lineno,n.colno,e,t)}n=this.peekToken()}return e},parseExpression:function(){var e=this.parseInlineIf();return e},parseInlineIf:function(){var e=this.parseOr();if(this.skipSymbol("if")){var t=this.parseOr(),n=e;e=new r.InlineIf(e.lineno,e.colno),e.body=n,e.cond=t,this.skipSymbol("else")?e.else_=this.parseOr():e.else_=null}return e},parseOr:function(){for(var e=this.parseAnd();this.skipSymbol("or");){var t=this.parseAnd();e=new r.Or(e.lineno,e.colno,e,t)}return e},parseAnd:function(){for(var e=this.parseNot();this.skipSymbol("and");){var t=this.parseNot();e=new r.And(e.lineno,e.colno,e,t)}return e},parseNot:function(){var e=this.peekToken();return this.skipSymbol("not")?new r.Not(e.lineno,e.colno,this.parseNot()):this.parseIn()},parseIn:function(){for(var e=this.parseCompare();;){var t=this.nextToken();if(!t)break;var n=t.type===i.TOKEN_SYMBOL&&"not"===t.value;if(n||this.pushToken(t),!this.skipSymbol("in")){n&&this.pushToken(t);break}var s=this.parseCompare();e=new r.In(e.lineno,e.colno,e,s),n&&(e=new r.Not(e.lineno,e.colno,e))}return e},parseCompare:function(){for(var e=["==","!=","<",">","<=",">="],t=this.parseConcat(),n=[];;){var i=this.nextToken();if(!i)break;if(-1===o.indexOf(e,i.value)){this.pushToken(i);break}n.push(new r.CompareOperand(i.lineno,i.colno,this.parseConcat(),i.value))}return n.length?new r.Compare(n[0].lineno,n[0].colno,t,n):t},parseConcat:function(){for(var e=this.parseAdd();this.skipValue(i.TOKEN_TILDE,"~");){var t=this.parseAdd();e=new r.Concat(e.lineno,e.colno,e,t)}return e},parseAdd:function(){for(var e=this.parseSub();this.skipValue(i.TOKEN_OPERATOR,"+");){var t=this.parseSub();e=new r.Add(e.lineno,e.colno,e,t)}return e},parseSub:function(){for(var e=this.parseMul();this.skipValue(i.TOKEN_OPERATOR,"-");){var t=this.parseMul();e=new r.Sub(e.lineno,e.colno,e,t)}return e},parseMul:function(){for(var e=this.parseDiv();this.skipValue(i.TOKEN_OPERATOR,"*");){var t=this.parseDiv();e=new r.Mul(e.lineno,e.colno,e,t)}return e},parseDiv:function(){for(var e=this.parseFloorDiv();this.skipValue(i.TOKEN_OPERATOR,"/");){var t=this.parseFloorDiv();e=new r.Div(e.lineno,e.colno,e,t)}return e},parseFloorDiv:function(){for(var e=this.parseMod();this.skipValue(i.TOKEN_OPERATOR,"//");){var t=this.parseMod();e=new r.FloorDiv(e.lineno,e.colno,e,t)}return e},parseMod:function(){for(var e=this.parsePow();this.skipValue(i.TOKEN_OPERATOR,"%");){var t=this.parsePow();e=new r.Mod(e.lineno,e.colno,e,t)}return e},parsePow:function(){for(var e=this.parseUnary();this.skipValue(i.TOKEN_OPERATOR,"**");){var t=this.parseUnary();e=new r.Pow(e.lineno,e.colno,e,t)}return e},parseUnary:function(e){var t,n=this.peekToken();return t=this.skipValue(i.TOKEN_OPERATOR,"-")?new r.Neg(n.lineno,n.colno,this.parseUnary(!0)):this.skipValue(i.TOKEN_OPERATOR,"+")?new r.Pos(n.lineno,n.colno,this.parseUnary(!0)):this.parsePrimary(),e||(t=this.parseFilter(t)),t},parsePrimary:function(e){var t,n=this.nextToken(),s=null;return n?n.type===i.TOKEN_STRING?t=n.value:n.type===i.TOKEN_INT?t=parseInt(n.value,10):n.type===i.TOKEN_FLOAT?t=parseFloat(n.value):n.type===i.TOKEN_BOOLEAN?"true"===n.value?t=!0:"false"===n.value?t=!1:this.fail("invalid boolean: "+n.value,n.lineno,n.colno):n.type===i.TOKEN_NONE?t=null:n.type===i.TOKEN_REGEX&&(t=new RegExp(n.value.body,n.value.flags)):this.fail("expected expression, got end of file"),void 0!==t?s=new r.Literal(n.lineno,n.colno,t):n.type===i.TOKEN_SYMBOL?(s=new r.Symbol(n.lineno,n.colno,n.value),e||(s=this.parsePostfix(s))):(this.pushToken(n),s=this.parseAggregate()),s?s:void this.fail("unexpected token: "+n.value,n.lineno,n.colno)},parseFilterName:function(){for(var e=this.expect(i.TOKEN_SYMBOL),t=e.value;this.skipValue(i.TOKEN_OPERATOR,".");)t+="."+this.expect(i.TOKEN_SYMBOL).value;return new r.Symbol(e.lineno,e.colno,t)},parseFilterArgs:function(e){if(this.peekToken().type===i.TOKEN_LEFT_PAREN){var t=this.parsePostfix(e);return t.args.children}return[]},parseFilter:function(e){for(;this.skip(i.TOKEN_PIPE);){var t=this.parseFilterName();e=new r.Filter(t.lineno,t.colno,t,new r.NodeList(t.lineno,t.colno,[e].concat(this.parseFilterArgs(e))))}return e},parseFilterStatement:function(){var e=this.peekToken();this.skipSymbol("filter")||this.fail("parseFilterStatement: expected filter");var t=this.parseFilterName(),n=this.parseFilterArgs(t);this.advanceAfterBlockEnd(e.value);var i=this.parseUntilBlocks("endfilter");this.advanceAfterBlockEnd();var s=new r.Filter(t.lineno,t.colno,t,new r.NodeList(t.lineno,t.colno,i.children[0].children.concat(n)));return new r.Output(t.lineno,t.colno,[s])},parseAggregate:function(){var e,t=this.nextToken();switch(t.type){case i.TOKEN_LEFT_PAREN:e=new r.Group(t.lineno,t.colno);break;case i.TOKEN_LEFT_BRACKET:e=new r.Array(t.lineno,t.colno);break;case i.TOKEN_LEFT_CURLY:e=new r.Dict(t.lineno,t.colno);break;default:return null}for(;;){var n=this.peekToken().type;if(n===i.TOKEN_RIGHT_PAREN||n===i.TOKEN_RIGHT_BRACKET||n===i.TOKEN_RIGHT_CURLY){this.nextToken();break}if(e.children.length>0&&(this.skip(i.TOKEN_COMMA)||this.fail("parseAggregate: expected comma after expression",t.lineno,t.colno)),e instanceof r.Dict){var s=this.parsePrimary();this.skip(i.TOKEN_COLON)||this.fail("parseAggregate: expected colon after dict key",t.lineno,t.colno);var o=this.parseExpression();e.addChild(new r.Pair(s.lineno,s.colno,s,o))}else{var a=this.parseExpression();e.addChild(a)}}return e},parseSignature:function(e,t){var n=this.peekToken();if(!t&&n.type!==i.TOKEN_LEFT_PAREN){if(e)return null;this.fail("expected arguments",n.lineno,n.colno)}n.type===i.TOKEN_LEFT_PAREN&&(n=this.nextToken());for(var s=new r.NodeList(n.lineno,n.colno),o=new r.KeywordArgs(n.lineno,n.colno),a=!1;;){if(n=this.peekToken(),!t&&n.type===i.TOKEN_RIGHT_PAREN){this.nextToken();break}if(t&&n.type===i.TOKEN_BLOCK_END)break;if(a&&!this.skip(i.TOKEN_COMMA))this.fail("parseSignature: expected comma after expression",n.lineno,n.colno);else{var l=this.parseExpression();this.skipValue(i.TOKEN_OPERATOR,"=")?o.addChild(new r.Pair(l.lineno,l.colno,l,this.parseExpression())):s.addChild(l)}a=!0}return o.children.length&&s.addChild(o),s},parseUntilBlocks:function(){var e=this.breakOnBlocks;this.breakOnBlocks=o.toArray(arguments);var t=this.parse();return this.breakOnBlocks=e,t},parseNodes:function(){for(var e,t=[];e=this.nextToken();)if(e.type===i.TOKEN_DATA){var n=e.value,s=this.peekToken(),o=s&&s.value;this.dropLeadingWhitespace&&(n=n.replace(/^\s*/,""),this.dropLeadingWhitespace=!1),s&&s.type===i.TOKEN_BLOCK_START&&"-"===o.charAt(o.length-1)&&(n=n.replace(/\s*$/,"")),t.push(new r.Output(e.lineno,e.colno,[new r.TemplateData(e.lineno,e.colno,n)]))}else if(e.type===i.TOKEN_BLOCK_START){var a=this.parseStatement();if(!a)break;t.push(a)}else if(e.type===i.TOKEN_VARIABLE_START){var l=this.parseExpression();this.advanceAfterVariableEnd(),t.push(new r.Output(e.lineno,e.colno,[l]))}else e.type!==i.TOKEN_COMMENT&&this.fail("Unexpected token at top-level: "+e.type,e.lineno,e.colno);return t},parse:function(){return new r.NodeList(0,0,this.parseNodes())},parseAsRoot:function(){return new r.Root(0,0,this.parseNodes())}});e.exports={parse:function(e,t,n){var r=new a(i.lex(e,n));return void 0!==t&&(r.extensions=t),r.parseAsRoot()}}},function(e,t,n){"use strict";function i(e,t,n,i){return{type:e,value:t,lineno:n,colno:i}}function r(e,t){this.str=e,this.index=0,this.len=e.length,this.lineno=0,this.colno=0,this.in_code=!1,t=t||{};var n=t.tags||{};this.tags={BLOCK_START:n.blockStart||c,BLOCK_END:n.blockEnd||h,VARIABLE_START:n.variableStart||u,VARIABLE_END:n.variableEnd||p,COMMENT_START:n.commentStart||f,COMMENT_END:n.commentEnd||m},this.trimBlocks=!!t.trimBlocks,this.lstripBlocks=!!t.lstripBlocks}var s=n(1),o=" \n \r ",a="()[]{}%*-+~/#,:|.<>=!",l="0123456789",c="{%",h="%}",u="{{",p="}}",f="{#",m="#}",d="string",v="whitespace",g="data",y="block-start",k="block-end",x="variable-start",b="variable-end",E="comment",w="left-paren",T="right-paren",L="left-bracket",_="right-bracket",O="left-curly",A="right-curly",S="operator",N="comma",C="colon",B="tilde",F="pipe",K="int",R="float",I="boolean",M="none",P="symbol",D="special",V="regex";r.prototype.nextToken=function(){var e,t=this.lineno,n=this.colno;if(this.in_code){var r=this.current();if(this.is_finished())return null;if('"'===r||"'"===r)return i(d,this.parseString(r),t,n);if(e=this._extract(o))return i(v,e,t,n);if((e=this._extractString(this.tags.BLOCK_END))||(e=this._extractString("-"+this.tags.BLOCK_END)))return this.in_code=!1,this.trimBlocks&&(r=this.current(),"\n"===r?this.forward():"\r"===r&&(this.forward(),r=this.current(),"\n"===r?this.forward():this.back())),i(k,e,t,n);if(e=this._extractString(this.tags.VARIABLE_END))return this.in_code=!1,i(b,e,t,n);if("r"===r&&"/"===this.str.charAt(this.index+1)){this.forwardN(2);for(var c="";!this.is_finished();){if("/"===this.current()&&"\\"!==this.previous()){this.forward();break}c+=this.current(),this.forward()}for(var h=["g","i","m","y"],u="";!this.is_finished();){var p=-1!==h.indexOf(this.current());if(!p)break;u+=this.current(),this.forward()}return i(V,{body:c,flags:u},t,n)}if(-1!==a.indexOf(r)){this.forward();var f,m=["==","!=","<=",">=","//","**"],D=r+this.current();switch(-1!==s.indexOf(m,D)&&(this.forward(),r=D),r){case"(":f=w;break;case")":f=T;break;case"[":f=L;break;case"]":f=_;break;case"{":f=O;break;case"}":f=A;break;case",":f=N;break;case":":f=C;break;case"~":f=B;break;case"|":f=F;break;default:f=S}return i(f,r,t,n)}if(e=this._extractUntil(o+a),e.match(/^[-+]?[0-9]+$/)){if("."===this.current()){this.forward();var j=this._extract(l);return i(R,e+"."+j,t,n)}return i(K,e,t,n)}if(e.match(/^(true|false)$/))return i(I,e,t,n);if("none"===e)return i(M,e,t,n);if(e)return i(P,e,t,n);throw new Error("Unexpected value while parsing: "+e)}var U=this.tags.BLOCK_START.charAt(0)+this.tags.VARIABLE_START.charAt(0)+this.tags.COMMENT_START.charAt(0)+this.tags.COMMENT_END.charAt(0);if(this.is_finished())return null;if((e=this._extractString(this.tags.BLOCK_START+"-"))||(e=this._extractString(this.tags.BLOCK_START)))return this.in_code=!0,i(y,e,t,n);if(e=this._extractString(this.tags.VARIABLE_START))return this.in_code=!0,i(x,e,t,n);e="";var W,G=!1;for(this._matches(this.tags.COMMENT_START)&&(G=!0,e=this._extractString(this.tags.COMMENT_START));null!==(W=this._extractUntil(U));){if(e+=W,(this._matches(this.tags.BLOCK_START)||this._matches(this.tags.VARIABLE_START)||this._matches(this.tags.COMMENT_START))&&!G){if(this.lstripBlocks&&this._matches(this.tags.BLOCK_START)&&this.colno>0&&this.colno<=e.length){var Y=e.slice(-this.colno);if(/^\s+$/.test(Y)&&(e=e.slice(0,-this.colno),!e.length))return this.nextToken()}break}if(this._matches(this.tags.COMMENT_END)){if(!G)throw new Error("unexpected end of comment");e+=this._extractString(this.tags.COMMENT_END);break}e+=this.current(),this.forward()}if(null===W&&G)throw new Error("expected end of comment, got end of file");return i(G?E:g,e,t,n)},r.prototype.parseString=function(e){this.forward();for(var t="";!this.is_finished()&&this.current()!==e;){var n=this.current();if("\\"===n){switch(this.forward(),this.current()){case"n":t+="\n";break;case"t":t+=" ";break;case"r":t+="\r";break;default:t+=this.current()}this.forward()}else t+=n,this.forward()}return this.forward(),t},r.prototype._matches=function(e){if(this.index+e.length>this.len)return null;var t=this.str.slice(this.index,this.index+e.length);return t===e},r.prototype._extractString=function(e){return this._matches(e)?(this.index+=e.length,e):null},r.prototype._extractUntil=function(e){return this._extractMatching(!0,e||"")},r.prototype._extract=function(e){return this._extractMatching(!1,e)},r.prototype._extractMatching=function(e,t){if(this.is_finished())return null;var n=t.indexOf(this.current());if(e&&-1===n||!e&&-1!==n){var i=this.current();this.forward();for(var r=t.indexOf(this.current());(e&&-1===r||!e&&-1!==r)&&!this.is_finished();)i+=this.current(),this.forward(),r=t.indexOf(this.current());return i}return""},r.prototype._extractRegex=function(e){var t=this.currentStr().match(e);return t?(this.forwardN(t[0].length),t):null},r.prototype.is_finished=function(){return this.index>=this.len},r.prototype.forwardN=function(e){for(var t=0;e>t;t++)this.forward()},r.prototype.forward=function(){this.index++,"\n"===this.previous()?(this.lineno++,this.colno=0):this.colno++},r.prototype.backN=function(e){for(var t=0;e>t;t++)this.back()},r.prototype.back=function(){if(this.index--,"\n"===this.current()){this.lineno--;var e=this.src.lastIndexOf("\n",this.index-1);-1===e?this.colno=this.index:this.colno=this.index-e}else this.colno--},r.prototype.current=function(){return this.is_finished()?"":this.str.charAt(this.index)},r.prototype.currentStr=function(){return this.is_finished()?"":this.str.substr(this.index)},r.prototype.previous=function(){return this.str.charAt(this.index-1)},e.exports={lex:function(e,t){return new r(e,t)},TOKEN_STRING:d,TOKEN_WHITESPACE:v,TOKEN_DATA:g,TOKEN_BLOCK_START:y,TOKEN_BLOCK_END:k,TOKEN_VARIABLE_START:x,TOKEN_VARIABLE_END:b,TOKEN_COMMENT:E,TOKEN_LEFT_PAREN:w,TOKEN_RIGHT_PAREN:T,TOKEN_LEFT_BRACKET:L,TOKEN_RIGHT_BRACKET:_,TOKEN_LEFT_CURLY:O,TOKEN_RIGHT_CURLY:A,TOKEN_OPERATOR:S,TOKEN_COMMA:N,TOKEN_COLON:C,TOKEN_TILDE:B,TOKEN_PIPE:F,TOKEN_INT:K,TOKEN_FLOAT:R,TOKEN_BOOLEAN:I,TOKEN_NONE:M,TOKEN_SYMBOL:P,TOKEN_SPECIAL:D,TOKEN_REGEX:V}},function(e,t,n){(function(t){"use strict";function i(e,t,n){e instanceof t&&n.push(e),e instanceof a&&e.findAll(t,n)}function r(e,n){function i(e,n,i){for(var r=e.split("\n"),s=0;s0||!i))for(var o=0;n>o;o++)t.stdout.write(" ");s===r.length-1?t.stdout.write(r[s]):t.stdout.write(r[s]+"\n")}}if(n=n||0,i(e.typename+": ",n),e instanceof c)i("\n"),s.each(e.children,function(e){r(e,n+2)});else if(e instanceof re)i(e.extName+"."+e.prop),i("\n"),e.args&&r(e.args,n+2),e.contentArgs&&s.each(e.contentArgs,function(e){r(e,n+2)});else{var o=null,l=null;if(e.iterFields(function(e,t){e instanceof a?(o=o||{},o[t]=e):(l=l||{},l[t]=e)}),l?i(JSON.stringify(l,null,2)+"\n",null,!0):i("\n"),o)for(var h in o)r(o[h],n+2)}}var s=n(1),o=n(6),a=o.extend("Node",{init:function(e,t){this.lineno=e,this.colno=t;for(var n=this.fields,i=0,r=n.length;r>i;i++){var s=n[i],o=arguments[i+2];void 0===o&&(o=null),this[s]=o}},findAll:function(e,t){t=t||[];var n,r;if(this instanceof c){var s=this.children;for(n=0,r=s.length;r>n;n++)i(s[n],e,t)}else{var o=this.fields;for(n=0,r=o.length;r>n;n++)i(this[o[n]],e,t)}return t},iterFields:function(e){s.each(this.fields,function(t){e(this[t],t)},this)}}),l=a.extend("Value",{fields:["value"]}),c=a.extend("NodeList",{fields:["children"],init:function(e,t,n){this.parent(e,t,n||[])},addChild:function(e){this.children.push(e)}}),h=c.extend("Root"),u=l.extend("Literal"),p=l.extend("Symbol"),f=c.extend("Group"),m=c.extend("Array"),d=a.extend("Pair",{fields:["key","value"]}),v=c.extend("Dict"),g=a.extend("LookupVal",{fields:["target","val"]}),y=a.extend("If",{fields:["cond","body","else_"]}),k=y.extend("IfAsync"),x=a.extend("InlineIf",{fields:["cond","body","else_"]}),b=a.extend("For",{fields:["arr","name","body","else_"]}),E=b.extend("AsyncEach"),w=b.extend("AsyncAll"),T=a.extend("Macro",{fields:["name","args","body"]}),L=T.extend("Caller"),_=a.extend("Import",{fields:["template","target","withContext"]}),O=a.extend("FromImport",{fields:["template","names","withContext"],init:function(e,t,n,i,r){this.parent(e,t,n,i||new c,r)}}),A=a.extend("FunCall",{fields:["name","args"]}),S=A.extend("Filter"),N=S.extend("FilterAsync",{fields:["name","args","symbol"]}),C=v.extend("KeywordArgs"),B=a.extend("Block",{fields:["name","body"]}),F=a.extend("Super",{fields:["blockName","symbol"]}),K=a.extend("TemplateRef",{fields:["template"]}),R=K.extend("Extends"),I=a.extend("Include",{fields:["template","ignoreMissing"]}),M=a.extend("Set",{fields:["targets","value"]}),P=c.extend("Output"),D=u.extend("TemplateData"),V=a.extend("UnaryOp",{fields:["target"]}),j=a.extend("BinOp",{fields:["left","right"]}),U=j.extend("In"),W=j.extend("Or"),G=j.extend("And"),Y=V.extend("Not"),H=j.extend("Add"),$=j.extend("Concat"),z=j.extend("Sub"),X=j.extend("Mul"),q=j.extend("Div"),J=j.extend("FloorDiv"),Q=j.extend("Mod"),Z=j.extend("Pow"),ee=V.extend("Neg"),te=V.extend("Pos"),ne=a.extend("Compare",{fields:["expr","ops"]}),ie=a.extend("CompareOperand",{fields:["expr","type"]}),re=a.extend("CallExtension",{fields:["extName","prop","args","contentArgs"],init:function(e,t,n,i){this.extName=e._name||e,this.prop=t,this.args=n||new c,this.contentArgs=i||[],this.autoescape=e.autoescape}}),se=re.extend("CallExtensionAsync");e.exports={Node:a,Root:h,NodeList:c,Value:l,Literal:u,Symbol:p,Group:f,Array:m,Pair:d,Dict:v,Output:P,TemplateData:D,If:y,IfAsync:k,InlineIf:x,For:b,AsyncEach:E,AsyncAll:w,Macro:T,Caller:L,Import:_,FromImport:O,FunCall:A,Filter:S,FilterAsync:N,KeywordArgs:C,Block:B,Super:F,Extends:R,Include:I,Set:M,LookupVal:g,BinOp:j,In:U,Or:W,And:G,Not:Y,Add:H,Concat:$,Sub:z,Mul:X,Div:q,FloorDiv:J,Mod:Q,Pow:Z,Neg:ee,Pos:te,Compare:ne,CompareOperand:ie,CallExtension:re,CallExtensionAsync:se,printNodes:r}}).call(t,n(3))},function(e,t,n){"use strict";function i(){return"hole_"+d++}function r(e,t){for(var n=null,i=0;ie.length){i=Array.prototype.slice.call(arguments,0,e.length);var c=Array.prototype.slice.call(arguments,i.length,a);for(r=0;ri;i++)s.push(n);r.push(s)}return r},capitalize:function(e){e=i(e,"");var t=e.toLowerCase();return s.copySafeness(e,t.charAt(0).toUpperCase()+t.slice(1))},center:function(e,t){if(e=i(e,""),t=t||80,e.length>=t)return e;var n=t-e.length,o=r.repeat(" ",n/2-n%2),a=r.repeat(" ",n/2);return s.copySafeness(e,o+e+a)},"default":function(e,t,n){return n?e?e:t:void 0!==e?e:t},dictsort:function(e,t,n){if(!r.isObject(e))throw new r.TemplateError("dictsort filter: val must be an object");var i=[];for(var s in e)i.push([s,e[s]]);var o;if(void 0===n||"key"===n)o=0;else{if("value"!==n)throw new r.TemplateError("dictsort filter: You can only sort by either key or value");o=1}return i.sort(function(e,n){var i=e[o],s=n[o];return t||(r.isString(i)&&(i=i.toUpperCase()),r.isString(s)&&(s=s.toUpperCase())),i>s?1:i===s?0:-1}),i},dump:function(e){return JSON.stringify(e)},escape:function(e){return"string"==typeof e||e instanceof s.SafeString?r.escape(e):e},safe:function(e){return s.markSafe(e)},first:function(e){return e[0]},groupby:function(e,t){return r.groupBy(e,t)},indent:function(e,t,n){if(e=i(e,""),""===e)return"";t=t||4;for(var o="",a=e.split("\n"),l=r.repeat(" ",t),c=0;c-1&&(-1===i||i>c);)o+=e.substring(l,a)+n,
+l=a+t.length,c++,a=e.indexOf(t,l);return la;a++){var l=s+a*i;r>a&&s++;var c=s+(a+1)*i,h=e.slice(l,c);n&&a>=r&&h.push(n),o.push(h)}return o},sort:s.makeMacro(["value","reverse","case_sensitive","attribute"],[],function(e,t,n,i){return e=r.map(e,function(e){return e}),e.sort(function(e,s){var o,a;return i?(o=e[i],a=s[i]):(o=e,a=s),!n&&r.isString(o)&&r.isString(a)&&(o=o.toLowerCase(),a=a.toLowerCase()),a>o?t?1:-1:o>a?t?-1:1:0}),e}),string:function(e){return s.copySafeness(e,e)},striptags:function(e,t){e=i(e,""),t=t||!1;var n=/<\/?([a-z][a-z0-9]*)\b[^>]*>|/gi,r=o.trim(e.replace(n,"")),a="";return a=t?r.replace(/^ +| +$/gm,"").replace(/ +/g," ").replace(/(\r\n)/g,"\n").replace(/\n\n\n+/g,"\n\n"):r.replace(/\s+/gi," "),s.copySafeness(e,a)},title:function(e){e=i(e,"");for(var t=e.split(" "),n=0;n"+c.substr(0,t)+"":a.test(c)?'"+c.substr(0,t)+"":s.test(c)?''+c+"":l.test(c)?'"+c.substr(0,t)+"":e});return c.join(" ")},wordcount:function(e){e=i(e,"");var t=e?e.match(/\w+/g):null;return t?t.length:null},"float":function(e,t){var n=parseFloat(e);return isNaN(n)?t:n},"int":function(e,t){var n=parseInt(e,10);return isNaN(n)?t:n}};o.d=o["default"],o.e=o.escape,e.exports=o},function(e,t,n){"use strict";var i=n(15),r=n(16),s=i.extend({init:function(e,t){this.baseURL=e||".",t=t||{},this.useCache=!!t.useCache,this.async=!!t.async},resolve:function(e,t){throw new Error("relative templates not support in the browser yet")},getSource:function(e,t){var n,i=this.useCache;return this.fetch(this.baseURL+"/"+e,function(r,s){if(r)if(t)t(r.content);else{if(404!==r.status)throw r.content;n=null}else n={src:s,path:e,noCache:!i},t&&t(null,n)}),n},fetch:function(e,t){var n,i=!0;window.XMLHttpRequest?n=new XMLHttpRequest:window.ActiveXObject&&(n=new ActiveXObject("Microsoft.XMLHTTP")),n.onreadystatechange=function(){4===n.readyState&&i&&(i=!1,0===n.status||200===n.status?t(null,n.responseText):t({status:n.status,content:n.responseText}))},e+=(-1===e.indexOf("?")?"?":"&")+"s="+(new Date).getTime(),n.open("GET",e,this.async),n.send()}});e.exports={WebLoader:s,PrecompiledLoader:r}},function(e,t,n){"use strict";var i=n(3),r=n(6),s=n(1),o=r.extend({on:function(e,t){this.listeners=this.listeners||{},this.listeners[e]=this.listeners[e]||[],this.listeners[e].push(t)},emit:function(e){var t=Array.prototype.slice.call(arguments,1);this.listeners&&this.listeners[e]&&s.each(this.listeners[e],function(e){e.apply(null,t)})},resolve:function(e,t){return i.resolve(i.dirname(e),t)},isRelative:function(e){return 0===e.indexOf("./")||0===e.indexOf("../")}});e.exports=o},function(e,t,n){"use strict";var i=n(15),r=i.extend({init:function(e){this.precompiled=e||{}},getSource:function(e){return this.precompiled[e]?{src:{type:"code",obj:this.precompiled[e]},path:e}:null}});e.exports=r},function(e,t){"use strict";function n(e){var t=-1;return{current:null,reset:function(){t=-1,this.current=null},next:function(){return t++,t>=e.length&&(t=0),this.current=e[t],this.current}}}function i(e){e=e||",";var t=!0;return function(){var n=t?"":e;return t=!1,n}}function r(){return{range:function(e,t,n){t?n||(n=1):(t=e,e=0,n=1);var i,r=[];if(n>0)for(i=e;t>i;i+=n)r.push(i);else for(i=e;i>t;i+=n)r.push(i);return r},cycler:function(){return n(Array.prototype.slice.call(arguments))},joiner:function(e){return i(e)}}}e.exports=r},function(e,t){function n(){"use strict";var e=this.runtime,t=this.lib,n=e.contextOrFrameLookup;e.contextOrFrameLookup=function(e,t,i){var r=n.apply(this,arguments);if(void 0===r)switch(i){case"True":return!0;case"False":return!1;case"None":return null}return r};var i=e.memberLookup,r={pop:function(e){if(void 0===e)return this.pop();if(e>=this.length||0>e)throw new Error("KeyError");return this.splice(e,1)},remove:function(e){for(var t=0;t
{% for request in session.requests %}
- {% include "request.html" %}
+ {% include "views/request.html" %}
{% endfor %}
No certificate signing requests to sign! You can submit a certificate signing request by:
@@ -31,7 +31,7 @@
{% for certificate in session.signed | sort | reverse %}
- {% include "signed.html" %}
+ {% include "views/signed.html" %}
{% endfor %}
diff --git a/certidude/static/configuration.html b/certidude/static/views/configuration.html
similarity index 92%
rename from certidude/static/configuration.html
rename to certidude/static/views/configuration.html
index b9a57b1..9ea26af 100644
--- a/certidude/static/configuration.html
+++ b/certidude/static/views/configuration.html
@@ -10,7 +10,7 @@
attaches attribute
something
diff --git a/certidude/static/error.html b/certidude/static/views/error.html
similarity index 100%
rename from certidude/static/error.html
rename to certidude/static/views/error.html
diff --git a/certidude/static/logentry.html b/certidude/static/views/logentry.html
similarity index 100%
rename from certidude/static/logentry.html
rename to certidude/static/views/logentry.html
diff --git a/certidude/static/request.html b/certidude/static/views/request.html
similarity index 100%
rename from certidude/static/request.html
rename to certidude/static/views/request.html
diff --git a/certidude/static/signed.html b/certidude/static/views/signed.html
similarity index 94%
rename from certidude/static/signed.html
rename to certidude/static/views/signed.html
index df28fb5..a1a7178 100644
--- a/certidude/static/signed.html
+++ b/certidude/static/views/signed.html
@@ -32,11 +32,11 @@
- {% include 'status.html' %}
+ {% include 'views/status.html' %}
diff --git a/certidude/static/status.html b/certidude/static/views/status.html
similarity index 100%
rename from certidude/static/status.html
rename to certidude/static/views/status.html
diff --git a/certidude/static/tagtypes.html b/certidude/static/views/tagtypes.html
similarity index 100%
rename from certidude/static/tagtypes.html
rename to certidude/static/views/tagtypes.html