text: // NOTE: textAngularVersion must match the Gruntfile.js 'setVersion' task.... and have format v/d+./d+./d+
  var textAngularVersion = 'v1.5.12';   // This is automatically updated during the build process to the current release!
  
  
  // IE version detection - http://stackoverflow.com/questions/4169160/javascript-ie-detection-why-not-use-simple-conditional-comments
  // We need this as IE sometimes plays funny tricks with the contenteditable.
  // ----------------------------------------------------------
  // If you're not in IE (or IE version is less than 5) then:
  // ie === undefined
  // If you're in IE (>=5) then you can determine which version:
  // ie === 7; // IE7
  // Thus, to detect IE:
  // if (ie) {}
  // And to detect the version:
  // ie === 6 // IE6
  // ie > 7 // IE8, IE9, IE10 ...
  // ie < 9 // Anything less than IE9
  // ----------------------------------------------------------
  /* istanbul ignore next: untestable browser check */
  var _browserDetect = {
  	ie: (function(){
  		var undef,
  			v = 3,
  			div = document.createElement('div'),
  			all = div.getElementsByTagName('i');
  
  		while (
  			div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
  			all[0]
  		);
  
  		return v > 4 ? v : undef;
  	}()),
  	webkit: /AppleWebKit\/([\d.]+)/i.test(navigator.userAgent),
  	isFirefox: navigator.userAgent.toLowerCase().indexOf('firefox') > -1
  };
  
  // Global to textAngular to measure performance where needed
  /* istanbul ignore next: untestable browser check */
  var performance = performance || {};
  /* istanbul ignore next: untestable browser check */
  performance.now = (function() {
  	return performance.now       ||
  		performance.mozNow    ||
  		performance.msNow     ||
  		performance.oNow      ||
  		performance.webkitNow ||
  		function() { return new Date().getTime(); };
  })();
  // usage is:
  // var t0 = performance.now();
  // doSomething();
  // var t1 = performance.now();
  // console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to do something!');
  //
  
  // turn html into pure text that shows visiblity
  function stripHtmlToText(html)
  {
  	var tmp = document.createElement("DIV");
  	tmp.innerHTML = html;
  	var res = tmp.textContent || tmp.innerText || '';
  	res.replace('\u200B', ''); // zero width space
  	res = res.trim();
  	return res;
  }
  // get html
  function getDomFromHtml(html)
  {
  	var tmp = document.createElement("DIV");
  	tmp.innerHTML = html;
  	return tmp;
  }
  
  
  // Global to textAngular REGEXP vars for block and list elements.
  
  var BLOCKELEMENTS = /^(address|article|aside|audio|blockquote|canvas|center|dd|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|noscript|ol|output|p|pre|section|table|tfoot|ul|video)$/i;
  var LISTELEMENTS = /^(ul|li|ol)$/i;
  // updated VALIDELEMENTS to include #text and span so that we can use nodeName instead of tagName
  var VALIDELEMENTS = /^(#text|span|address|article|aside|audio|blockquote|canvas|center|dd|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|noscript|ol|output|p|pre|section|table|tfoot|ul|video|li)$/i;
  
  
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Compatibility
  /* istanbul ignore next: trim shim for older browsers */
  if (!String.prototype.trim) {
  	String.prototype.trim = function () {
  		return this.replace(/^\s+|\s+$/g, '');
  	};
  }
  
  /*
  	Custom stylesheet for the placeholders rules.
  	Credit to: http://davidwalsh.name/add-rules-stylesheets
  */
  var sheet, addCSSRule, removeCSSRule, _addCSSRule, _removeCSSRule, _getRuleIndex;
  /* istanbul ignore else: IE <8 test*/
  if(_browserDetect.ie > 8 || _browserDetect.ie === undefined){
  	var _sheets = document.styleSheets;
  	/* istanbul ignore next: preference for stylesheet loaded externally */
  	for(var i = 0; i < _sheets.length; i++){
  		if(_sheets[i].media.length === 0 || _sheets[i].media.mediaText.match(/(all|screen)/ig)){
  			if(_sheets[i].href){
  				if(_sheets[i].href.match(/textangular\.(min\.|)css/ig)){
  					sheet = _sheets[i];
  					break;
  				}
  			}
  		}
  	}
  	/* istanbul ignore next: preference for stylesheet loaded externally */
  	if(!sheet){
  		// this sheet is used for the placeholders later on.
  		sheet = (function() {
  			// Create the <style> tag
  			var style = document.createElement("style");
  			/* istanbul ignore else : WebKit hack :( */
  			if(_browserDetect.webkit) style.appendChild(document.createTextNode(""));
  
  			// Add the <style> element to the page, add as first so the styles can be overridden by custom stylesheets
  			document.getElementsByTagName('head')[0].appendChild(style);
  
  			return style.sheet;
  		})();
  	}
  
  	// use as: addCSSRule("header", "float: left");
  	addCSSRule = function(selector, rules) {
  		return _addCSSRule(sheet, selector, rules);
  	};
  	_addCSSRule = function(_sheet, selector, rules){
  		var insertIndex;
  		var insertedRule;
  		// This order is important as IE 11 has both cssRules and rules but they have different lengths - cssRules is correct, rules gives an error in IE 11
  		/* istanbul ignore next: browser catches */
  		if(_sheet.cssRules) insertIndex = Math.max(_sheet.cssRules.length - 1, 0);
  		else if(_sheet.rules) insertIndex = Math.max(_sheet.rules.length - 1, 0);
  
  		/* istanbul ignore else: untestable IE option */
  		if(_sheet.insertRule) {
  			_sheet.insertRule(selector + "{" + rules + "}", insertIndex);
  		}
  		else {
  			_sheet.addRule(selector, rules, insertIndex);
  		}
  		/* istanbul ignore next: browser catches */
  		if(sheet.rules) insertedRule = sheet.rules[insertIndex];
  		else if(sheet.cssRules) insertedRule = sheet.cssRules[insertIndex];
  		// return the inserted stylesheet rule
  		return insertedRule;
  	};
  
  	_getRuleIndex = function(rule, rules) {
  		var i, ruleIndex;
  		for (i=0; i < rules.length; i++) {
  			/* istanbul ignore else: check for correct rule */
  			if (rules[i].cssText === rule.cssText) {
  				ruleIndex = i;
  				break;
  			}
  		}
  		return ruleIndex;
  	};
  
  	removeCSSRule = function(rule){
  		_removeCSSRule(sheet, rule);
  	};
  	/* istanbul ignore next: tests are browser specific */
  	_removeCSSRule = function(sheet, rule){
  		var rules = sheet.cssRules || sheet.rules;
  		if(!rules || rules.length === 0) return;
  		var ruleIndex = _getRuleIndex(rule, rules);
  		if(sheet.removeRule){
  			sheet.removeRule(ruleIndex);
  		}else{
  			sheet.deleteRule(ruleIndex);
  		}
  	};
  }
  