src/ztfy/myams/resources/js/ext/jquery-select2-3.4.5.js
changeset 111 8297a1050c90
parent 110 0bcdc4e0191e
child 112 60b20c7b83fc
--- a/src/ztfy/myams/resources/js/ext/jquery-select2-3.4.5.js	Fri Mar 27 15:55:13 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3374 +0,0 @@
-/*
- Copyright 2012 Igor Vaynberg
-
- Version: 3.4.5 Timestamp: Mon Nov  4 08:22:42 PST 2013
-
- This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
- General Public License version 2 (the "GPL License"). You may choose either license to govern your
- use of this software only upon the condition that you accept all of the terms of either the Apache
- License or the GPL License.
-
- You may obtain a copy of the Apache License and the GPL License at:
-
- http://www.apache.org/licenses/LICENSE-2.0
- http://www.gnu.org/licenses/gpl-2.0.html
-
- Unless required by applicable law or agreed to in writing, software distributed under the
- Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
- CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
- the specific language governing permissions and limitations under the Apache License and the GPL License.
- */
-(function ($) {
-	if (typeof $.fn.each2 == "undefined") {
-		$.extend($.fn, {
-			/*
-			 * 4-10 times faster .each replacement
-			 * use it carefully, as it overrides jQuery context of element on each iteration
-			 */
-			each2: function (c) {
-				var j = $([0]), i = -1, l = this.length;
-				while (
-					++i < l
-						&& (j.context = j[0] = this[i])
-						&& c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
-					);
-				return this;
-			}
-		});
-	}
-})(jQuery);
-
-(function ($, undefined) {
-	"use strict";
-	/*global document, window, jQuery, console */
-
-	if (window.Select2 !== undefined) {
-		return;
-	}
-
-	var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
-		lastMousePosition = {x: 0, y: 0}, $document, scrollBarDimensions,
-
-		KEY = {
-			TAB: 9,
-			ENTER: 13,
-			ESC: 27,
-			SPACE: 32,
-			LEFT: 37,
-			UP: 38,
-			RIGHT: 39,
-			DOWN: 40,
-			SHIFT: 16,
-			CTRL: 17,
-			ALT: 18,
-			PAGE_UP: 33,
-			PAGE_DOWN: 34,
-			HOME: 36,
-			END: 35,
-			BACKSPACE: 8,
-			DELETE: 46,
-			isArrow: function (k) {
-				k = k.which ? k.which : k;
-				switch (k) {
-					case KEY.LEFT:
-					case KEY.RIGHT:
-					case KEY.UP:
-					case KEY.DOWN:
-						return true;
-				}
-				return false;
-			},
-			isControl: function (e) {
-				var k = e.which;
-				switch (k) {
-					case KEY.SHIFT:
-					case KEY.CTRL:
-					case KEY.ALT:
-						return true;
-				}
-
-				if (e.metaKey) return true;
-
-				return false;
-			},
-			isFunctionKey: function (k) {
-				k = k.which ? k.which : k;
-				return k >= 112 && k <= 123;
-			}
-		},
-		MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>",
-
-		DIACRITICS = {"\u24B6": "A", "\uFF21": "A", "\u00C0": "A", "\u00C1": "A", "\u00C2": "A", "\u1EA6": "A", "\u1EA4": "A", "\u1EAA": "A", "\u1EA8": "A", "\u00C3": "A", "\u0100": "A", "\u0102": "A", "\u1EB0": "A", "\u1EAE": "A", "\u1EB4": "A", "\u1EB2": "A", "\u0226": "A", "\u01E0": "A", "\u00C4": "A", "\u01DE": "A", "\u1EA2": "A", "\u00C5": "A", "\u01FA": "A", "\u01CD": "A", "\u0200": "A", "\u0202": "A", "\u1EA0": "A", "\u1EAC": "A", "\u1EB6": "A", "\u1E00": "A", "\u0104": "A", "\u023A": "A", "\u2C6F": "A", "\uA732": "AA", "\u00C6": "AE", "\u01FC": "AE", "\u01E2": "AE", "\uA734": "AO", "\uA736": "AU", "\uA738": "AV", "\uA73A": "AV", "\uA73C": "AY", "\u24B7": "B", "\uFF22": "B", "\u1E02": "B", "\u1E04": "B", "\u1E06": "B", "\u0243": "B", "\u0182": "B", "\u0181": "B", "\u24B8": "C", "\uFF23": "C", "\u0106": "C", "\u0108": "C", "\u010A": "C", "\u010C": "C", "\u00C7": "C", "\u1E08": "C", "\u0187": "C", "\u023B": "C", "\uA73E": "C", "\u24B9": "D", "\uFF24": "D", "\u1E0A": "D", "\u010E": "D", "\u1E0C": "D", "\u1E10": "D", "\u1E12": "D", "\u1E0E": "D", "\u0110": "D", "\u018B": "D", "\u018A": "D", "\u0189": "D", "\uA779": "D", "\u01F1": "DZ", "\u01C4": "DZ", "\u01F2": "Dz", "\u01C5": "Dz", "\u24BA": "E", "\uFF25": "E", "\u00C8": "E", "\u00C9": "E", "\u00CA": "E", "\u1EC0": "E", "\u1EBE": "E", "\u1EC4": "E", "\u1EC2": "E", "\u1EBC": "E", "\u0112": "E", "\u1E14": "E", "\u1E16": "E", "\u0114": "E", "\u0116": "E", "\u00CB": "E", "\u1EBA": "E", "\u011A": "E", "\u0204": "E", "\u0206": "E", "\u1EB8": "E", "\u1EC6": "E", "\u0228": "E", "\u1E1C": "E", "\u0118": "E", "\u1E18": "E", "\u1E1A": "E", "\u0190": "E", "\u018E": "E", "\u24BB": "F", "\uFF26": "F", "\u1E1E": "F", "\u0191": "F", "\uA77B": "F", "\u24BC": "G", "\uFF27": "G", "\u01F4": "G", "\u011C": "G", "\u1E20": "G", "\u011E": "G", "\u0120": "G", "\u01E6": "G", "\u0122": "G", "\u01E4": "G", "\u0193": "G", "\uA7A0": "G", "\uA77D": "G", "\uA77E": "G", "\u24BD": "H", "\uFF28": "H", "\u0124": "H", "\u1E22": "H", "\u1E26": "H", "\u021E": "H", "\u1E24": "H", "\u1E28": "H", "\u1E2A": "H", "\u0126": "H", "\u2C67": "H", "\u2C75": "H", "\uA78D": "H", "\u24BE": "I", "\uFF29": "I", "\u00CC": "I", "\u00CD": "I", "\u00CE": "I", "\u0128": "I", "\u012A": "I", "\u012C": "I", "\u0130": "I", "\u00CF": "I", "\u1E2E": "I", "\u1EC8": "I", "\u01CF": "I", "\u0208": "I", "\u020A": "I", "\u1ECA": "I", "\u012E": "I", "\u1E2C": "I", "\u0197": "I", "\u24BF": "J", "\uFF2A": "J", "\u0134": "J", "\u0248": "J", "\u24C0": "K", "\uFF2B": "K", "\u1E30": "K", "\u01E8": "K", "\u1E32": "K", "\u0136": "K", "\u1E34": "K", "\u0198": "K", "\u2C69": "K", "\uA740": "K", "\uA742": "K", "\uA744": "K", "\uA7A2": "K", "\u24C1": "L", "\uFF2C": "L", "\u013F": "L", "\u0139": "L", "\u013D": "L", "\u1E36": "L", "\u1E38": "L", "\u013B": "L", "\u1E3C": "L", "\u1E3A": "L", "\u0141": "L", "\u023D": "L", "\u2C62": "L", "\u2C60": "L", "\uA748": "L", "\uA746": "L", "\uA780": "L", "\u01C7": "LJ", "\u01C8": "Lj", "\u24C2": "M", "\uFF2D": "M", "\u1E3E": "M", "\u1E40": "M", "\u1E42": "M", "\u2C6E": "M", "\u019C": "M", "\u24C3": "N", "\uFF2E": "N", "\u01F8": "N", "\u0143": "N", "\u00D1": "N", "\u1E44": "N", "\u0147": "N", "\u1E46": "N", "\u0145": "N", "\u1E4A": "N", "\u1E48": "N", "\u0220": "N", "\u019D": "N", "\uA790": "N", "\uA7A4": "N", "\u01CA": "NJ", "\u01CB": "Nj", "\u24C4": "O", "\uFF2F": "O", "\u00D2": "O", "\u00D3": "O", "\u00D4": "O", "\u1ED2": "O", "\u1ED0": "O", "\u1ED6": "O", "\u1ED4": "O", "\u00D5": "O", "\u1E4C": "O", "\u022C": "O", "\u1E4E": "O", "\u014C": "O", "\u1E50": "O", "\u1E52": "O", "\u014E": "O", "\u022E": "O", "\u0230": "O", "\u00D6": "O", "\u022A": "O", "\u1ECE": "O", "\u0150": "O", "\u01D1": "O", "\u020C": "O", "\u020E": "O", "\u01A0": "O", "\u1EDC": "O", "\u1EDA": "O", "\u1EE0": "O", "\u1EDE": "O", "\u1EE2": "O", "\u1ECC": "O", "\u1ED8": "O", "\u01EA": "O", "\u01EC": "O", "\u00D8": "O", "\u01FE": "O", "\u0186": "O", "\u019F": "O", "\uA74A": "O", "\uA74C": "O", "\u01A2": "OI", "\uA74E": "OO", "\u0222": "OU", "\u24C5": "P", "\uFF30": "P", "\u1E54": "P", "\u1E56": "P", "\u01A4": "P", "\u2C63": "P", "\uA750": "P", "\uA752": "P", "\uA754": "P", "\u24C6": "Q", "\uFF31": "Q", "\uA756": "Q", "\uA758": "Q", "\u024A": "Q", "\u24C7": "R", "\uFF32": "R", "\u0154": "R", "\u1E58": "R", "\u0158": "R", "\u0210": "R", "\u0212": "R", "\u1E5A": "R", "\u1E5C": "R", "\u0156": "R", "\u1E5E": "R", "\u024C": "R", "\u2C64": "R", "\uA75A": "R", "\uA7A6": "R", "\uA782": "R", "\u24C8": "S", "\uFF33": "S", "\u1E9E": "S", "\u015A": "S", "\u1E64": "S", "\u015C": "S", "\u1E60": "S", "\u0160": "S", "\u1E66": "S", "\u1E62": "S", "\u1E68": "S", "\u0218": "S", "\u015E": "S", "\u2C7E": "S", "\uA7A8": "S", "\uA784": "S", "\u24C9": "T", "\uFF34": "T", "\u1E6A": "T", "\u0164": "T", "\u1E6C": "T", "\u021A": "T", "\u0162": "T", "\u1E70": "T", "\u1E6E": "T", "\u0166": "T", "\u01AC": "T", "\u01AE": "T", "\u023E": "T", "\uA786": "T", "\uA728": "TZ", "\u24CA": "U", "\uFF35": "U", "\u00D9": "U", "\u00DA": "U", "\u00DB": "U", "\u0168": "U", "\u1E78": "U", "\u016A": "U", "\u1E7A": "U", "\u016C": "U", "\u00DC": "U", "\u01DB": "U", "\u01D7": "U", "\u01D5": "U", "\u01D9": "U", "\u1EE6": "U", "\u016E": "U", "\u0170": "U", "\u01D3": "U", "\u0214": "U", "\u0216": "U", "\u01AF": "U", "\u1EEA": "U", "\u1EE8": "U", "\u1EEE": "U", "\u1EEC": "U", "\u1EF0": "U", "\u1EE4": "U", "\u1E72": "U", "\u0172": "U", "\u1E76": "U", "\u1E74": "U", "\u0244": "U", "\u24CB": "V", "\uFF36": "V", "\u1E7C": "V", "\u1E7E": "V", "\u01B2": "V", "\uA75E": "V", "\u0245": "V", "\uA760": "VY", "\u24CC": "W", "\uFF37": "W", "\u1E80": "W", "\u1E82": "W", "\u0174": "W", "\u1E86": "W", "\u1E84": "W", "\u1E88": "W", "\u2C72": "W", "\u24CD": "X", "\uFF38": "X", "\u1E8A": "X", "\u1E8C": "X", "\u24CE": "Y", "\uFF39": "Y", "\u1EF2": "Y", "\u00DD": "Y", "\u0176": "Y", "\u1EF8": "Y", "\u0232": "Y", "\u1E8E": "Y", "\u0178": "Y", "\u1EF6": "Y", "\u1EF4": "Y", "\u01B3": "Y", "\u024E": "Y", "\u1EFE": "Y", "\u24CF": "Z", "\uFF3A": "Z", "\u0179": "Z", "\u1E90": "Z", "\u017B": "Z", "\u017D": "Z", "\u1E92": "Z", "\u1E94": "Z", "\u01B5": "Z", "\u0224": "Z", "\u2C7F": "Z", "\u2C6B": "Z", "\uA762": "Z", "\u24D0": "a", "\uFF41": "a", "\u1E9A": "a", "\u00E0": "a", "\u00E1": "a", "\u00E2": "a", "\u1EA7": "a", "\u1EA5": "a", "\u1EAB": "a", "\u1EA9": "a", "\u00E3": "a", "\u0101": "a", "\u0103": "a", "\u1EB1": "a", "\u1EAF": "a", "\u1EB5": "a", "\u1EB3": "a", "\u0227": "a", "\u01E1": "a", "\u00E4": "a", "\u01DF": "a", "\u1EA3": "a", "\u00E5": "a", "\u01FB": "a", "\u01CE": "a", "\u0201": "a", "\u0203": "a", "\u1EA1": "a", "\u1EAD": "a", "\u1EB7": "a", "\u1E01": "a", "\u0105": "a", "\u2C65": "a", "\u0250": "a", "\uA733": "aa", "\u00E6": "ae", "\u01FD": "ae", "\u01E3": "ae", "\uA735": "ao", "\uA737": "au", "\uA739": "av", "\uA73B": "av", "\uA73D": "ay", "\u24D1": "b", "\uFF42": "b", "\u1E03": "b", "\u1E05": "b", "\u1E07": "b", "\u0180": "b", "\u0183": "b", "\u0253": "b", "\u24D2": "c", "\uFF43": "c", "\u0107": "c", "\u0109": "c", "\u010B": "c", "\u010D": "c", "\u00E7": "c", "\u1E09": "c", "\u0188": "c", "\u023C": "c", "\uA73F": "c", "\u2184": "c", "\u24D3": "d", "\uFF44": "d", "\u1E0B": "d", "\u010F": "d", "\u1E0D": "d", "\u1E11": "d", "\u1E13": "d", "\u1E0F": "d", "\u0111": "d", "\u018C": "d", "\u0256": "d", "\u0257": "d", "\uA77A": "d", "\u01F3": "dz", "\u01C6": "dz", "\u24D4": "e", "\uFF45": "e", "\u00E8": "e", "\u00E9": "e", "\u00EA": "e", "\u1EC1": "e", "\u1EBF": "e", "\u1EC5": "e", "\u1EC3": "e", "\u1EBD": "e", "\u0113": "e", "\u1E15": "e", "\u1E17": "e", "\u0115": "e", "\u0117": "e", "\u00EB": "e", "\u1EBB": "e", "\u011B": "e", "\u0205": "e", "\u0207": "e", "\u1EB9": "e", "\u1EC7": "e", "\u0229": "e", "\u1E1D": "e", "\u0119": "e", "\u1E19": "e", "\u1E1B": "e", "\u0247": "e", "\u025B": "e", "\u01DD": "e", "\u24D5": "f", "\uFF46": "f", "\u1E1F": "f", "\u0192": "f", "\uA77C": "f", "\u24D6": "g", "\uFF47": "g", "\u01F5": "g", "\u011D": "g", "\u1E21": "g", "\u011F": "g", "\u0121": "g", "\u01E7": "g", "\u0123": "g", "\u01E5": "g", "\u0260": "g", "\uA7A1": "g", "\u1D79": "g", "\uA77F": "g", "\u24D7": "h", "\uFF48": "h", "\u0125": "h", "\u1E23": "h", "\u1E27": "h", "\u021F": "h", "\u1E25": "h", "\u1E29": "h", "\u1E2B": "h", "\u1E96": "h", "\u0127": "h", "\u2C68": "h", "\u2C76": "h", "\u0265": "h", "\u0195": "hv", "\u24D8": "i", "\uFF49": "i", "\u00EC": "i", "\u00ED": "i", "\u00EE": "i", "\u0129": "i", "\u012B": "i", "\u012D": "i", "\u00EF": "i", "\u1E2F": "i", "\u1EC9": "i", "\u01D0": "i", "\u0209": "i", "\u020B": "i", "\u1ECB": "i", "\u012F": "i", "\u1E2D": "i", "\u0268": "i", "\u0131": "i", "\u24D9": "j", "\uFF4A": "j", "\u0135": "j", "\u01F0": "j", "\u0249": "j", "\u24DA": "k", "\uFF4B": "k", "\u1E31": "k", "\u01E9": "k", "\u1E33": "k", "\u0137": "k", "\u1E35": "k", "\u0199": "k", "\u2C6A": "k", "\uA741": "k", "\uA743": "k", "\uA745": "k", "\uA7A3": "k", "\u24DB": "l", "\uFF4C": "l", "\u0140": "l", "\u013A": "l", "\u013E": "l", "\u1E37": "l", "\u1E39": "l", "\u013C": "l", "\u1E3D": "l", "\u1E3B": "l", "\u017F": "l", "\u0142": "l", "\u019A": "l", "\u026B": "l", "\u2C61": "l", "\uA749": "l", "\uA781": "l", "\uA747": "l", "\u01C9": "lj", "\u24DC": "m", "\uFF4D": "m", "\u1E3F": "m", "\u1E41": "m", "\u1E43": "m", "\u0271": "m", "\u026F": "m", "\u24DD": "n", "\uFF4E": "n", "\u01F9": "n", "\u0144": "n", "\u00F1": "n", "\u1E45": "n", "\u0148": "n", "\u1E47": "n", "\u0146": "n", "\u1E4B": "n", "\u1E49": "n", "\u019E": "n", "\u0272": "n", "\u0149": "n", "\uA791": "n", "\uA7A5": "n", "\u01CC": "nj", "\u24DE": "o", "\uFF4F": "o", "\u00F2": "o", "\u00F3": "o", "\u00F4": "o", "\u1ED3": "o", "\u1ED1": "o", "\u1ED7": "o", "\u1ED5": "o", "\u00F5": "o", "\u1E4D": "o", "\u022D": "o", "\u1E4F": "o", "\u014D": "o", "\u1E51": "o", "\u1E53": "o", "\u014F": "o", "\u022F": "o", "\u0231": "o", "\u00F6": "o", "\u022B": "o", "\u1ECF": "o", "\u0151": "o", "\u01D2": "o", "\u020D": "o", "\u020F": "o", "\u01A1": "o", "\u1EDD": "o", "\u1EDB": "o", "\u1EE1": "o", "\u1EDF": "o", "\u1EE3": "o", "\u1ECD": "o", "\u1ED9": "o", "\u01EB": "o", "\u01ED": "o", "\u00F8": "o", "\u01FF": "o", "\u0254": "o", "\uA74B": "o", "\uA74D": "o", "\u0275": "o", "\u01A3": "oi", "\u0223": "ou", "\uA74F": "oo", "\u24DF": "p", "\uFF50": "p", "\u1E55": "p", "\u1E57": "p", "\u01A5": "p", "\u1D7D": "p", "\uA751": "p", "\uA753": "p", "\uA755": "p", "\u24E0": "q", "\uFF51": "q", "\u024B": "q", "\uA757": "q", "\uA759": "q", "\u24E1": "r", "\uFF52": "r", "\u0155": "r", "\u1E59": "r", "\u0159": "r", "\u0211": "r", "\u0213": "r", "\u1E5B": "r", "\u1E5D": "r", "\u0157": "r", "\u1E5F": "r", "\u024D": "r", "\u027D": "r", "\uA75B": "r", "\uA7A7": "r", "\uA783": "r", "\u24E2": "s", "\uFF53": "s", "\u00DF": "s", "\u015B": "s", "\u1E65": "s", "\u015D": "s", "\u1E61": "s", "\u0161": "s", "\u1E67": "s", "\u1E63": "s", "\u1E69": "s", "\u0219": "s", "\u015F": "s", "\u023F": "s", "\uA7A9": "s", "\uA785": "s", "\u1E9B": "s", "\u24E3": "t", "\uFF54": "t", "\u1E6B": "t", "\u1E97": "t", "\u0165": "t", "\u1E6D": "t", "\u021B": "t", "\u0163": "t", "\u1E71": "t", "\u1E6F": "t", "\u0167": "t", "\u01AD": "t", "\u0288": "t", "\u2C66": "t", "\uA787": "t", "\uA729": "tz", "\u24E4": "u", "\uFF55": "u", "\u00F9": "u", "\u00FA": "u", "\u00FB": "u", "\u0169": "u", "\u1E79": "u", "\u016B": "u", "\u1E7B": "u", "\u016D": "u", "\u00FC": "u", "\u01DC": "u", "\u01D8": "u", "\u01D6": "u", "\u01DA": "u", "\u1EE7": "u", "\u016F": "u", "\u0171": "u", "\u01D4": "u", "\u0215": "u", "\u0217": "u", "\u01B0": "u", "\u1EEB": "u", "\u1EE9": "u", "\u1EEF": "u", "\u1EED": "u", "\u1EF1": "u", "\u1EE5": "u", "\u1E73": "u", "\u0173": "u", "\u1E77": "u", "\u1E75": "u", "\u0289": "u", "\u24E5": "v", "\uFF56": "v", "\u1E7D": "v", "\u1E7F": "v", "\u028B": "v", "\uA75F": "v", "\u028C": "v", "\uA761": "vy", "\u24E6": "w", "\uFF57": "w", "\u1E81": "w", "\u1E83": "w", "\u0175": "w", "\u1E87": "w", "\u1E85": "w", "\u1E98": "w", "\u1E89": "w", "\u2C73": "w", "\u24E7": "x", "\uFF58": "x", "\u1E8B": "x", "\u1E8D": "x", "\u24E8": "y", "\uFF59": "y", "\u1EF3": "y", "\u00FD": "y", "\u0177": "y", "\u1EF9": "y", "\u0233": "y", "\u1E8F": "y", "\u00FF": "y", "\u1EF7": "y", "\u1E99": "y", "\u1EF5": "y", "\u01B4": "y", "\u024F": "y", "\u1EFF": "y", "\u24E9": "z", "\uFF5A": "z", "\u017A": "z", "\u1E91": "z", "\u017C": "z", "\u017E": "z", "\u1E93": "z", "\u1E95": "z", "\u01B6": "z", "\u0225": "z", "\u0240": "z", "\u2C6C": "z", "\uA763": "z"};
-
-	$document = $(document);
-
-	nextUid = (function () {
-		var counter = 1;
-		return function () {
-			return counter++;
-		};
-	}());
-
-
-	function stripDiacritics(str) {
-		var ret, i, l, c;
-
-		if (!str || str.length < 1) return str;
-
-		ret = "";
-		for (i = 0, l = str.length; i < l; i++) {
-			c = str.charAt(i);
-			ret += DIACRITICS[c] || c;
-		}
-		return ret;
-	}
-
-	function indexOf(value, array) {
-		var i = 0, l = array.length;
-		for (; i < l; i = i + 1) {
-			if (equal(value, array[i])) return i;
-		}
-		return -1;
-	}
-
-	function measureScrollbar() {
-		var $template = $(MEASURE_SCROLLBAR_TEMPLATE);
-		$template.appendTo('body');
-
-		var dim = {
-			width: $template.width() - $template[0].clientWidth,
-			height: $template.height() - $template[0].clientHeight
-		};
-		$template.remove();
-
-		return dim;
-	}
-
-	/**
-	 * Compares equality of a and b
-	 * @param a
-	 * @param b
-	 */
-	function equal(a, b) {
-		if (a === b) return true;
-		if (a === undefined || b === undefined) return false;
-		if (a === null || b === null) return false;
-		// Check whether 'a' or 'b' is a string (primitive or object).
-		// The concatenation of an empty string (+'') converts its argument to a string's primitive.
-		if (a.constructor === String) return a + '' === b + ''; // a+'' - in case 'a' is a String object
-		if (b.constructor === String) return b + '' === a + ''; // b+'' - in case 'b' is a String object
-		return false;
-	}
-
-	/**
-	 * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
-	 * strings
-	 * @param string
-	 * @param separator
-	 */
-	function splitVal(string, separator) {
-		var val, i, l;
-		if (string === null || string.length < 1) return [];
-		val = string.split(separator);
-		for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
-		return val;
-	}
-
-	function getSideBorderPadding(element) {
-		return element.outerWidth(false) - element.width();
-	}
-
-	function installKeyUpChangeEvent(element) {
-		var key = "keyup-change-value";
-		element.on("keydown", function () {
-			if ($.data(element, key) === undefined) {
-				$.data(element, key, element.val());
-			}
-		});
-		element.on("keyup", function () {
-			var val = $.data(element, key);
-			if (val !== undefined && element.val() !== val) {
-				$.removeData(element, key);
-				element.trigger("keyup-change");
-			}
-		});
-	}
-
-	$document.on("mousemove", function (e) {
-		lastMousePosition.x = e.pageX;
-		lastMousePosition.y = e.pageY;
-	});
-
-	/**
-	 * filters mouse events so an event is fired only if the mouse moved.
-	 *
-	 * filters out mouse events that occur when mouse is stationary but
-	 * the elements under the pointer are scrolled.
-	 */
-	function installFilteredMouseMove(element) {
-		element.on("mousemove", function (e) {
-			var lastpos = lastMousePosition;
-			if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
-				$(e.target).trigger("mousemove-filtered", e);
-			}
-		});
-	}
-
-	/**
-	 * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
-	 * within the last quietMillis milliseconds.
-	 *
-	 * @param quietMillis number of milliseconds to wait before invoking fn
-	 * @param fn function to be debounced
-	 * @param ctx object to be used as this reference within fn
-	 * @return debounced version of fn
-	 */
-	function debounce(quietMillis, fn, ctx) {
-		ctx = ctx || undefined;
-		var timeout;
-		return function () {
-			var args = arguments;
-			window.clearTimeout(timeout);
-			timeout = window.setTimeout(function () {
-				fn.apply(ctx, args);
-			}, quietMillis);
-		};
-	}
-
-	/**
-	 * A simple implementation of a thunk
-	 * @param formula function used to lazily initialize the thunk
-	 * @return {Function}
-	 */
-	function thunk(formula) {
-		var evaluated = false,
-			value;
-		return function () {
-			if (evaluated === false) {
-				value = formula();
-				evaluated = true;
-			}
-			return value;
-		};
-	};
-
-	function installDebouncedScroll(threshold, element) {
-		var notify = debounce(threshold, function (e) {
-			element.trigger("scroll-debounced", e);
-		});
-		element.on("scroll", function (e) {
-			if (indexOf(e.target, element.get()) >= 0) notify(e);
-		});
-	}
-
-	function focus($el) {
-		if ($el[0] === document.activeElement) return;
-
-		/* set the focus in a 0 timeout - that way the focus is set after the processing
-		 of the current event has finished - which seems like the only reliable way
-		 to set focus */
-		window.setTimeout(function () {
-			var el = $el[0], pos = $el.val().length, range;
-
-			$el.focus();
-
-			/* make sure el received focus so we do not error out when trying to manipulate the caret.
-			 sometimes modals or others listeners may steal it after its set */
-			if ($el.is(":visible") && el === document.activeElement) {
-
-				/* after the focus is set move the caret to the end, necessary when we val()
-				 just before setting focus */
-				if (el.setSelectionRange) {
-					el.setSelectionRange(pos, pos);
-				}
-				else if (el.createTextRange) {
-					range = el.createTextRange();
-					range.collapse(false);
-					range.select();
-				}
-			}
-		}, 0);
-	}
-
-	function getCursorInfo(el) {
-		el = $(el)[0];
-		var offset = 0;
-		var length = 0;
-		if ('selectionStart' in el) {
-			offset = el.selectionStart;
-			length = el.selectionEnd - offset;
-		} else if ('selection' in document) {
-			el.focus();
-			var sel = document.selection.createRange();
-			length = document.selection.createRange().text.length;
-			sel.moveStart('character', -el.value.length);
-			offset = sel.text.length - length;
-		}
-		return { offset: offset, length: length };
-	}
-
-	function killEvent(event) {
-		event.preventDefault();
-		event.stopPropagation();
-	}
-
-	function killEventImmediately(event) {
-		event.preventDefault();
-		event.stopImmediatePropagation();
-	}
-
-	function measureTextWidth(e) {
-		if (!sizer) {
-			var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
-			sizer = $(document.createElement("div")).css({
-															 position: "absolute",
-															 left: "-10000px",
-															 top: "-10000px",
-															 display: "none",
-															 fontSize: style.fontSize,
-															 fontFamily: style.fontFamily,
-															 fontStyle: style.fontStyle,
-															 fontWeight: style.fontWeight,
-															 letterSpacing: style.letterSpacing,
-															 textTransform: style.textTransform,
-															 whiteSpace: "nowrap"
-														 });
-			sizer.attr("class", "select2-sizer");
-			$("body").append(sizer);
-		}
-		sizer.text(e.val());
-		return sizer.width();
-	}
-
-	function syncCssClasses(dest, src, adapter) {
-		var classes, replacements = [], adapted;
-
-		classes = dest.attr("class");
-		if (classes) {
-			classes = '' + classes; // for IE which returns object
-			$(classes.split(" ")).each2(function () {
-				if (this.indexOf("select2-") === 0) {
-					replacements.push(this);
-				}
-			});
-		}
-		classes = src.attr("class");
-		if (classes) {
-			classes = '' + classes; // for IE which returns object
-			$(classes.split(" ")).each2(function () {
-				if (this.indexOf("select2-") !== 0) {
-					adapted = adapter(this);
-					if (adapted) {
-						replacements.push(adapted);
-					}
-				}
-			});
-		}
-		dest.attr("class", replacements.join(" "));
-	}
-
-
-	function markMatch(text, term, markup, escapeMarkup) {
-		var match = stripDiacritics(text.toUpperCase()).indexOf(stripDiacritics(term.toUpperCase())),
-			tl = term.length;
-
-		if (match < 0) {
-			markup.push(escapeMarkup(text));
-			return;
-		}
-
-		markup.push(escapeMarkup(text.substring(0, match)));
-		markup.push("<span class='select2-match'>");
-		markup.push(escapeMarkup(text.substring(match, match + tl)));
-		markup.push("</span>");
-		markup.push(escapeMarkup(text.substring(match + tl, text.length)));
-	}
-
-	function defaultEscapeMarkup(markup) {
-		var replace_map = {
-			'\\': '&#92;',
-			'&': '&amp;',
-			'<': '&lt;',
-			'>': '&gt;',
-			'"': '&quot;',
-			"'": '&#39;',
-			"/": '&#47;'
-		};
-
-		return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
-			return replace_map[match];
-		});
-	}
-
-	/**
-	 * Produces an ajax-based query function
-	 *
-	 * @param options object containing configuration paramters
-	 * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
-	 * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
-	 * @param options.url url for the data
-	 * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
-	 * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified
-	 * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
-	 * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
-	 *      The expected format is an object containing the following keys:
-	 *      results array of objects that will be used as choices
-	 *      more (optional) boolean indicating whether there are more results available
-	 *      Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
-	 */
-	function ajax(options) {
-		var timeout, // current scheduled but not yet executed request
-			handler = null,
-			quietMillis = options.quietMillis || 100,
-			ajaxUrl = options.url,
-			self = this;
-
-		return function (query) {
-			window.clearTimeout(timeout);
-			timeout = window.setTimeout(function () {
-				var data = options.data, // ajax data function
-					url = ajaxUrl, // ajax url string or function
-					transport = options.transport || $.fn.select2.ajaxDefaults.transport,
-				// deprecated - to be removed in 4.0  - use params instead
-					deprecated = {
-						type: options.type || 'GET', // set type of request (GET or POST)
-						cache: options.cache || false,
-						jsonpCallback: options.jsonpCallback || undefined,
-						dataType: options.dataType || "json"
-					},
-					params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
-
-				data = data ? data.call(self, query.term, query.page, query.context) : null;
-				url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
-
-				if (handler) {
-					handler.abort();
-				}
-
-				if (options.params) {
-					if ($.isFunction(options.params)) {
-						$.extend(params, options.params.call(self));
-					} else {
-						$.extend(params, options.params);
-					}
-				}
-
-				$.extend(params, {
-					url: url,
-					dataType: options.dataType,
-					data: data,
-					success: function (data) {
-						// TODO - replace query.page with query so users have access to term, page, etc.
-						var results = options.results(data, query.page);
-						query.callback(results);
-					}
-				});
-				handler = transport.call(self, params);
-			}, quietMillis);
-		};
-	}
-
-	/**
-	 * Produces a query function that works with a local array
-	 *
-	 * @param options object containing configuration parameters. The options parameter can either be an array or an
-	 * object.
-	 *
-	 * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
-	 *
-	 * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
-	 * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
-	 * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
-	 * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
-	 * the text.
-	 */
-	function local(options) {
-		var data = options, // data elements
-			dataText,
-			tmp,
-			text = function (item) {
-				return "" + item.text;
-			}; // function used to retrieve the text portion of a data item that is matched against the search
-
-		if ($.isArray(data)) {
-			tmp = data;
-			data = { results: tmp };
-		}
-
-		if ($.isFunction(data) === false) {
-			tmp = data;
-			data = function () {
-				return tmp;
-			};
-		}
-
-		var dataItem = data();
-		if (dataItem.text) {
-			text = dataItem.text;
-			// if text is not a function we assume it to be a key name
-			if (!$.isFunction(text)) {
-				dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
-				text = function (item) {
-					return item[dataText];
-				};
-			}
-		}
-
-		return function (query) {
-			var t = query.term, filtered = { results: [] }, process;
-			if (t === "") {
-				query.callback(data());
-				return;
-			}
-
-			process = function (datum, collection) {
-				var group, attr;
-				datum = datum[0];
-				if (datum.children) {
-					group = {};
-					for (attr in datum) {
-						if (datum.hasOwnProperty(attr)) group[attr] = datum[attr];
-					}
-					group.children = [];
-					$(datum.children).each2(function (i, childDatum) {
-						process(childDatum, group.children);
-					});
-					if (group.children.length || query.matcher(t, text(group), datum)) {
-						collection.push(group);
-					}
-				} else {
-					if (query.matcher(t, text(datum), datum)) {
-						collection.push(datum);
-					}
-				}
-			};
-
-			$(data().results).each2(function (i, datum) {
-				process(datum, filtered.results);
-			});
-			query.callback(filtered);
-		};
-	}
-
-	// TODO javadoc
-	function tags(data) {
-		var isFunc = $.isFunction(data);
-		return function (query) {
-			var t = query.term, filtered = {results: []};
-			$(isFunc ? data() : data).each(function () {
-				var isObject = this.text !== undefined,
-					text = isObject ? this.text : this;
-				if (t === "" || query.matcher(t, text)) {
-					filtered.results.push(isObject ? this : {id: this, text: this});
-				}
-			});
-			query.callback(filtered);
-		};
-	}
-
-	/**
-	 * Checks if the formatter function should be used.
-	 *
-	 * Throws an error if it is not a function. Returns true if it should be used,
-	 * false if no formatting should be performed.
-	 *
-	 * @param formatter
-	 */
-	function checkFormatter(formatter, formatterName) {
-		if ($.isFunction(formatter)) return true;
-		if (!formatter) return false;
-		throw new Error(formatterName + " must be a function or a falsy value");
-	}
-
-	function evaluate(val) {
-		return $.isFunction(val) ? val() : val;
-	}
-
-	function countResults(results) {
-		var count = 0;
-		$.each(results, function (i, item) {
-			if (item.children) {
-				count += countResults(item.children);
-			} else {
-				count++;
-			}
-		});
-		return count;
-	}
-
-	/**
-	 * Default tokenizer. This function uses breaks the input on substring match of any string from the
-	 * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
-	 * two options have to be defined in order for the tokenizer to work.
-	 *
-	 * @param input text user has typed so far or pasted into the search field
-	 * @param selection currently selected choices
-	 * @param selectCallback function(choice) callback tho add the choice to selection
-	 * @param opts select2's opts
-	 * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
-	 */
-	function defaultTokenizer(input, selection, selectCallback, opts) {
-		var original = input, // store the original so we can compare and know if we need to tell the search to update its text
-			dupe = false, // check for whether a token we extracted represents a duplicate selected choice
-			token, // token
-			index, // position at which the separator was found
-			i, l, // looping variables
-			separator; // the matched separator
-
-		if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
-
-		while (true) {
-			index = -1;
-
-			for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
-				separator = opts.tokenSeparators[i];
-				index = input.indexOf(separator);
-				if (index >= 0) break;
-			}
-
-			if (index < 0) break; // did not find any token separator in the input string, bail
-
-			token = input.substring(0, index);
-			input = input.substring(index + separator.length);
-
-			if (token.length > 0) {
-				token = opts.createSearchChoice.call(this, token, selection);
-				if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
-					dupe = false;
-					for (i = 0, l = selection.length; i < l; i++) {
-						if (equal(opts.id(token), opts.id(selection[i]))) {
-							dupe = true;
-							break;
-						}
-					}
-
-					if (!dupe) selectCallback(token);
-				}
-			}
-		}
-
-		if (original !== input) return input;
-	}
-
-	/**
-	 * Creates a new class
-	 *
-	 * @param superClass
-	 * @param methods
-	 */
-	function clazz(SuperClass, methods) {
-		var constructor = function () {
-		};
-		constructor.prototype = new SuperClass;
-		constructor.prototype.constructor = constructor;
-		constructor.prototype.parent = SuperClass.prototype;
-		constructor.prototype = $.extend(constructor.prototype, methods);
-		return constructor;
-	}
-
-	AbstractSelect2 = clazz(Object, {
-
-		// abstract
-		bind: function (func) {
-			var self = this;
-			return function () {
-				func.apply(self, arguments);
-			};
-		},
-
-		// abstract
-		init: function (opts) {
-			var results, search, resultsSelector = ".select2-results";
-
-			// prepare options
-			this.opts = opts = this.prepareOpts(opts);
-
-			this.id = opts.id;
-
-			// destroy if called on an existing component
-			if (opts.element.data("select2") !== undefined &&
-				opts.element.data("select2") !== null) {
-				opts.element.data("select2").destroy();
-			}
-
-			this.container = this.createContainer();
-
-			this.containerId = "s2id_" + (opts.element.attr("id") || "autogen" + nextUid());
-			this.containerSelector = "#" + this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
-			this.container.attr("id", this.containerId);
-
-			// cache the body so future lookups are cheap
-			this.body = thunk(function () {
-				return opts.element.closest("body");
-			});
-
-			syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
-
-			this.container.attr("style", opts.element.attr("style"));
-			this.container.css(evaluate(opts.containerCss));
-			this.container.addClass(evaluate(opts.containerCssClass));
-
-			this.elementTabIndex = this.opts.element.attr("tabindex");
-
-			// swap container for the element
-			this.opts.element
-				.data("select2", this)
-				.attr("tabindex", "-1")
-				.before(this.container)
-				.on("click.select2", killEvent); // do not leak click events
-
-			this.container.data("select2", this);
-
-			this.dropdown = this.container.find(".select2-drop");
-
-			syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
-
-			this.dropdown.addClass(evaluate(opts.dropdownCssClass));
-			this.dropdown.data("select2", this);
-			this.dropdown.on("click", killEvent);
-
-			this.results = results = this.container.find(resultsSelector);
-			this.search = search = this.container.find("input.select2-input");
-
-			this.queryCount = 0;
-			this.resultsPage = 0;
-			this.context = null;
-
-			// initialize the container
-			this.initContainer();
-
-			this.container.on("click", killEvent);
-
-			installFilteredMouseMove(this.results);
-			this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent));
-
-			installDebouncedScroll(80, this.results);
-			this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
-
-			// do not propagate change event from the search field out of the component
-			$(this.container).on("change", ".select2-input", function (e) {
-				e.stopPropagation();
-			});
-			$(this.dropdown).on("change", ".select2-input", function (e) {
-				e.stopPropagation();
-			});
-
-			// if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
-			if ($.fn.mousewheel) {
-				results.mousewheel(function (e, delta, deltaX, deltaY) {
-					var top = results.scrollTop();
-					if (deltaY > 0 && top - deltaY <= 0) {
-						results.scrollTop(0);
-						killEvent(e);
-					} else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
-						results.scrollTop(results.get(0).scrollHeight - results.height());
-						killEvent(e);
-					}
-				});
-			}
-
-			installKeyUpChangeEvent(search);
-			search.on("keyup-change input paste", this.bind(this.updateResults));
-			search.on("focus", function () {
-				search.addClass("select2-focused");
-			});
-			search.on("blur", function () {
-				search.removeClass("select2-focused");
-			});
-
-			this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
-				if ($(e.target).closest(".select2-result-selectable").length > 0) {
-					this.highlightUnderEvent(e);
-					this.selectHighlighted(e);
-				}
-			}));
-
-			// trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
-			// for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
-			// dom it will trigger the popup close, which is not what we want
-			this.dropdown.on("click mouseup mousedown", function (e) {
-				e.stopPropagation();
-			});
-
-			if ($.isFunction(this.opts.initSelection)) {
-				// initialize selection based on the current value of the source element
-				this.initSelection();
-
-				// if the user has provided a function that can set selection based on the value of the source element
-				// we monitor the change event on the element and trigger it, allowing for two way synchronization
-				this.monitorSource();
-			}
-
-			if (opts.maximumInputLength !== null) {
-				this.search.attr("maxlength", opts.maximumInputLength);
-			}
-
-			var disabled = opts.element.prop("disabled");
-			if (disabled === undefined) disabled = false;
-			this.enable(!disabled);
-
-			var readonly = opts.element.prop("readonly");
-			if (readonly === undefined) readonly = false;
-			this.readonly(readonly);
-
-			// Calculate size of scrollbar
-			scrollBarDimensions = scrollBarDimensions || measureScrollbar();
-
-			this.autofocus = opts.element.prop("autofocus");
-			opts.element.prop("autofocus", false);
-			if (this.autofocus) this.focus();
-
-			this.nextSearchTerm = undefined;
-		},
-
-		// abstract
-		destroy: function () {
-			var element = this.opts.element, select2 = element.data("select2");
-
-			this.close();
-
-			if (this.propertyObserver) {
-				delete this.propertyObserver;
-				this.propertyObserver = null;
-			}
-
-			if (select2 !== undefined) {
-				select2.container.remove();
-				select2.dropdown.remove();
-				element
-					.removeClass("select2-offscreen")
-					.removeData("select2")
-					.off(".select2")
-					.prop("autofocus", this.autofocus || false);
-				if (this.elementTabIndex) {
-					element.attr({tabindex: this.elementTabIndex});
-				} else {
-					element.removeAttr("tabindex");
-				}
-				element.show();
-			}
-		},
-
-		// abstract
-		optionToData: function (element) {
-			if (element.is("option")) {
-				return {
-					id: element.prop("value"),
-					text: element.text(),
-					element: element.get(),
-					css: element.attr("class"),
-					disabled: element.prop("disabled"),
-					locked: equal(element.attr("locked"), "locked") || equal(element.data("locked"), true)
-				};
-			} else if (element.is("optgroup")) {
-				return {
-					text: element.attr("label"),
-					children: [],
-					element: element.get(),
-					css: element.attr("class")
-				};
-			}
-		},
-
-		// abstract
-		prepareOpts: function (opts) {
-			var element, select, idKey, ajaxUrl, self = this;
-
-			element = opts.element;
-
-			if (element.get(0).tagName.toLowerCase() === "select") {
-				this.select = select = opts.element;
-			}
-
-			if (select) {
-				// these options are not allowed when attached to a select because they are picked up off the element itself
-				$.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
-					if (this in opts) {
-						throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
-					}
-				});
-			}
-
-			opts = $.extend({}, {
-				populateResults: function (container, results, query) {
-					var populate, id = this.opts.id;
-
-					populate = function (results, container, depth) {
-
-						var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
-
-						results = opts.sortResults(results, container, query);
-
-						for (i = 0, l = results.length; i < l; i = i + 1) {
-
-							result = results[i];
-
-							disabled = (result.disabled === true);
-							selectable = (!disabled) && (id(result) !== undefined);
-
-							compound = result.children && result.children.length > 0;
-
-							node = $("<li></li>");
-							node.addClass("select2-results-dept-" + depth);
-							node.addClass("select2-result");
-							node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
-							if (disabled) {
-								node.addClass("select2-disabled");
-							}
-							if (compound) {
-								node.addClass("select2-result-with-children");
-							}
-							node.addClass(self.opts.formatResultCssClass(result));
-
-							label = $(document.createElement("div"));
-							label.addClass("select2-result-label");
-
-							formatted = opts.formatResult(result, label, query, self.opts.escapeMarkup);
-							if (formatted !== undefined) {
-								label.html(formatted);
-							}
-
-							node.append(label);
-
-							if (compound) {
-
-								innerContainer = $("<ul></ul>");
-								innerContainer.addClass("select2-result-sub");
-								populate(result.children, innerContainer, depth + 1);
-								node.append(innerContainer);
-							}
-
-							node.data("select2-data", result);
-							container.append(node);
-						}
-					};
-
-					populate(results, container, 0);
-				}
-			}, $.fn.select2.defaults, opts);
-
-			if (typeof(opts.id) !== "function") {
-				idKey = opts.id;
-				opts.id = function (e) {
-					return e[idKey];
-				};
-			}
-
-			if ($.isArray(opts.element.data("select2Tags"))) {
-				if ("tags" in opts) {
-					throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
-				}
-				opts.tags = opts.element.data("select2Tags");
-			}
-
-			if (select) {
-				opts.query = this.bind(function (query) {
-					var data = { results: [], more: false },
-						term = query.term,
-						children, placeholderOption, process;
-
-					process = function (element, collection) {
-						var group;
-						if (element.is("option")) {
-							if (query.matcher(term, element.text(), element)) {
-								collection.push(self.optionToData(element));
-							}
-						} else if (element.is("optgroup")) {
-							group = self.optionToData(element);
-							element.children().each2(function (i, elm) {
-								process(elm, group.children);
-							});
-							if (group.children.length > 0) {
-								collection.push(group);
-							}
-						}
-					};
-
-					children = element.children();
-
-					// ignore the placeholder option if there is one
-					if (this.getPlaceholder() !== undefined && children.length > 0) {
-						placeholderOption = this.getPlaceholderOption();
-						if (placeholderOption) {
-							children = children.not(placeholderOption);
-						}
-					}
-
-					children.each2(function (i, elm) {
-						process(elm, data.results);
-					});
-
-					query.callback(data);
-				});
-				// this is needed because inside val() we construct choices from options and there id is hardcoded
-				opts.id = function (e) {
-					return e.id;
-				};
-				opts.formatResultCssClass = function (data) {
-					return data.css;
-				};
-			} else {
-				if (!("query" in opts)) {
-
-					if ("ajax" in opts) {
-						ajaxUrl = opts.element.data("ajax-url");
-						if (ajaxUrl && ajaxUrl.length > 0) {
-							opts.ajax.url = ajaxUrl;
-						}
-						opts.query = ajax.call(opts.element, opts.ajax);
-					} else if ("data" in opts) {
-						opts.query = local(opts.data);
-					} else if ("tags" in opts) {
-						opts.query = tags(opts.tags);
-						if (opts.createSearchChoice === undefined) {
-							opts.createSearchChoice = function (term) {
-								return {id: $.trim(term), text: $.trim(term)};
-							};
-						}
-						if (opts.initSelection === undefined) {
-							opts.initSelection = function (element, callback) {
-								var data = [];
-								$(splitVal(element.val(), opts.separator)).each(function () {
-									var obj = { id: this, text: this },
-										tags = opts.tags;
-									if ($.isFunction(tags)) tags = tags();
-									$(tags).each(function () {
-										if (equal(this.id, obj.id)) {
-											obj = this;
-											return false;
-										}
-									});
-									data.push(obj);
-								});
-
-								callback(data);
-							};
-						}
-					}
-				}
-			}
-			if (typeof(opts.query) !== "function") {
-				throw "query function not defined for Select2 " + opts.element.attr("id");
-			}
-
-			return opts;
-		},
-
-		/**
-		 * Monitor the original element for changes and update select2 accordingly
-		 */
-		// abstract
-		monitorSource: function () {
-			var el = this.opts.element, sync, observer;
-
-			el.on("change.select2", this.bind(function (e) {
-				if (this.opts.element.data("select2-change-triggered") !== true) {
-					this.initSelection();
-				}
-			}));
-
-			sync = this.bind(function () {
-
-				// sync enabled state
-				var disabled = el.prop("disabled");
-				if (disabled === undefined) disabled = false;
-				this.enable(!disabled);
-
-				var readonly = el.prop("readonly");
-				if (readonly === undefined) readonly = false;
-				this.readonly(readonly);
-
-				syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
-				this.container.addClass(evaluate(this.opts.containerCssClass));
-
-				syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
-				this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));
-
-			});
-
-			// IE8-10
-			el.on("propertychange.select2", sync);
-
-			// hold onto a reference of the callback to work around a chromium bug
-			if (this.mutationCallback === undefined) {
-				this.mutationCallback = function (mutations) {
-					mutations.forEach(sync);
-				}
-			}
-
-			// safari, chrome, firefox, IE11
-			observer = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
-			if (observer !== undefined) {
-				if (this.propertyObserver) {
-					delete this.propertyObserver;
-					this.propertyObserver = null;
-				}
-				this.propertyObserver = new observer(this.mutationCallback);
-				this.propertyObserver.observe(el.get(0), { attributes: true, subtree: false });
-			}
-		},
-
-		// abstract
-		triggerSelect: function (data) {
-			var evt = $.Event("select2-selecting", { val: this.id(data), object: data });
-			this.opts.element.trigger(evt);
-			return !evt.isDefaultPrevented();
-		},
-
-		/**
-		 * Triggers the change event on the source element
-		 */
-		// abstract
-		triggerChange: function (details) {
-
-			details = details || {};
-			details = $.extend({}, details, { type: "change", val: this.val() });
-			// prevents recursive triggering
-			this.opts.element.data("select2-change-triggered", true);
-			this.opts.element.trigger(details);
-			this.opts.element.data("select2-change-triggered", false);
-
-			// some validation frameworks ignore the change event and listen instead to keyup, click for selects
-			// so here we trigger the click event manually
-			this.opts.element.click();
-
-			// ValidationEngine ignorea the change event and listens instead to blur
-			// so here we trigger the blur event manually if so desired
-			if (this.opts.blurOnChange)
-				this.opts.element.blur();
-		},
-
-		//abstract
-		isInterfaceEnabled: function () {
-			return this.enabledInterface === true;
-		},
-
-		// abstract
-		enableInterface: function () {
-			var enabled = this._enabled && !this._readonly,
-				disabled = !enabled;
-
-			if (enabled === this.enabledInterface) return false;
-
-			this.container.toggleClass("select2-container-disabled", disabled);
-			this.close();
-			this.enabledInterface = enabled;
-
-			return true;
-		},
-
-		// abstract
-		enable: function (enabled) {
-			if (enabled === undefined) enabled = true;
-			if (this._enabled === enabled) return;
-			this._enabled = enabled;
-
-			this.opts.element.prop("disabled", !enabled);
-			this.enableInterface();
-		},
-
-		// abstract
-		disable: function () {
-			this.enable(false);
-		},
-
-		// abstract
-		readonly: function (enabled) {
-			if (enabled === undefined) enabled = false;
-			if (this._readonly === enabled) return false;
-			this._readonly = enabled;
-
-			this.opts.element.prop("readonly", enabled);
-			this.enableInterface();
-			return true;
-		},
-
-		// abstract
-		opened: function () {
-			return this.container.hasClass("select2-dropdown-open");
-		},
-
-		// abstract
-		positionDropdown: function () {
-			var $dropdown = this.dropdown,
-				offset = this.container.offset(),
-				height = this.container.outerHeight(false),
-				width = this.container.outerWidth(false),
-				dropHeight = $dropdown.outerHeight(false),
-				$window = $(window),
-				windowWidth = $window.width(),
-				windowHeight = $window.height(),
-				viewPortRight = $window.scrollLeft() + windowWidth,
-				viewportBottom = $window.scrollTop() + windowHeight,
-				dropTop = offset.top + height,
-				dropLeft = offset.left,
-				enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
-				enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),
-				dropWidth = $dropdown.outerWidth(false),
-				enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight,
-				aboveNow = $dropdown.hasClass("select2-drop-above"),
-				bodyOffset,
-				above,
-				changeDirection,
-				css,
-				resultsListNode;
-
-			// always prefer the current above/below alignment, unless there is not enough room
-			if (aboveNow) {
-				above = true;
-				if (!enoughRoomAbove && enoughRoomBelow) {
-					changeDirection = true;
-					above = false;
-				}
-			} else {
-				above = false;
-				if (!enoughRoomBelow && enoughRoomAbove) {
-					changeDirection = true;
-					above = true;
-				}
-			}
-
-			//if we are changing direction we need to get positions when dropdown is hidden;
-			if (changeDirection) {
-				$dropdown.hide();
-				offset = this.container.offset();
-				height = this.container.outerHeight(false);
-				width = this.container.outerWidth(false);
-				dropHeight = $dropdown.outerHeight(false);
-				viewPortRight = $window.scrollLeft() + windowWidth;
-				viewportBottom = $window.scrollTop() + windowHeight;
-				dropTop = offset.top + height;
-				dropLeft = offset.left;
-				dropWidth = $dropdown.outerWidth(false);
-				enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
-				$dropdown.show();
-			}
-
-			if (this.opts.dropdownAutoWidth) {
-				resultsListNode = $('.select2-results', $dropdown)[0];
-				$dropdown.addClass('select2-drop-auto-width');
-				$dropdown.css('width', '');
-				// Add scrollbar width to dropdown if vertical scrollbar is present
-				dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
-				dropWidth > width ? width = dropWidth : dropWidth = width;
-				enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
-			}
-			else {
-				this.container.removeClass('select2-drop-auto-width');
-			}
-
-			//console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
-			//console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove);
-
-			// fix positioning when body has an offset and is not position: static
-			if (this.body().css('position') !== 'static') {
-				bodyOffset = this.body().offset();
-				dropTop -= bodyOffset.top;
-				dropLeft -= bodyOffset.left;
-			}
-
-			if (!enoughRoomOnRight) {
-				dropLeft = offset.left + width - dropWidth;
-			}
-
-			css = {
-				left: dropLeft,
-				width: width
-			};
-
-			if (above) {
-				css.bottom = windowHeight - offset.top;
-				css.top = 'auto';
-				this.container.addClass("select2-drop-above");
-				$dropdown.addClass("select2-drop-above");
-			}
-			else {
-				css.top = dropTop;
-				css.bottom = 'auto';
-				this.container.removeClass("select2-drop-above");
-				$dropdown.removeClass("select2-drop-above");
-			}
-			css = $.extend(css, evaluate(this.opts.dropdownCss));
-
-			$dropdown.css(css);
-		},
-
-		// abstract
-		shouldOpen: function () {
-			var event;
-
-			if (this.opened()) return false;
-
-			if (this._enabled === false || this._readonly === true) return false;
-
-			event = $.Event("select2-opening");
-			this.opts.element.trigger(event);
-			return !event.isDefaultPrevented();
-		},
-
-		// abstract
-		clearDropdownAlignmentPreference: function () {
-			// clear the classes used to figure out the preference of where the dropdown should be opened
-			this.container.removeClass("select2-drop-above");
-			this.dropdown.removeClass("select2-drop-above");
-		},
-
-		/**
-		 * Opens the dropdown
-		 *
-		 * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
-		 * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
-		 */
-		// abstract
-		open: function () {
-
-			if (!this.shouldOpen()) return false;
-
-			this.opening();
-
-			return true;
-		},
-
-		/**
-		 * Performs the opening of the dropdown
-		 */
-		// abstract
-		opening: function () {
-			var cid = this.containerId,
-				scroll = "scroll." + cid,
-				resize = "resize." + cid,
-				orient = "orientationchange." + cid,
-				mask;
-
-			this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
-
-			this.clearDropdownAlignmentPreference();
-
-			if (this.dropdown[0] !== this.body().children().last()[0]) {
-				this.dropdown.detach().appendTo(this.body());
-			}
-
-			// create the dropdown mask if doesnt already exist
-			mask = $("#select2-drop-mask");
-			if (mask.length == 0) {
-				mask = $(document.createElement("div"));
-				mask.attr("id", "select2-drop-mask").attr("class", "select2-drop-mask");
-				mask.hide();
-				mask.appendTo(this.body());
-				mask.on("mousedown touchstart click", function (e) {
-					var dropdown = $("#select2-drop"), self;
-					if (dropdown.length > 0) {
-						self = dropdown.data("select2");
-						if (self.opts.selectOnBlur) {
-							self.selectHighlighted({noFocus: true});
-						}
-						self.close({focus: true});
-						e.preventDefault();
-						e.stopPropagation();
-					}
-				});
-			}
-
-			// ensure the mask is always right before the dropdown
-			if (this.dropdown.prev()[0] !== mask[0]) {
-				this.dropdown.before(mask);
-			}
-
-			// move the global id to the correct dropdown
-			$("#select2-drop").removeAttr("id");
-			this.dropdown.attr("id", "select2-drop");
-
-			// show the elements
-			mask.show();
-
-			this.positionDropdown();
-			this.dropdown.show();
-			this.positionDropdown();
-
-			this.dropdown.addClass("select2-drop-active");
-
-			// attach listeners to events that can change the position of the container and thus require
-			// the position of the dropdown to be updated as well so it does not come unglued from the container
-			var that = this;
-			this.container.parents().add(window).each(function () {
-				$(this).on(resize + " " + scroll + " " + orient, function (e) {
-					that.positionDropdown();
-				});
-			});
-
-
-		},
-
-		// abstract
-		close: function () {
-			if (!this.opened()) return;
-
-			var cid = this.containerId,
-				scroll = "scroll." + cid,
-				resize = "resize." + cid,
-				orient = "orientationchange." + cid;
-
-			// unbind event listeners
-			this.container.parents().add(window).each(function () {
-				$(this).off(scroll).off(resize).off(orient);
-			});
-
-			this.clearDropdownAlignmentPreference();
-
-			$("#select2-drop-mask").hide();
-			this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
-			this.dropdown.hide();
-			this.container.removeClass("select2-dropdown-open").removeClass("select2-container-active");
-			this.results.empty();
-
-
-			this.clearSearch();
-			this.search.removeClass("select2-active");
-			this.opts.element.trigger($.Event("select2-close"));
-		},
-
-		/**
-		 * Opens control, sets input value, and updates results.
-		 */
-		// abstract
-		externalSearch: function (term) {
-			this.open();
-			this.search.val(term);
-			this.updateResults(false);
-		},
-
-		// abstract
-		clearSearch: function () {
-
-		},
-
-		//abstract
-		getMaximumSelectionSize: function () {
-			return evaluate(this.opts.maximumSelectionSize);
-		},
-
-		// abstract
-		ensureHighlightVisible: function () {
-			var results = this.results, children, index, child, hb, rb, y, more;
-
-			index = this.highlight();
-
-			if (index < 0) return;
-
-			if (index == 0) {
-
-				// if the first element is highlighted scroll all the way to the top,
-				// that way any unselectable headers above it will also be scrolled
-				// into view
-
-				results.scrollTop(0);
-				return;
-			}
-
-			children = this.findHighlightableChoices().find('.select2-result-label');
-
-			child = $(children[index]);
-
-			hb = child.offset().top + child.outerHeight(true);
-
-			// if this is the last child lets also make sure select2-more-results is visible
-			if (index === children.length - 1) {
-				more = results.find("li.select2-more-results");
-				if (more.length > 0) {
-					hb = more.offset().top + more.outerHeight(true);
-				}
-			}
-
-			rb = results.offset().top + results.outerHeight(true);
-			if (hb > rb) {
-				results.scrollTop(results.scrollTop() + (hb - rb));
-			}
-			y = child.offset().top - results.offset().top;
-
-			// make sure the top of the element is visible
-			if (y < 0 && child.css('display') != 'none') {
-				results.scrollTop(results.scrollTop() + y); // y is negative
-			}
-		},
-
-		// abstract
-		findHighlightableChoices: function () {
-			return this.results.find(".select2-result-selectable:not(.select2-disabled, .select2-selected)");
-		},
-
-		// abstract
-		moveHighlight: function (delta) {
-			var choices = this.findHighlightableChoices(),
-				index = this.highlight();
-
-			while (index > -1 && index < choices.length) {
-				index += delta;
-				var choice = $(choices[index]);
-				if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
-					this.highlight(index);
-					break;
-				}
-			}
-		},
-
-		// abstract
-		highlight: function (index) {
-			var choices = this.findHighlightableChoices(),
-				choice,
-				data;
-
-			if (arguments.length === 0) {
-				return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
-			}
-
-			if (index >= choices.length) index = choices.length - 1;
-			if (index < 0) index = 0;
-
-			this.removeHighlight();
-
-			choice = $(choices[index]);
-			choice.addClass("select2-highlighted");
-
-			this.ensureHighlightVisible();
-
-			data = choice.data("select2-data");
-			if (data) {
-				this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
-			}
-		},
-
-		removeHighlight: function () {
-			this.results.find(".select2-highlighted").removeClass("select2-highlighted");
-		},
-
-		// abstract
-		countSelectableResults: function () {
-			return this.findHighlightableChoices().length;
-		},
-
-		// abstract
-		highlightUnderEvent: function (event) {
-			var el = $(event.target).closest(".select2-result-selectable");
-			if (el.length > 0 && !el.is(".select2-highlighted")) {
-				var choices = this.findHighlightableChoices();
-				this.highlight(choices.index(el));
-			} else if (el.length == 0) {
-				// if we are over an unselectable item remove all highlights
-				this.removeHighlight();
-			}
-		},
-
-		// abstract
-		loadMoreIfNeeded: function () {
-			var results = this.results,
-				more = results.find("li.select2-more-results"),
-				below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
-				page = this.resultsPage + 1,
-				self = this,
-				term = this.search.val(),
-				context = this.context;
-
-			if (more.length === 0) return;
-			below = more.offset().top - results.offset().top - results.height();
-
-			if (below <= this.opts.loadMorePadding) {
-				more.addClass("select2-active");
-				this.opts.query({
-									element: this.opts.element,
-									term: term,
-									page: page,
-									context: context,
-									matcher: this.opts.matcher,
-									callback: this.bind(function (data) {
-
-										// ignore a response if the select2 has been closed before it was received
-										if (!self.opened()) return;
-
-
-										self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context: context});
-										self.postprocessResults(data, false, false);
-
-										if (data.more === true) {
-											more.detach().appendTo(results).text(self.opts.formatLoadMore(page + 1));
-											window.setTimeout(function () {
-												self.loadMoreIfNeeded();
-											}, 10);
-										} else {
-											more.remove();
-										}
-										self.positionDropdown();
-										self.resultsPage = page;
-										self.context = data.context;
-										this.opts.element.trigger({ type: "select2-loaded", items: data });
-									})});
-			}
-		},
-
-		/**
-		 * Default tokenizer function which does nothing
-		 */
-		tokenize: function () {
-
-		},
-
-		/**
-		 * @param initial whether or not this is the call to this method right after the dropdown has been opened
-		 */
-		// abstract
-		updateResults: function (initial) {
-			var search = this.search,
-				results = this.results,
-				opts = this.opts,
-				data,
-				self = this,
-				input,
-				term = search.val(),
-				lastTerm = $.data(this.container, "select2-last-term"),
-			// sequence number used to drop out-of-order responses
-				queryNumber;
-
-			// prevent duplicate queries against the same term
-			if (initial !== true && lastTerm && equal(term, lastTerm)) return;
-
-			$.data(this.container, "select2-last-term", term);
-
-			// if the search is currently hidden we do not alter the results
-			if (initial !== true && (this.showSearchInput === false || !this.opened())) {
-				return;
-			}
-
-			function postRender() {
-				search.removeClass("select2-active");
-				self.positionDropdown();
-			}
-
-			function render(html) {
-				results.html(html);
-				postRender();
-			}
-
-			queryNumber = ++this.queryCount;
-
-			var maxSelSize = this.getMaximumSelectionSize();
-			if (maxSelSize >= 1) {
-				data = this.data();
-				if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
-					render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(maxSelSize) + "</li>");
-					return;
-				}
-			}
-
-			if (search.val().length < opts.minimumInputLength) {
-				if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
-					render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
-				} else {
-					render("");
-				}
-				if (initial && this.showSearch) this.showSearch(true);
-				return;
-			}
-
-			if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
-				if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
-					render("<li class='select2-no-results'>" + opts.formatInputTooLong(search.val(), opts.maximumInputLength) + "</li>");
-				} else {
-					render("");
-				}
-				return;
-			}
-
-			if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
-				render("<li class='select2-searching'>" + opts.formatSearching() + "</li>");
-			}
-
-			search.addClass("select2-active");
-
-			this.removeHighlight();
-
-			// give the tokenizer a chance to pre-process the input
-			input = this.tokenize();
-			if (input != undefined && input != null) {
-				search.val(input);
-			}
-
-			this.resultsPage = 1;
-
-			opts.query({
-						   element: opts.element,
-						   term: search.val(),
-						   page: this.resultsPage,
-						   context: null,
-						   matcher: opts.matcher,
-						   callback: this.bind(function (data) {
-							   var def; // default choice
-
-							   // ignore old responses
-							   if (queryNumber != this.queryCount) {
-								   return;
-							   }
-
-							   // ignore a response if the select2 has been closed before it was received
-							   if (!this.opened()) {
-								   this.search.removeClass("select2-active");
-								   return;
-							   }
-
-							   // save context, if any
-							   this.context = (data.context === undefined) ? null : data.context;
-							   // create a default choice and prepend it to the list
-							   if (this.opts.createSearchChoice && search.val() !== "") {
-								   def = this.opts.createSearchChoice.call(self, search.val(), data.results);
-								   if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
-									   if ($(data.results).filter(
-										   function () {
-											   return equal(self.id(this), self.id(def));
-										   }).length === 0) {
-										   data.results.unshift(def);
-									   }
-								   }
-							   }
-
-							   if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
-								   render("<li class='select2-no-results'>" + opts.formatNoMatches(search.val()) + "</li>");
-								   return;
-							   }
-
-							   results.empty();
-							   self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context: null});
-
-							   if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
-								   results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
-								   window.setTimeout(function () {
-									   self.loadMoreIfNeeded();
-								   }, 10);
-							   }
-
-							   this.postprocessResults(data, initial);
-
-							   postRender();
-
-							   this.opts.element.trigger({ type: "select2-loaded", items: data });
-						   })});
-		},
-
-		// abstract
-		cancel: function () {
-			this.close();
-		},
-
-		// abstract
-		blur: function () {
-			// if selectOnBlur == true, select the currently highlighted option
-			if (this.opts.selectOnBlur)
-				this.selectHighlighted({noFocus: true});
-
-			this.close();
-			this.container.removeClass("select2-container-active");
-			// synonymous to .is(':focus'), which is available in jquery >= 1.6
-			if (this.search[0] === document.activeElement) {
-				this.search.blur();
-			}
-			this.clearSearch();
-			this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
-		},
-
-		// abstract
-		focusSearch: function () {
-			focus(this.search);
-		},
-
-		// abstract
-		selectHighlighted: function (options) {
-			var index = this.highlight(),
-				highlighted = this.results.find(".select2-highlighted"),
-				data = highlighted.closest('.select2-result').data("select2-data");
-
-			if (data) {
-				this.highlight(index);
-				this.onSelect(data, options);
-			} else if (options && options.noFocus) {
-				this.close();
-			}
-		},
-
-		// abstract
-		getPlaceholder: function () {
-			var placeholderOption;
-			return this.opts.element.attr("placeholder") ||
-				this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
-				this.opts.element.data("placeholder") ||
-				this.opts.placeholder ||
-				((placeholderOption = this.getPlaceholderOption()) !== undefined ? placeholderOption.text() : undefined);
-		},
-
-		// abstract
-		getPlaceholderOption: function () {
-			if (this.select) {
-				var firstOption = this.select.children('option').first();
-				if (this.opts.placeholderOption !== undefined) {
-					//Determine the placeholder option based on the specified placeholderOption setting
-					return (this.opts.placeholderOption === "first" && firstOption) ||
-						(typeof this.opts.placeholderOption === "function" && this.opts.placeholderOption(this.select));
-				} else if (firstOption.text() === "" && firstOption.val() === "") {
-					//No explicit placeholder option specified, use the first if it's blank
-					return firstOption;
-				}
-			}
-		},
-
-		/**
-		 * Get the desired width for the container element.  This is
-		 * derived first from option `width` passed to select2, then
-		 * the inline 'style' on the original element, and finally
-		 * falls back to the jQuery calculated element width.
-		 */
-		// abstract
-		initContainerWidth: function () {
-			function resolveContainerWidth() {
-				var style, attrs, matches, i, l, attr;
-
-				if (this.opts.width === "off") {
-					return null;
-				} else if (this.opts.width === "element") {
-					return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
-				} else if (this.opts.width === "copy" || this.opts.width === "resolve") {
-					// check if there is inline style on the element that contains width
-					style = this.opts.element.attr('style');
-					if (style !== undefined) {
-						attrs = style.split(';');
-						for (i = 0, l = attrs.length; i < l; i = i + 1) {
-							attr = attrs[i].replace(/\s/g, '');
-							matches = attr.match(/^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
-							if (matches !== null && matches.length >= 1)
-								return matches[1];
-						}
-					}
-
-					if (this.opts.width === "resolve") {
-						// next check if css('width') can resolve a width that is percent based, this is sometimes possible
-						// when attached to input type=hidden or elements hidden via css
-						style = this.opts.element.css('width');
-						if (style.indexOf("%") > 0) return style;
-
-						// finally, fallback on the calculated width of the element
-						return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
-					}
-
-					return null;
-				} else if ($.isFunction(this.opts.width)) {
-					return this.opts.width();
-				} else {
-					return this.opts.width;
-				}
-			};
-
-			var width = resolveContainerWidth.call(this);
-			if (width !== null) {
-				this.container.css("width", width);
-			}
-		}
-	});
-
-	SingleSelect2 = clazz(AbstractSelect2, {
-
-		// single
-
-		createContainer: function () {
-			var container = $(document.createElement("div")).attr({
-																	  "class": "select2-container"
-																  }).html([
-																			  "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>",
-																			  "   <span class='select2-chosen'>&nbsp;</span><abbr class='select2-search-choice-close'></abbr>",
-																			  "   <span class='select2-arrow'><b></b></span>",
-																			  "</a>",
-																			  "<input class='select2-focusser select2-offscreen' type='text'/>",
-																			  "<div class='select2-drop select2-display-none'>",
-																			  "   <div class='select2-search'>",
-																			  "       <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'/>",
-																			  "   </div>",
-																			  "   <ul class='select2-results'>",
-																			  "   </ul>",
-																			  "</div>"].join(""));
-			return container;
-		},
-
-		// single
-		enableInterface: function () {
-			if (this.parent.enableInterface.apply(this, arguments)) {
-				this.focusser.prop("disabled", !this.isInterfaceEnabled());
-			}
-		},
-
-		// single
-		opening: function () {
-			var el, range, len;
-
-			if (this.opts.minimumResultsForSearch >= 0) {
-				this.showSearch(true);
-			}
-
-			this.parent.opening.apply(this, arguments);
-
-			if (this.showSearchInput !== false) {
-				// IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
-				// all other browsers handle this just fine
-
-				this.search.val(this.focusser.val());
-			}
-			this.search.focus();
-			// move the cursor to the end after focussing, otherwise it will be at the beginning and
-			// new text will appear *before* focusser.val()
-			el = this.search.get(0);
-			if (el.createTextRange) {
-				range = el.createTextRange();
-				range.collapse(false);
-				range.select();
-			} else if (el.setSelectionRange) {
-				len = this.search.val().length;
-				el.setSelectionRange(len, len);
-			}
-
-			// initializes search's value with nextSearchTerm (if defined by user)
-			// ignore nextSearchTerm if the dropdown is opened by the user pressing a letter
-			if (this.search.val() === "") {
-				if (this.nextSearchTerm != undefined) {
-					this.search.val(this.nextSearchTerm);
-					this.search.select();
-				}
-			}
-
-			this.focusser.prop("disabled", true).val("");
-			this.updateResults(true);
-			this.opts.element.trigger($.Event("select2-open"));
-		},
-
-		// single
-		close: function (params) {
-			if (!this.opened()) return;
-			this.parent.close.apply(this, arguments);
-
-			params = params || {focus: true};
-			this.focusser.removeAttr("disabled");
-
-			if (params.focus) {
-				this.focusser.focus();
-			}
-		},
-
-		// single
-		focus: function () {
-			if (this.opened()) {
-				this.close();
-			} else {
-				this.focusser.removeAttr("disabled");
-				this.focusser.focus();
-			}
-		},
-
-		// single
-		isFocused: function () {
-			return this.container.hasClass("select2-container-active");
-		},
-
-		// single
-		cancel: function () {
-			this.parent.cancel.apply(this, arguments);
-			this.focusser.removeAttr("disabled");
-			this.focusser.focus();
-		},
-
-		// single
-		destroy: function () {
-			$("label[for='" + this.focusser.attr('id') + "']")
-				.attr('for', this.opts.element.attr("id"));
-			this.parent.destroy.apply(this, arguments);
-		},
-
-		// single
-		initContainer: function () {
-
-			var selection,
-				container = this.container,
-				dropdown = this.dropdown;
-
-			if (this.opts.minimumResultsForSearch < 0) {
-				this.showSearch(false);
-			} else {
-				this.showSearch(true);
-			}
-
-			this.selection = selection = container.find(".select2-choice");
-
-			this.focusser = container.find(".select2-focusser");
-
-			// rewrite labels from original element to focusser
-			this.focusser.attr("id", "s2id_autogen" + nextUid());
-
-			$("label[for='" + this.opts.element.attr("id") + "']")
-				.attr('for', this.focusser.attr('id'));
-
-			this.focusser.attr("tabindex", this.elementTabIndex);
-
-			this.search.on("keydown", this.bind(function (e) {
-				if (!this.isInterfaceEnabled()) return;
-
-				if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
-					// prevent the page from scrolling
-					killEvent(e);
-					return;
-				}
-
-				switch (e.which) {
-					case KEY.UP:
-					case KEY.DOWN:
-						this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
-						killEvent(e);
-						return;
-					case KEY.ENTER:
-						this.selectHighlighted();
-						killEvent(e);
-						return;
-					case KEY.TAB:
-						this.selectHighlighted({noFocus: true});
-						return;
-					case KEY.ESC:
-						this.cancel(e);
-						killEvent(e);
-						return;
-				}
-			}));
-
-			this.search.on("blur", this.bind(function (e) {
-				// a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
-				// without this the search field loses focus which is annoying
-				if (document.activeElement === this.body().get(0)) {
-					window.setTimeout(this.bind(function () {
-						this.search.focus();
-					}), 0);
-				}
-			}));
-
-			this.focusser.on("keydown", this.bind(function (e) {
-				if (!this.isInterfaceEnabled()) return;
-
-				if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
-					return;
-				}
-
-				if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
-					killEvent(e);
-					return;
-				}
-
-				if (e.which == KEY.DOWN || e.which == KEY.UP
-					|| (e.which == KEY.ENTER && this.opts.openOnEnter)) {
-
-					if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) return;
-
-					this.open();
-					killEvent(e);
-					return;
-				}
-
-				if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
-					if (this.opts.allowClear) {
-						this.clear();
-					}
-					killEvent(e);
-					return;
-				}
-			}));
-
-
-			installKeyUpChangeEvent(this.focusser);
-			this.focusser.on("keyup-change input", this.bind(function (e) {
-				if (this.opts.minimumResultsForSearch >= 0) {
-					e.stopPropagation();
-					if (this.opened()) return;
-					this.open();
-				}
-			}));
-
-			selection.on("mousedown", "abbr", this.bind(function (e) {
-				if (!this.isInterfaceEnabled()) return;
-				this.clear();
-				killEventImmediately(e);
-				this.close();
-				this.selection.focus();
-			}));
-
-			selection.on("mousedown", this.bind(function (e) {
-
-				if (!this.container.hasClass("select2-container-active")) {
-					this.opts.element.trigger($.Event("select2-focus"));
-				}
-
-				if (this.opened()) {
-					this.close();
-				} else if (this.isInterfaceEnabled()) {
-					this.open();
-				}
-
-				killEvent(e);
-			}));
-
-			dropdown.on("mousedown", this.bind(function () {
-				this.search.focus();
-			}));
-
-			selection.on("focus", this.bind(function (e) {
-				killEvent(e);
-			}));
-
-			this.focusser.on("focus", this.bind(function () {
-					if (!this.container.hasClass("select2-container-active")) {
-						this.opts.element.trigger($.Event("select2-focus"));
-					}
-					this.container.addClass("select2-container-active");
-				})).on("blur", this.bind(function () {
-					if (!this.opened()) {
-						this.container.removeClass("select2-container-active");
-						this.opts.element.trigger($.Event("select2-blur"));
-					}
-				}));
-			this.search.on("focus", this.bind(function () {
-				if (!this.container.hasClass("select2-container-active")) {
-					this.opts.element.trigger($.Event("select2-focus"));
-				}
-				this.container.addClass("select2-container-active");
-			}));
-
-			this.initContainerWidth();
-			this.opts.element.addClass("select2-offscreen");
-			this.setPlaceholder();
-
-		},
-
-		// single
-		clear: function (triggerChange) {
-			var data = this.selection.data("select2-data");
-			if (data) { // guard against queued quick consecutive clicks
-				var evt = $.Event("select2-clearing");
-				this.opts.element.trigger(evt);
-				if (evt.isDefaultPrevented()) {
-					return;
-				}
-				var placeholderOption = this.getPlaceholderOption();
-				this.opts.element.val(placeholderOption ? placeholderOption.val() : "");
-				this.selection.find(".select2-chosen").empty();
-				this.selection.removeData("select2-data");
-				this.setPlaceholder();
-
-				if (triggerChange !== false) {
-					this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
-					this.triggerChange({removed: data});
-				}
-			}
-		},
-
-		/**
-		 * Sets selection based on source element's value
-		 */
-		// single
-		initSelection: function () {
-			var selected;
-			if (this.isPlaceholderOptionSelected()) {
-				this.updateSelection(null);
-				this.close();
-				this.setPlaceholder();
-			} else {
-				var self = this;
-				this.opts.initSelection.call(null, this.opts.element, function (selected) {
-					if (selected !== undefined && selected !== null) {
-						self.updateSelection(selected);
-						self.close();
-						self.setPlaceholder();
-					}
-				});
-			}
-		},
-
-		isPlaceholderOptionSelected: function () {
-			var placeholderOption;
-			if (!this.getPlaceholder()) return false; // no placeholder specified so no option should be considered
-			return ((placeholderOption = this.getPlaceholderOption()) !== undefined && placeholderOption.prop("selected"))
-				|| (this.opts.element.val() === "")
-				|| (this.opts.element.val() === undefined)
-				|| (this.opts.element.val() === null);
-		},
-
-		// single
-		prepareOpts: function () {
-			var opts = this.parent.prepareOpts.apply(this, arguments),
-				self = this;
-
-			if (opts.element.get(0).tagName.toLowerCase() === "select") {
-				// install the selection initializer
-				opts.initSelection = function (element, callback) {
-					var selected = element.find("option").filter(function () {
-						return this.selected
-					});
-					// a single select box always has a value, no need to null check 'selected'
-					callback(self.optionToData(selected));
-				};
-			} else if ("data" in opts) {
-				// install default initSelection when applied to hidden input and data is local
-				opts.initSelection = opts.initSelection || function (element, callback) {
-					var id = element.val();
-					//search in data by id, storing the actual matching item
-					var match = null;
-					opts.query({
-								   matcher: function (term, text, el) {
-									   var is_match = equal(id, opts.id(el));
-									   if (is_match) {
-										   match = el;
-									   }
-									   return is_match;
-								   },
-								   callback: !$.isFunction(callback) ? $.noop : function () {
-									   callback(match);
-								   }
-							   });
-				};
-			}
-
-			return opts;
-		},
-
-		// single
-		getPlaceholder: function () {
-			// if a placeholder is specified on a single select without a valid placeholder option ignore it
-			if (this.select) {
-				if (this.getPlaceholderOption() === undefined) {
-					return undefined;
-				}
-			}
-
-			return this.parent.getPlaceholder.apply(this, arguments);
-		},
-
-		// single
-		setPlaceholder: function () {
-			var placeholder = this.getPlaceholder();
-
-			if (this.isPlaceholderOptionSelected() && placeholder !== undefined) {
-
-				// check for a placeholder option if attached to a select
-				if (this.select && this.getPlaceholderOption() === undefined) return;
-
-				this.selection.find(".select2-chosen").html(this.opts.escapeMarkup(placeholder));
-
-				this.selection.addClass("select2-default");
-
-				this.container.removeClass("select2-allowclear");
-			}
-		},
-
-		// single
-		postprocessResults: function (data, initial, noHighlightUpdate) {
-			var selected = 0, self = this, showSearchInput = true;
-
-			// find the selected element in the result list
-
-			this.findHighlightableChoices().each2(function (i, elm) {
-				if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
-					selected = i;
-					return false;
-				}
-			});
-
-			// and highlight it
-			if (noHighlightUpdate !== false) {
-				if (initial === true && selected >= 0) {
-					this.highlight(selected);
-				} else {
-					this.highlight(0);
-				}
-			}
-
-			// hide the search box if this is the first we got the results and there are enough of them for search
-
-			if (initial === true) {
-				var min = this.opts.minimumResultsForSearch;
-				if (min >= 0) {
-					this.showSearch(countResults(data.results) >= min);
-				}
-			}
-		},
-
-		// single
-		showSearch: function (showSearchInput) {
-			if (this.showSearchInput === showSearchInput) return;
-
-			this.showSearchInput = showSearchInput;
-
-			this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
-			this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
-			//add "select2-with-searchbox" to the container if search box is shown
-			$(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
-		},
-
-		// single
-		onSelect: function (data, options) {
-
-			if (!this.triggerSelect(data)) {
-				return;
-			}
-
-			var old = this.opts.element.val(),
-				oldData = this.data();
-
-			this.opts.element.val(this.id(data));
-			this.updateSelection(data);
-
-			this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
-
-			this.nextSearchTerm = this.opts.nextSearchTerm(data, this.search.val());
-			this.close();
-
-			if (!options || !options.noFocus)
-				this.focusser.focus();
-
-			if (!equal(old, this.id(data))) {
-				this.triggerChange({added: data, removed: oldData});
-			}
-		},
-
-		// single
-		updateSelection: function (data) {
-
-			var container = this.selection.find(".select2-chosen"), formatted, cssClass;
-
-			this.selection.data("select2-data", data);
-
-			container.empty();
-			if (data !== null) {
-				formatted = this.opts.formatSelection(data, container, this.opts.escapeMarkup);
-			}
-			if (formatted !== undefined) {
-				container.append(formatted);
-			}
-			cssClass = this.opts.formatSelectionCssClass(data, container);
-			if (cssClass !== undefined) {
-				container.addClass(cssClass);
-			}
-
-			this.selection.removeClass("select2-default");
-
-			if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
-				this.container.addClass("select2-allowclear");
-			}
-		},
-
-		// single
-		val: function () {
-			var val,
-				triggerChange = false,
-				data = null,
-				self = this,
-				oldData = this.data();
-
-			if (arguments.length === 0) {
-				return this.opts.element.val();
-			}
-
-			val = arguments[0];
-
-			if (arguments.length > 1) {
-				triggerChange = arguments[1];
-			}
-
-			if (this.select) {
-				this.select
-					.val(val)
-					.find("option").filter(function () {
-											   return this.selected
-										   }).each2(function (i, elm) {
-														data = self.optionToData(elm);
-														return false;
-													});
-				this.updateSelection(data);
-				this.setPlaceholder();
-				if (triggerChange) {
-					this.triggerChange({added: data, removed: oldData});
-				}
-			} else {
-				// val is an id. !val is true for [undefined,null,'',0] - 0 is legal
-				if (!val && val !== 0) {
-					this.clear(triggerChange);
-					return;
-				}
-				if (this.opts.initSelection === undefined) {
-					throw new Error("cannot call val() if initSelection() is not defined");
-				}
-				this.opts.element.val(val);
-				this.opts.initSelection(this.opts.element, function (data) {
-					self.opts.element.val(!data ? "" : self.id(data));
-					self.updateSelection(data);
-					self.setPlaceholder();
-					if (triggerChange) {
-						self.triggerChange({added: data, removed: oldData});
-					}
-				});
-			}
-		},
-
-		// single
-		clearSearch: function () {
-			this.search.val("");
-			this.focusser.val("");
-		},
-
-		// single
-		data: function (value) {
-			var data,
-				triggerChange = false;
-
-			if (arguments.length === 0) {
-				data = this.selection.data("select2-data");
-				if (data == undefined) data = null;
-				return data;
-			} else {
-				if (arguments.length > 1) {
-					triggerChange = arguments[1];
-				}
-				if (!value) {
-					this.clear(triggerChange);
-				} else {
-					data = this.data();
-					this.opts.element.val(!value ? "" : this.id(value));
-					this.updateSelection(value);
-					if (triggerChange) {
-						this.triggerChange({added: value, removed: data});
-					}
-				}
-			}
-		}
-	});
-
-	MultiSelect2 = clazz(AbstractSelect2, {
-
-		// multi
-		createContainer: function () {
-			var container = $(document.createElement("div")).attr({
-																	  "class": "select2-container select2-container-multi"
-																  }).html([
-																			  "<ul class='select2-choices'>",
-																			  "  <li class='select2-search-field'>",
-																			  "    <input type='text' autocomplete='off' autocorrect='off' autocapitalize='off' spellcheck='false' class='select2-input'>",
-																			  "  </li>",
-																			  "  <span class='select2-arrow'><b></b></span>",
-																			  "</ul>",
-																			  "<div class='select2-drop select2-drop-multi select2-display-none'>",
-																			  "   <ul class='select2-results'>",
-																			  "   </ul>",
-																			  "</div>"].join(""));
-			return container;
-		},
-
-		// multi
-		prepareOpts: function () {
-			var opts = this.parent.prepareOpts.apply(this, arguments),
-				self = this;
-
-			// TODO validate placeholder is a string if specified
-
-			if (opts.element.get(0).tagName.toLowerCase() === "select") {
-				// install sthe selection initializer
-				opts.initSelection = function (element, callback) {
-
-					var data = [];
-
-					element.find("option").filter(function () {
-						return this.selected
-					}).each2(function (i, elm) {
-						data.push(self.optionToData(elm));
-					});
-					callback(data);
-				};
-			} else if ("data" in opts) {
-				// install default initSelection when applied to hidden input and data is local
-				opts.initSelection = opts.initSelection || function (element, callback) {
-					var ids = splitVal(element.val(), opts.separator);
-					//search in data by array of ids, storing matching items in a list
-					var matches = [];
-					opts.query({
-								   matcher: function (term, text, el) {
-									   var is_match = $.grep(ids,function (id) {
-										   return equal(id, opts.id(el));
-									   }).length;
-									   if (is_match) {
-										   matches.push(el);
-									   }
-									   return is_match;
-								   },
-								   callback: !$.isFunction(callback) ? $.noop : function () {
-									   // reorder matches based on the order they appear in the ids array because right now
-									   // they are in the order in which they appear in data array
-									   var ordered = [];
-									   for (var i = 0; i < ids.length; i++) {
-										   var id = ids[i];
-										   for (var j = 0; j < matches.length; j++) {
-											   var match = matches[j];
-											   if (equal(id, opts.id(match))) {
-												   ordered.push(match);
-												   matches.splice(j, 1);
-												   break;
-											   }
-										   }
-									   }
-									   callback(ordered);
-								   }
-							   });
-				};
-			}
-
-			return opts;
-		},
-
-		// multi
-		selectChoice: function (choice) {
-
-			var selected = this.container.find(".select2-search-choice-focus");
-			if (selected.length && choice && choice[0] == selected[0]) {
-
-			} else {
-				if (selected.length) {
-					this.opts.element.trigger("choice-deselected", selected);
-				}
-				selected.removeClass("select2-search-choice-focus");
-				if (choice && choice.length) {
-					this.close();
-					choice.addClass("select2-search-choice-focus");
-					this.opts.element.trigger("choice-selected", choice);
-				}
-			}
-		},
-
-		// multi
-		destroy: function () {
-			$("label[for='" + this.search.attr('id') + "']")
-				.attr('for', this.opts.element.attr("id"));
-			this.parent.destroy.apply(this, arguments);
-		},
-
-		// multi
-		initContainer: function () {
-
-			var selector = ".select2-choices", selection;
-
-			this.searchContainer = this.container.find(".select2-search-field");
-			this.selection = selection = this.container.find(selector);
-
-			var _this = this;
-			this.selection.on("click", ".select2-search-choice:not(.select2-locked)", function (e) {
-				//killEvent(e);
-				_this.search[0].focus();
-				_this.selectChoice($(this));
-			});
-
-			// rewrite labels from original element to focusser
-			this.search.attr("id", "s2id_autogen" + nextUid());
-			$("label[for='" + this.opts.element.attr("id") + "']")
-				.attr('for', this.search.attr('id'));
-
-			this.search.on("input paste", this.bind(function () {
-				if (!this.isInterfaceEnabled()) return;
-				if (!this.opened()) {
-					this.open();
-				}
-			}));
-
-			this.search.attr("tabindex", this.elementTabIndex);
-
-			this.keydowns = 0;
-			this.search.on("keydown", this.bind(function (e) {
-				if (!this.isInterfaceEnabled()) return;
-
-				++this.keydowns;
-				var selected = selection.find(".select2-search-choice-focus");
-				var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
-				var next = selected.next(".select2-search-choice:not(.select2-locked)");
-				var pos = getCursorInfo(this.search);
-
-				if (selected.length &&
-					(e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
-					var selectedChoice = selected;
-					if (e.which == KEY.LEFT && prev.length) {
-						selectedChoice = prev;
-					}
-					else if (e.which == KEY.RIGHT) {
-						selectedChoice = next.length ? next : null;
-					}
-					else if (e.which === KEY.BACKSPACE) {
-						this.unselect(selected.first());
-						this.search.width(10);
-						selectedChoice = prev.length ? prev : next;
-					} else if (e.which == KEY.DELETE) {
-						this.unselect(selected.first());
-						this.search.width(10);
-						selectedChoice = next.length ? next : null;
-					} else if (e.which == KEY.ENTER) {
-						selectedChoice = null;
-					}
-
-					this.selectChoice(selectedChoice);
-					killEvent(e);
-					if (!selectedChoice || !selectedChoice.length) {
-						this.open();
-					}
-					return;
-				} else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
-					|| e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
-
-					this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
-					killEvent(e);
-					return;
-				} else {
-					this.selectChoice(null);
-				}
-
-				if (this.opened()) {
-					switch (e.which) {
-						case KEY.UP:
-						case KEY.DOWN:
-							this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
-							killEvent(e);
-							return;
-						case KEY.ENTER:
-							this.selectHighlighted();
-							killEvent(e);
-							return;
-						case KEY.TAB:
-							this.selectHighlighted({noFocus: true});
-							this.close();
-							return;
-						case KEY.ESC:
-							this.cancel(e);
-							killEvent(e);
-							return;
-					}
-				}
-
-				if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
-					|| e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
-					return;
-				}
-
-				if (e.which === KEY.ENTER) {
-					if (this.opts.openOnEnter === false) {
-						return;
-					} else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
-						return;
-					}
-				}
-
-				this.open();
-
-				if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
-					// prevent the page from scrolling
-					killEvent(e);
-				}
-
-				if (e.which === KEY.ENTER) {
-					// prevent form from being submitted
-					killEvent(e);
-				}
-
-			}));
-
-			this.search.on("keyup", this.bind(function (e) {
-				this.keydowns = 0;
-				this.resizeSearch();
-			})
-			);
-
-			this.search.on("blur", this.bind(function (e) {
-				this.container.removeClass("select2-container-active");
-				this.search.removeClass("select2-focused");
-				this.selectChoice(null);
-				if (!this.opened()) this.clearSearch();
-				e.stopImmediatePropagation();
-				this.opts.element.trigger($.Event("select2-blur"));
-			}));
-
-			this.container.on("click", selector, this.bind(function (e) {
-				if (!this.isInterfaceEnabled()) return;
-				if ($(e.target).closest(".select2-search-choice").length > 0) {
-					// clicked inside a select2 search choice, do not open
-					return;
-				}
-				this.selectChoice(null);
-				this.clearPlaceholder();
-				if (!this.container.hasClass("select2-container-active")) {
-					this.opts.element.trigger($.Event("select2-focus"));
-				}
-				this.open();
-				this.focusSearch();
-				e.preventDefault();
-			}));
-
-			this.container.on("focus", selector, this.bind(function () {
-				if (!this.isInterfaceEnabled()) return;
-				if (!this.container.hasClass("select2-container-active")) {
-					this.opts.element.trigger($.Event("select2-focus"));
-				}
-				this.container.addClass("select2-container-active");
-				this.dropdown.addClass("select2-drop-active");
-				this.clearPlaceholder();
-			}));
-
-			this.initContainerWidth();
-			this.opts.element.addClass("select2-offscreen");
-
-			// set the placeholder if necessary
-			this.clearSearch();
-		},
-
-		// multi
-		enableInterface: function () {
-			if (this.parent.enableInterface.apply(this, arguments)) {
-				this.search.prop("disabled", !this.isInterfaceEnabled());
-			}
-		},
-
-		// multi
-		initSelection: function () {
-			var data;
-			if (this.opts.element.val() === "" && this.opts.element.text() === "") {
-				this.updateSelection([]);
-				this.close();
-				// set the placeholder if necessary
-				this.clearSearch();
-			}
-			if (this.select || this.opts.element.val() !== "") {
-				var self = this;
-				this.opts.initSelection.call(null, this.opts.element, function (data) {
-					if (data !== undefined && data !== null) {
-						self.updateSelection(data);
-						self.close();
-						// set the placeholder if necessary
-						self.clearSearch();
-					}
-				});
-			}
-		},
-
-		// multi
-		clearSearch: function () {
-			var placeholder = this.getPlaceholder(),
-				maxWidth = this.getMaxSearchWidth();
-
-			if (placeholder !== undefined && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
-				this.search.val(placeholder).addClass("select2-default");
-				// stretch the search box to full width of the container so as much of the placeholder is visible as possible
-				// we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
-				this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
-			} else {
-				this.search.val("").width(10);
-			}
-		},
-
-		// multi
-		clearPlaceholder: function () {
-			if (this.search.hasClass("select2-default")) {
-				this.search.val("").removeClass("select2-default");
-			}
-		},
-
-		// multi
-		opening: function () {
-			this.clearPlaceholder(); // should be done before super so placeholder is not used to search
-			this.resizeSearch();
-
-			this.parent.opening.apply(this, arguments);
-
-			this.focusSearch();
-
-			this.updateResults(true);
-			this.search.focus();
-			this.opts.element.trigger($.Event("select2-open"));
-		},
-
-		// multi
-		close: function () {
-			if (!this.opened()) return;
-			this.parent.close.apply(this, arguments);
-		},
-
-		// multi
-		focus: function () {
-			this.close();
-			this.search.focus();
-		},
-
-		// multi
-		isFocused: function () {
-			return this.search.hasClass("select2-focused");
-		},
-
-		// multi
-		updateSelection: function (data) {
-			var ids = [], filtered = [], self = this;
-
-			// filter out duplicates
-			$(data).each(function () {
-				if (indexOf(self.id(this), ids) < 0) {
-					ids.push(self.id(this));
-					filtered.push(this);
-				}
-			});
-			data = filtered;
-
-			this.selection.find(".select2-search-choice").remove();
-			$(data).each(function () {
-				self.addSelectedChoice(this);
-			});
-			self.postprocessResults();
-		},
-
-		// multi
-		tokenize: function () {
-			var input = this.search.val();
-			input = this.opts.tokenizer.call(this, input, this.data(), this.bind(this.onSelect), this.opts);
-			if (input != null && input != undefined) {
-				this.search.val(input);
-				if (input.length > 0) {
-					this.open();
-				}
-			}
-
-		},
-
-		// multi
-		onSelect: function (data, options) {
-
-			if (!this.triggerSelect(data)) {
-				return;
-			}
-
-			this.addSelectedChoice(data);
-
-			this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
-
-			if (this.select || !this.opts.closeOnSelect) this.postprocessResults(data, false, this.opts.closeOnSelect === true);
-
-			if (this.opts.closeOnSelect) {
-				this.close();
-				this.search.width(10);
-			} else {
-				if (this.countSelectableResults() > 0) {
-					this.search.width(10);
-					this.resizeSearch();
-					if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
-						// if we reached max selection size repaint the results so choices
-						// are replaced with the max selection reached message
-						this.updateResults(true);
-					}
-					this.positionDropdown();
-				} else {
-					// if nothing left to select close
-					this.close();
-					this.search.width(10);
-				}
-			}
-
-			// since its not possible to select an element that has already been
-			// added we do not need to check if this is a new element before firing change
-			this.triggerChange({ added: data });
-
-			if (!options || !options.noFocus)
-				this.focusSearch();
-		},
-
-		// multi
-		cancel: function () {
-			this.close();
-			this.focusSearch();
-		},
-
-		addSelectedChoice: function (data) {
-			var enableChoice = !data.locked,
-				enabledItem = $(
-					"<li class='select2-search-choice'>" +
-						"    <div></div>" +
-						"    <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" +
-						"</li>"),
-				disabledItem = $(
-					"<li class='select2-search-choice select2-locked'>" +
-						"<div></div>" +
-						"</li>");
-			var choice = enableChoice ? enabledItem : disabledItem,
-				id = this.id(data),
-				val = this.getVal(),
-				formatted,
-				cssClass;
-
-			formatted = this.opts.formatSelection(data, choice.find("div"), this.opts.escapeMarkup);
-			if (formatted != undefined) {
-				choice.find("div").replaceWith("<div>" + formatted + "</div>");
-			}
-			cssClass = this.opts.formatSelectionCssClass(data, choice.find("div"));
-			if (cssClass != undefined) {
-				choice.addClass(cssClass);
-			}
-
-			if (enableChoice) {
-				choice.find(".select2-search-choice-close")
-					.on("mousedown", killEvent)
-					.on("click dblclick", this.bind(function (e) {
-						if (!this.isInterfaceEnabled()) return;
-
-						$(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function () {
-							this.unselect($(e.target));
-							this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
-							this.close();
-							this.focusSearch();
-						})).dequeue();
-						killEvent(e);
-					})).on("focus", this.bind(function () {
-						if (!this.isInterfaceEnabled()) return;
-						this.container.addClass("select2-container-active");
-						this.dropdown.addClass("select2-drop-active");
-					}));
-			}
-
-			choice.data("select2-data", data);
-			choice.insertBefore(this.searchContainer);
-
-			val.push(id);
-			this.setVal(val);
-		},
-
-		// multi
-		unselect: function (selected) {
-			var val = this.getVal(),
-				data,
-				index;
-			selected = selected.closest(".select2-search-choice");
-
-			if (selected.length === 0) {
-				throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
-			}
-
-			data = selected.data("select2-data");
-
-			if (!data) {
-				// prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
-				// and invoked on an element already removed
-				return;
-			}
-
-			while ((index = indexOf(this.id(data), val)) >= 0) {
-				val.splice(index, 1);
-				this.setVal(val);
-				if (this.select) this.postprocessResults();
-			}
-
-			var evt = $.Event("select2-removing");
-			evt.val = this.id(data);
-			evt.choice = data;
-			this.opts.element.trigger(evt);
-
-			if (evt.isDefaultPrevented()) {
-				return;
-			}
-
-			selected.remove();
-
-			this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
-			this.triggerChange({ removed: data });
-		},
-
-		// multi
-		postprocessResults: function (data, initial, noHighlightUpdate) {
-			var val = this.getVal(),
-				choices = this.results.find(".select2-result"),
-				compound = this.results.find(".select2-result-with-children"),
-				self = this;
-
-			choices.each2(function (i, choice) {
-				var id = self.id(choice.data("select2-data"));
-				if (indexOf(id, val) >= 0) {
-					choice.addClass("select2-selected");
-					// mark all children of the selected parent as selected
-					choice.find(".select2-result-selectable").addClass("select2-selected");
-				}
-			});
-
-			compound.each2(function (i, choice) {
-				// hide an optgroup if it doesnt have any selectable children
-				if (!choice.is('.select2-result-selectable')
-					&& choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
-					choice.addClass("select2-selected");
-				}
-			});
-
-			if (this.highlight() == -1 && noHighlightUpdate !== false) {
-				self.highlight(0);
-			}
-
-			//If all results are chosen render formatNoMAtches
-			if (!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0) {
-				if (!data || data && !data.more && this.results.find(".select2-no-results").length === 0) {
-					if (checkFormatter(self.opts.formatNoMatches, "formatNoMatches")) {
-						this.results.append("<li class='select2-no-results'>" + self.opts.formatNoMatches(self.search.val()) + "</li>");
-					}
-				}
-			}
-
-		},
-
-		// multi
-		getMaxSearchWidth: function () {
-			return this.selection.width() - getSideBorderPadding(this.search);
-		},
-
-		// multi
-		resizeSearch: function () {
-			var minimumWidth, left, maxWidth, containerLeft, searchWidth,
-				sideBorderPadding = getSideBorderPadding(this.search);
-
-			minimumWidth = measureTextWidth(this.search) + 10;
-
-			left = this.search.offset().left;
-
-			maxWidth = this.selection.width();
-			containerLeft = this.selection.offset().left;
-
-			searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
-
-			if (searchWidth < minimumWidth) {
-				searchWidth = maxWidth - sideBorderPadding;
-			}
-
-			if (searchWidth < 40) {
-				searchWidth = maxWidth - sideBorderPadding;
-			}
-
-			if (searchWidth <= 0) {
-				searchWidth = minimumWidth;
-			}
-
-			this.search.width(Math.floor(searchWidth));
-		},
-
-		// multi
-		getVal: function () {
-			var val;
-			if (this.select) {
-				val = this.select.val();
-				return val === null ? [] : val;
-			} else {
-				val = this.opts.element.val();
-				return splitVal(val, this.opts.separator);
-			}
-		},
-
-		// multi
-		setVal: function (val) {
-			var unique;
-			if (this.select) {
-				this.select.val(val);
-			} else {
-				unique = [];
-				// filter out duplicates
-				$(val).each(function () {
-					if (indexOf(this, unique) < 0) unique.push(this);
-				});
-				this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
-			}
-		},
-
-		// multi
-		buildChangeDetails: function (old, current) {
-			var current = current.slice(0),
-				old = old.slice(0);
-
-			// remove intersection from each array
-			for (var i = 0; i < current.length; i++) {
-				for (var j = 0; j < old.length; j++) {
-					if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
-						current.splice(i, 1);
-						if (i > 0) {
-							i--;
-						}
-						old.splice(j, 1);
-						j--;
-					}
-				}
-			}
-
-			return {added: current, removed: old};
-		},
-
-
-		// multi
-		val: function (val, triggerChange) {
-			var oldData, self = this;
-
-			if (arguments.length === 0) {
-				return this.getVal();
-			}
-
-			oldData = this.data();
-			if (!oldData.length) oldData = [];
-
-			// val is an id. !val is true for [undefined,null,'',0] - 0 is legal
-			if (!val && val !== 0) {
-				this.opts.element.val("");
-				this.updateSelection([]);
-				this.clearSearch();
-				if (triggerChange) {
-					this.triggerChange({added: this.data(), removed: oldData});
-				}
-				return;
-			}
-
-			// val is a list of ids
-			this.setVal(val);
-
-			if (this.select) {
-				this.opts.initSelection(this.select, this.bind(this.updateSelection));
-				if (triggerChange) {
-					this.triggerChange(this.buildChangeDetails(oldData, this.data()));
-				}
-			} else {
-				if (this.opts.initSelection === undefined) {
-					throw new Error("val() cannot be called if initSelection() is not defined");
-				}
-
-				this.opts.initSelection(this.opts.element, function (data) {
-					var ids = $.map(data, self.id);
-					self.setVal(ids);
-					self.updateSelection(data);
-					self.clearSearch();
-					if (triggerChange) {
-						self.triggerChange(self.buildChangeDetails(oldData, self.data()));
-					}
-				});
-			}
-			this.clearSearch();
-		},
-
-		// multi
-		onSortStart: function () {
-			if (this.select) {
-				throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
-			}
-
-			// collapse search field into 0 width so its container can be collapsed as well
-			this.search.width(0);
-			// hide the container
-			this.searchContainer.hide();
-		},
-
-		// multi
-		onSortEnd: function () {
-
-			var val = [], self = this;
-
-			// show search and move it to the end of the list
-			this.searchContainer.show();
-			// make sure the search container is the last item in the list
-			this.searchContainer.appendTo(this.searchContainer.parent());
-			// since we collapsed the width in dragStarted, we resize it here
-			this.resizeSearch();
-
-			// update selection
-			this.selection.find(".select2-search-choice").each(function () {
-				val.push(self.opts.id($(this).data("select2-data")));
-			});
-			this.setVal(val);
-			this.triggerChange();
-		},
-
-		// multi
-		data: function (values, triggerChange) {
-			var self = this, ids, old;
-			if (arguments.length === 0) {
-				return this.selection
-					.find(".select2-search-choice")
-					.map(function () {
-							 return $(this).data("select2-data");
-						 })
-					.get();
-			} else {
-				old = this.data();
-				if (!values) {
-					values = [];
-				}
-				ids = $.map(values, function (e) {
-					return self.opts.id(e);
-				});
-				this.setVal(ids);
-				this.updateSelection(values);
-				this.clearSearch();
-				if (triggerChange) {
-					this.triggerChange(this.buildChangeDetails(old, this.data()));
-				}
-			}
-		}
-	});
-
-	$.fn.select2 = function () {
-
-		var args = Array.prototype.slice.call(arguments, 0),
-			opts,
-			select2,
-			method, value, multiple,
-			allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "dropdown", "onSortStart", "onSortEnd", "enable", "disable", "readonly", "positionDropdown", "data", "search"],
-			valueMethods = ["opened", "isFocused", "container", "dropdown"],
-			propertyMethods = ["val", "data"],
-			methodsMap = { search: "externalSearch" };
-
-		this.each(function () {
-			if (args.length === 0 || typeof(args[0]) === "object") {
-				opts = args.length === 0 ? {} : $.extend({}, args[0]);
-				opts.element = $(this);
-
-				if (opts.element.get(0).tagName.toLowerCase() === "select") {
-					multiple = opts.element.prop("multiple");
-				} else {
-					multiple = opts.multiple || false;
-					if ("tags" in opts) {
-						opts.multiple = multiple = true;
-					}
-				}
-
-				select2 = multiple ? new MultiSelect2() : new SingleSelect2();
-				select2.init(opts);
-			} else if (typeof(args[0]) === "string") {
-
-				if (indexOf(args[0], allowedMethods) < 0) {
-					throw "Unknown method: " + args[0];
-				}
-
-				value = undefined;
-				select2 = $(this).data("select2");
-				if (select2 === undefined) return;
-
-				method = args[0];
-
-				if (method === "container") {
-					value = select2.container;
-				} else if (method === "dropdown") {
-					value = select2.dropdown;
-				} else {
-					if (methodsMap[method]) method = methodsMap[method];
-
-					value = select2[method].apply(select2, args.slice(1));
-				}
-				if (indexOf(args[0], valueMethods) >= 0
-					|| (indexOf(args[0], propertyMethods) && args.length == 1)) {
-					return false; // abort the iteration, ready to return first matched value
-				}
-			} else {
-				throw "Invalid arguments to select2 plugin: " + args;
-			}
-		});
-		return (value === undefined) ? this : value;
-	};
-
-	// plugin defaults, accessible to users
-	$.fn.select2.defaults = {
-		width: "copy",
-		loadMorePadding: 0,
-		closeOnSelect: true,
-		openOnEnter: true,
-		containerCss: {},
-		dropdownCss: {},
-		containerCssClass: "",
-		dropdownCssClass: "",
-		formatResult: function (result, container, query, escapeMarkup) {
-			var markup = [];
-			markMatch(result.text, query.term, markup, escapeMarkup);
-			return markup.join("");
-		},
-		formatSelection: function (data, container, escapeMarkup) {
-			return data ? escapeMarkup(data.text) : undefined;
-		},
-		sortResults: function (results, container, query) {
-			return results;
-		},
-		formatResultCssClass: function (data) {
-			return undefined;
-		},
-		formatSelectionCssClass: function (data, container) {
-			return undefined;
-		},
-		formatNoMatches: function () {
-			return "No matches found";
-		},
-		formatInputTooShort: function (input, min) {
-			var n = min - input.length;
-			return "Please enter " + n + " more character" + (n == 1 ? "" : "s");
-		},
-		formatInputTooLong: function (input, max) {
-			var n = input.length - max;
-			return "Please delete " + n + " character" + (n == 1 ? "" : "s");
-		},
-		formatSelectionTooBig: function (limit) {
-			return "You can only select " + limit + " item" + (limit == 1 ? "" : "s");
-		},
-		formatLoadMore: function (pageNumber) {
-			return "Loading more results...";
-		},
-		formatSearching: function () {
-			return "Searching...";
-		},
-		minimumResultsForSearch: 0,
-		minimumInputLength: 0,
-		maximumInputLength: null,
-		maximumSelectionSize: 0,
-		id: function (e) {
-			return e.id;
-		},
-		matcher: function (term, text) {
-			return stripDiacritics('' + text).toUpperCase().indexOf(stripDiacritics('' + term).toUpperCase()) >= 0;
-		},
-		separator: ",",
-		tokenSeparators: [],
-		tokenizer: defaultTokenizer,
-		escapeMarkup: defaultEscapeMarkup,
-		blurOnChange: false,
-		selectOnBlur: false,
-		adaptContainerCssClass: function (c) {
-			return c;
-		},
-		adaptDropdownCssClass: function (c) {
-			return null;
-		},
-		nextSearchTerm: function (selectedObject, currentSearchTerm) {
-			return undefined;
-		}
-	};
-
-	$.fn.select2.ajaxDefaults = {
-		transport: $.ajax,
-		params: {
-			type: "GET",
-			cache: false,
-			dataType: "json"
-		}
-	};
-
-	// exports
-	window.Select2 = {
-		query: {
-			ajax: ajax,
-			local: local,
-			tags: tags
-		}, util: {
-			debounce: debounce,
-			markMatch: markMatch,
-			escapeMarkup: defaultEscapeMarkup,
-			stripDiacritics: stripDiacritics
-		}, "class": {
-			"abstract": AbstractSelect2,
-			"single": SingleSelect2,
-			"multi": MultiSelect2
-		}
-	};
-
-}(jQuery));