text: /* global _ */
  (function () {
  	'use strict';
  
  	/* jshint ignore:start */
  	// Underscore's Template Module
  	// Courtesy of underscorejs.org
  	var _ = (function (_) {
  		_.defaults = function (object) {
  			if (!object) {
  				return object;
  			}
  			for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
  				var iterable = arguments[argsIndex];
  				if (iterable) {
  					for (var key in iterable) {
  						if (object[key] == null) {
  							object[key] = iterable[key];
  						}
  					}
  				}
  			}
  			return object;
  		}
  
  		// By default, Underscore uses ERB-style template delimiters, change the
  		// following template settings to use alternative delimiters.
  		_.templateSettings = {
  			evaluate    : /<%([\s\S]+?)%>/g,
  			interpolate : /<%=([\s\S]+?)%>/g,
  			escape      : /<%-([\s\S]+?)%>/g
  		};
  
  		// When customizing `templateSettings`, if you don't want to define an
  		// interpolation, evaluation or escaping regex, we need one that is
  		// guaranteed not to match.
  		var noMatch = /(.)^/;
  
  		// Certain characters need to be escaped so that they can be put into a
  		// string literal.
  		var escapes = {
  			"'":      "'",
  			'\\':     '\\',
  			'\r':     'r',
  			'\n':     'n',
  			'\t':     't',
  			'\u2028': 'u2028',
  			'\u2029': 'u2029'
  		};
  
  		var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
  
  		// JavaScript micro-templating, similar to John Resig's implementation.
  		// Underscore templating handles arbitrary delimiters, preserves whitespace,
  		// and correctly escapes quotes within interpolated code.
  		_.template = function(text, data, settings) {
  			var render;
  			settings = _.defaults({}, settings, _.templateSettings);
  
  			// Combine delimiters into one regular expression via alternation.
  			var matcher = new RegExp([
  				(settings.escape || noMatch).source,
  				(settings.interpolate || noMatch).source,
  				(settings.evaluate || noMatch).source
  			].join('|') + '|$', 'g');
  
  			// Compile the template source, escaping string literals appropriately.
  			var index = 0;
  			var source = "__p+='";
  			text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
  				source += text.slice(index, offset)
  					.replace(escaper, function(match) { return '\\' + escapes[match]; });
  
  				if (escape) {
  					source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
  				}
  				if (interpolate) {
  					source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
  				}
  				if (evaluate) {
  					source += "';\n" + evaluate + "\n__p+='";
  				}
  				index = offset + match.length;
  				return match;
  			});
  			source += "';\n";
  
  			// If a variable is not specified, place data values in local scope.
  			if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
  
  			source = "var __t,__p='',__j=Array.prototype.join," +
  				"print=function(){__p+=__j.call(arguments,'');};\n" +
  				source + "return __p;\n";
  
  			try {
  				render = new Function(settings.variable || 'obj', '_', source);
  			} catch (e) {
  				e.source = source;
  				throw e;
  			}
  
  			if (data) return render(data, _);
  			var template = function(data) {
  				return render.call(this, data, _);
  			};
  
  			// Provide the compiled function source as a convenience for precompilation.
  			template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
  
  			return template;
  		};
  
  		return _;
  	})({});
  
  	if (location.hostname === 'bookmarkmvc.com') {
  		(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  		(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  		m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  		})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
  		ga('create', 'UA-31081062-1', 'auto');
  		ga('send', 'pageview');
  	}
  	/* jshint ignore:end */
  
  	function redirect() {
  		if (location.hostname === 'tastejs.github.io') {
  			location.href = location.href.replace('tastejs.github.io/bookmarkmvc', 'bookmarkmvc.com');
  		}
  	}
  
  	function findRoot() {
  		var base = location.href.indexOf('examples/');
  		return location.href.substr(0, base);
  	}
  
  	function getFile(file, callback) {
  		if (!location.host) {
  			return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
  		}
  
  		var xhr = new XMLHttpRequest();
  
  		xhr.open('GET', findRoot() + file, true);
  		xhr.send();
  
  		xhr.onload = function () {
  			if (xhr.status === 200 && callback) {
  				callback(xhr.responseText);
  			}
  		};
  	}
  
  	function Learn(learnJSON, config) {
  		if (!(this instanceof Learn)) {
  			return new Learn(learnJSON, config);
  		}
  
  		var template, framework;
  
  		if (typeof learnJSON !== 'object') {
  			try {
  				learnJSON = JSON.parse(learnJSON);
  			} catch (e) {
  				return;
  			}
  		}
  
  		if (config) {
  			template = config.template;
  			framework = config.framework;
  		}
  
  		if (!template && learnJSON.templates) {
  			template = learnJSON.templates.bookmarkmvc;
  		}
  
  		if (!framework && document.querySelector('[data-framework]')) {
  			framework = document.querySelector('[data-framework]').dataset.framework;
  		}
  
  		this.template = template;
  
  		if (learnJSON.backend) {
  			this.frameworkJSON = learnJSON.backend;
  			this.frameworkJSON.issueLabel = framework;
  			this.append({
  				backend: true
  			});
  		} else if (learnJSON[framework]) {
  			this.frameworkJSON = learnJSON[framework];
  			this.frameworkJSON.issueLabel = framework;
  			this.append();
  		}
  
  		this.fetchIssueCount();
  	}
  
  	Learn.prototype.append = function (opts) {
  		var aside = document.createElement('aside');
  		aside.innerHTML = _.template(this.template, this.frameworkJSON);
  		aside.className = 'learn';
  
  		if (opts && opts.backend) {
  			// Remove demo link
  			var sourceLinks = aside.querySelector('.source-links');
  			var heading = sourceLinks.firstElementChild;
  			var sourceLink = sourceLinks.lastElementChild;
  			// Correct link path
  			var href = sourceLink.getAttribute('href');
  			sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http')));
  			sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML;
  		} else {
  			// Localize demo links
  			var demoLinks = aside.querySelectorAll('.demo-link');
  			Array.prototype.forEach.call(demoLinks, function (demoLink) {
  				if (demoLink.getAttribute('href').substr(0, 4) !== 'http') {
  					demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
  				}
  			});
  		}
  
  		document.body.className = (document.body.className + ' learn-bar').trim();
  		document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
  	};
  
  	Learn.prototype.fetchIssueCount = function () {
  		var issueLink = document.getElementById('issue-count-link');
  		if (issueLink) {
  			var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
  			var xhr = new XMLHttpRequest();
  			xhr.open('GET', url, true);
  			xhr.onload = function (e) {
  				var parsedResponse = JSON.parse(e.target.responseText);
  				if (parsedResponse instanceof Array) {
  					var count = parsedResponse.length;
  					if (count !== 0) {
  						issueLink.innerHTML = 'This app has ' + count + ' open issues';
  						document.getElementById('issue-count').style.display = 'inline';
  					}
  				}
  			};
  			xhr.send();
  		}
  	};
  
  	redirect();
  	getFile('learn.json', Learn);
  })();
  