1 (function (GCN) {
  2 
  3 	'use strict';
  4 
  5 	/**
  6 	 * Only grows, never shrinks.
  7 	 * @private
  8 	 * @type {number}
  9 	 */
 10 	var uniqueIdCounter = 0;
 11 
 12 	/**
 13 	 * Generates a unique id with an optional prefix.
 14 	 *
 15 	 * The returned value is only unique among other returned values,
 16 	 * not globally.
 17 	 *
 18 	 * @public
 19 	 * @param {string}
 20 	 *        Optional prefix for the id to be generated.
 21 	 * @return {string}
 22 	 *        Never the same string more than once.
 23 	 */
 24 	function uniqueId(prefix) {
 25 		return (prefix || '') + (++uniqueIdCounter);
 26 	}
 27 
 28 	function escapePropertyName(name) {
 29 		return name.replace(/\./g, '\\.');
 30 	}
 31 
 32 	/**
 33 	 * A regular expression to identify executable script tags.
 34 	 *
 35 	 * @type {RegExp}
 36 	 */
 37 	var rgxpScriptType = /\/(java|ecma)script/i;
 38 
 39 	/**
 40 	 * A regular expression to find script tags.
 41 	 *
 42 	 * @type {RegExp}
 43 	 */
 44 	var rgxpScriptTag = new RegExp('<script(\\s[^>]*?)?>', 'ig');
 45 
 46 	/**
 47 	 * A regular expression to find script types.
 48 	 *
 49 	 * @type {RegExp}
 50 	 */
 51 	var rgxpType = new RegExp(
 52 		' type\\s*=\\s*'
 53 			+ '[\\"\\\']'
 54 			+ '([^\\"\\\']*[^\\s][^\\"\\\']*)'
 55 			+ '[\\"\\\']',
 56 		'i'
 57 	);
 58 
 59 	var rand = Math.random().toString().replace('.', '');
 60 
 61 	/**
 62 	 * Places sentinal strings in front of every executable script tag.
 63 	 *
 64 	 * @param {string} html HTML markup
 65 	 * @return {string} HTML string with marked <script> tags.
 66 	 */
 67 	function markScriptTagLocations(html) {
 68 		var i = 0;
 69 		return html.replace(rgxpScriptTag, function (str, substr, offset) {
 70 			var type = substr && substr.match(rgxpType);
 71 			if (!type || rgxpScriptType.test(type)) {
 72 				return rand + (i++) + str;
 73 			}
 74 			return str;
 75 		});
 76 	}
 77 
 78 	/**
 79 	 * Replaces the type attribute of <script> tags with a value that will
 80 	 * protect them from being specially handled by jQuery.
 81 	 *
 82 	 * @param {string} html Markup
 83 	 * @return {string} Markup with <script> tags protected from jQuery.
 84 	 */
 85 	function protectScriptTags(html, $scripts) {
 86 		var i;
 87 		var $script;
 88 		var type;
 89 		for (i = 0; i < $scripts.length; i++) {
 90 			$script = $scripts.eq(i).clone();
 91 			type = $script.attr('type');
 92 			if (!type || rgxpScriptType.test(type)) {
 93 				$script.attr('type', rand).attr('data-origtype', type);
 94 				html = html.replace(rand + i, $script[0].outerHTML);
 95 			}
 96 		}
 97 		return html;
 98 	}
 99 
100 	/**
101 	 * Restores the type attribute for <script> tags that have been processed
102 	 * via protectScriptTags().
103 	 *
104 	 * @param {jQuery.<HTMLElement>} $element Root HTMLElement in which to
105 	 *                                        restore <script> tags.
106 	 */
107 	function restoreScriptTagTypes($element) {
108 		var $scripts = $element.find('script[type="' + rand + '"]');
109 		var $script;
110 		var orig;
111 		var i;
112 		for (i = 0; i < $scripts.length; i++) {
113 			$script = $scripts.eq(i);
114 			$script.removeClass(rand + i);
115 			orig = $script.attr('data-origtype');
116 			if (typeof orig === 'string') {
117 				$script.attr('type', orig).removeAttr('data-origtype');
118 			} else {
119 				$script.removeAttr('type');
120 			}
121 		}
122 	}
123 
124 	/**
125 	 * Joins the innerHTML of multiple elements.
126 	 *
127 	 * @param {jQuery.<HTMLElement>} $elements
128 	 */
129 	function joinContents($elements) {
130 		var contents = '';
131 		$elements.each(function () {
132 			contents += jQuery(this).html();
133 		});
134 		return contents;
135 	}
136 
137 	/**
138 	 * Inserts the inner HTML of the given HTML markup while preserving
139 	 * <script> tags, and still allowing jQuery to execute them.
140 	 *
141 	 * @param {jQuery.<HTMLElement>} $element
142 	 * @param {string} html
143 	 */
144 	function insertInnerHTMLWithScriptTags($element, html) {
145 		if (!rgxpScriptTag.test(html)) {
146 			$element.html(jQuery(html).contents());
147 			return;
148 		}
149 		var marked = markScriptTagLocations(html);
150 		var $scripts = jQuery(html).filter('script');
151 		var $html = jQuery(marked);
152 		var contents = joinContents($html.filter(':not(script)'));
153 		contents = protectScriptTags(contents, $scripts);
154 		$element.html(contents).append($scripts);
155 		restoreScriptTagTypes($element);
156 	}
157 
158 	GCN.uniqueId = uniqueId;
159 	GCN.escapePropertyName = escapePropertyName;
160 	GCN.insertInnerHTMLWithScriptTags = insertInnerHTMLWithScriptTags;
161 
162 }(GCN));
163