summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 19:47:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 19:47:39 +0000
commit8d13bdc6cac0e20c43c6f909fc0208774b9c5c84 (patch)
tree5fd46925c6b4a881c9208772ed8e5cc0588bc164 /src/lib
parentInitial commit. (diff)
downloadprivacybadger-upstream.tar.xz
privacybadger-upstream.zip
Adding upstream version 2020.10.7.upstream/2020.10.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/basedomain.js319
-rw-r--r--src/lib/i18n.js151
-rw-r--r--src/lib/options.js120
-rw-r--r--src/lib/publicSuffixList.js7497
-rw-r--r--src/lib/vendor/jquery-3.5.1.js10872
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 335 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 207 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 262 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 262 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 332 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 280 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.pngbin0 -> 6922 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.pngbin0 -> 4549 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.pngbin0 -> 6992 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.pngbin0 -> 6999 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4549 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js2815
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css286
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css443
-rw-r--r--src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2bin0 -> 21208 bytes
-rw-r--r--src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css839
-rw-r--r--src/lib/vendor/jquery.smooth-scroll.js357
-rw-r--r--src/lib/vendor/punycode-1.4.1.js533
-rw-r--r--src/lib/vendor/select2-4.0.11/select2-4.0.11.css481
-rw-r--r--src/lib/vendor/select2-4.0.11/select2-4.0.11.js6044
-rw-r--r--src/lib/vendor/toggle-switch.css310
-rw-r--r--src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css388
-rw-r--r--src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js4273
-rw-r--r--src/lib/vendor/underscore-1.9.1.js1692
29 files changed, 37420 insertions, 0 deletions
diff --git a/src/lib/basedomain.js b/src/lib/basedomain.js
new file mode 100644
index 0000000..32e8768
--- /dev/null
+++ b/src/lib/basedomain.js
@@ -0,0 +1,319 @@
+/*!
+ * Parts of original code from ipv6.js <https://github.com/beaugunderson/javascript-ipv6>
+ * Copyright 2011 Beau Gunderson
+ * Available under MIT license <http://mths.be/mit>
+ */
+
+/* globals punycode:false */
+
+const RE_V4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})$/i;
+const RE_V4_HEX = /^0x([0-9a-f]{8})$/i;
+const RE_V4_NUMERIC = /^[0-9]+$/;
+const RE_V4inV6 = /(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
+
+const RE_BAD_CHARACTERS = /([^0-9a-f:])/i;
+const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]$)/i;
+
+function isIPv4(address) {
+ if (RE_V4.test(address)) {
+ return true;
+ }
+ if (RE_V4_HEX.test(address)) {
+ return true;
+ }
+ if (RE_V4_NUMERIC.test(address)) {
+ return true;
+ }
+ return false;
+}
+
+function isIPv6(address) {
+ var a4addon = 0;
+ var address4 = address.match(RE_V4inV6);
+ if (address4) {
+ var temp4 = address4[0].split('.');
+ for (var i = 0; i < 4; i++) {
+ if (/^0[0-9]+/.test(temp4[i])) {
+ return false;
+ }
+ }
+ address = address.replace(RE_V4inV6, '');
+ if (/[0-9]$/.test(address)) {
+ return false;
+ }
+
+ address = address + temp4.join(':');
+ a4addon = 2;
+ }
+
+ if (RE_BAD_CHARACTERS.test(address)) {
+ return false;
+ }
+
+ if (RE_BAD_ADDRESS.test(address)) {
+ return false;
+ }
+
+ function count(string, substring) {
+ return (string.length - string.replace(new RegExp(substring,"g"), '').length) / substring.length;
+ }
+
+ var halves = count(address, '::');
+ if (halves == 1 && count(address, ':') <= 6 + 2 + a4addon) {
+ return true;
+ }
+ if (halves == 0 && count(address, ':') == 7 + a4addon) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Returns base domain for specified host based on Public Suffix List.
+ * @param {String} hostname The name of the host to get the base domain for
+ */
+function getBaseDomain(/**String*/ hostname) /**String*/ {
+ // remove trailing dot(s)
+ hostname = hostname.replace(/\.+$/, '');
+
+ // return IP address untouched
+ if (isIPv6(hostname) || isIPv4(hostname)) {
+ return hostname;
+ }
+
+ // decode punycode if exists
+ if (hostname.indexOf('xn--') >= 0) {
+ hostname = punycode.toUnicode(hostname);
+ }
+
+ // search through PSL
+ var prevDomains = [];
+ var curDomain = hostname;
+ var nextDot = curDomain.indexOf('.');
+ var tld = 0;
+
+ for (;;) {
+ var suffix = window.publicSuffixes[curDomain];
+ if (typeof suffix != 'undefined') {
+ tld = suffix;
+ break;
+ }
+
+ if (nextDot < 0) {
+ tld = 1;
+ break;
+ }
+
+ prevDomains.push(curDomain.substring(0,nextDot));
+ curDomain = curDomain.substring(nextDot+1);
+ nextDot = curDomain.indexOf('.');
+ }
+
+ while (tld > 0 && prevDomains.length > 0) {
+ curDomain = prevDomains.pop() + '.' + curDomain;
+ tld--;
+ }
+
+ return curDomain;
+}
+
+/**
+ * Converts an IP address to a number. If given input is not a valid IP address
+ * then 0 is returned.
+ * @param {String} ip The IP address to convert
+ * @returns {Integer}
+ */
+function ipAddressToNumber(ip) {
+ // Separate IP address into octets, make sure there are four.
+ var octets = ip.split(".");
+ if (octets.length !== 4) {
+ return 0;
+ }
+
+ var result = 0;
+ var maxOctetIndex = 3;
+ for (var i = maxOctetIndex; i >= 0; i--) {
+ var octet = parseInt(octets[maxOctetIndex - i], 10);
+
+ // If octet is invalid return early, no need to continue.
+ if (Number.isNaN(octet) || octet < 0 || octet > 255) {
+ return 0;
+ }
+
+ // Use bit shifting to store each octet for result.
+ result |= octet << (i * 8); // eslint-disable-line no-bitwise
+ }
+
+ // Results of bitwise operations in JS are interpreted as signed
+ // so use zero-fill right shift to return unsigned number.
+ return result >>> 0; // eslint-disable-line no-bitwise
+}
+
+/**
+ * Determines if domain is private, that is localhost or the IP address spaces
+ * specified by RFC 1918.
+ * @param {String} domain The domain to check
+ * @returns {Boolean}
+ */
+function isPrivateDomain(domain) { // eslint-disable-line no-unused-vars
+ // Check for localhost match.
+ if (domain === "localhost") {
+ return true;
+ }
+
+ // Check for private IP match.
+ var ipNumber = ipAddressToNumber(domain);
+ var privateIpMasks = {
+ "127.0.0.0": "255.0.0.0",
+ "10.0.0.0": "255.0.0.0",
+ "172.16.0.0": "255.240.0.0",
+ "192.168.0.0": "255.255.0.0",
+ };
+ for (var ip in privateIpMasks) {
+ // Ignore object properties.
+ if (!privateIpMasks.hasOwnProperty(ip)) {
+ continue;
+ }
+
+ // Compare given IP value to private IP value using bitwise AND.
+ // Make sure result of AND is unsigned by using zero-fill right shift.
+ var privateIpNumber = ipAddressToNumber(ip);
+ var privateMaskNumber = ipAddressToNumber(privateIpMasks[ip]);
+ if (((ipNumber & privateMaskNumber) >>> 0) === privateIpNumber) { // eslint-disable-line no-bitwise
+ return true;
+ }
+ }
+
+ // Getting here means given host didn't match localhost
+ // or other private addresses so return false.
+ return false;
+}
+
+/**
+ * Checks whether a request is third party for the given document, uses
+ * information from the public suffix list to determine the effective domain
+ * name for the document.
+ * @param {String} requestHost The host of the 3rd party request
+ * @param {String} documentHost The host of the document
+ */
+function isThirdParty(/**String*/ requestHost, /**String*/ documentHost) { // eslint-disable-line no-unused-vars
+ // Remove trailing dots
+ requestHost = requestHost.replace(/\.+$/, "");
+ documentHost = documentHost.replace(/\.+$/, "");
+
+ // Extract domain name - leave IP addresses unchanged, otherwise leave only base domain
+ var documentDomain = getBaseDomain(documentHost);
+ if (requestHost.length > documentDomain.length) {
+ return (requestHost.substr(requestHost.length - documentDomain.length - 1) != "." + documentDomain);
+ } else {
+ return (requestHost != documentDomain);
+ }
+}
+
+/**
+ * Extracts host name from a URL.
+ */
+function extractHostFromURL(/**String*/ url) { // eslint-disable-line no-unused-vars
+ if (url && extractHostFromURL._lastURL == url) {
+ return extractHostFromURL._lastDomain;
+ }
+
+ var host = "";
+ try {
+ host = new URI(url).host;
+ } catch (e) {
+ // Keep the empty string for invalid URIs.
+ }
+
+ extractHostFromURL._lastURL = url;
+ extractHostFromURL._lastDomain = host;
+ return host;
+}
+
+/**
+ * Parses URLs and provides an interface similar to nsIURI in Gecko, see
+ * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIURI.
+ * TODO: Make sure the parsing actually works the same as nsStandardURL.
+ * @constructor
+ */
+function URI(/**String*/ spec) {
+ this.spec = spec;
+ this._schemeEnd = spec.indexOf(":");
+ if (this._schemeEnd < 0) {
+ throw new Error("Invalid URI scheme");
+ }
+
+ if (spec.substr(this._schemeEnd + 1, 2) != "//") {
+ // special case for filesystem, blob URIs
+ if (this.scheme === "filesystem" || this.scheme === "blob") {
+ this._schemeEnd = spec.indexOf(":", this._schemeEnd + 1);
+ if (spec.substr(this._schemeEnd + 1, 2) != "//") {
+ throw new Error("Unexpected URI structure");
+ }
+ } else {
+ throw new Error("Unexpected URI structure");
+ }
+ }
+
+ this._hostPortStart = this._schemeEnd + 3;
+ this._hostPortEnd = spec.indexOf("/", this._hostPortStart);
+ if (this._hostPortEnd < 0) {
+ throw new Error("Invalid URI host");
+ }
+
+ var authEnd = spec.indexOf("@", this._hostPortStart);
+ if (authEnd >= 0 && authEnd < this._hostPortEnd) {
+ this._hostPortStart = authEnd + 1;
+ }
+
+ this._portStart = -1;
+ this._hostEnd = spec.indexOf("]", this._hostPortStart + 1);
+ if (spec[this._hostPortStart] == "[" && this._hostEnd >= 0 && this._hostEnd < this._hostPortEnd) {
+ // The host is an IPv6 literal
+ this._hostStart = this._hostPortStart + 1;
+ if (spec[this._hostEnd + 1] == ":") {
+ this._portStart = this._hostEnd + 2;
+ }
+ } else {
+ this._hostStart = this._hostPortStart;
+ this._hostEnd = spec.indexOf(":", this._hostStart);
+ if (this._hostEnd >= 0 && this._hostEnd < this._hostPortEnd) {
+ this._portStart = this._hostEnd + 1;
+ } else {
+ this._hostEnd = this._hostPortEnd;
+ }
+ }
+}
+URI.prototype = {
+ spec: null,
+ get scheme() {
+ return this.spec.substring(0, this._schemeEnd).toLowerCase();
+ },
+ get host() {
+ return this.spec.substring(this._hostStart, this._hostEnd);
+ },
+ get asciiHost() {
+ var host = this.host;
+ if (/^[\x00-\x7F]+$/.test(host)) { // eslint-disable-line no-control-regex
+ return host;
+ } else {
+ return punycode.toASCII(host);
+ }
+ },
+ get hostPort() {
+ return this.spec.substring(this._hostPortStart, this._hostPortEnd);
+ },
+ get port() {
+ if (this._portStart < 0) {
+ return -1;
+ } else {
+ return parseInt(this.spec.substring(this._portStart, this._hostPortEnd), 10);
+ }
+ },
+ get path() {
+ return this.spec.substring(this._hostPortEnd);
+ },
+ get prePath() {
+ return this.spec.substring(0, this._hostPortEnd);
+ }
+};
diff --git a/src/lib/i18n.js b/src/lib/i18n.js
new file mode 100644
index 0000000..11ef67c
--- /dev/null
+++ b/src/lib/i18n.js
@@ -0,0 +1,151 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function () {
+
+const LOCALE = chrome.i18n.getMessage('@@ui_locale'),
+ ON_POPUP = (document.location.pathname == "/skin/popup.html");
+
+function localizeFaqLink() {
+ const LOCALIZED_HOMEPAGE_LOCALES = ['es'];
+ if (ON_POPUP && LOCALIZED_HOMEPAGE_LOCALES.includes(LOCALE)) {
+ // update FAQ link to point to localized version
+ $('#help').prop('href', `https://privacybadger.org/${LOCALE}/#faq`);
+ }
+}
+
+function setTextDirection() {
+ function toggle_css_value(selector, property, from, to) {
+ let $els = $(selector);
+ $els.each(i => {
+ let $el = $($els[i]);
+ if ($el.css(property) === from) {
+ $el.css(property, to);
+ }
+ });
+ }
+
+ // https://www.w3.org/International/questions/qa-scripts#examples
+ // https://developer.chrome.com/webstore/i18n?csw=1#localeTable
+ // TODO duplicated in src/js/webrequest.js
+ const RTL_LOCALES = ['ar', 'he', 'fa'];
+ if (!RTL_LOCALES.includes(LOCALE)) {
+ return;
+ }
+
+ // set body text direction
+ document.body.setAttribute("dir", "rtl");
+
+ // popup page
+ if (ON_POPUP) {
+ // fix floats
+ ['#privacyBadgerHeader img', '#header-image-stack', '#version'].forEach((selector) => {
+ toggle_css_value(selector, "float", "left", "right");
+ });
+ ['#fittslaw', '#options', '#help', '#share', '.overlay_close'].forEach((selector) => {
+ toggle_css_value(selector, "float", "right", "left");
+ });
+
+ // options page
+ } else if (document.location.pathname == "/skin/options.html") {
+ // apply RTL workaround for jQuery UI tabs
+ // https://zoomicon.wordpress.com/2009/10/15/how-to-use-jqueryui-tabs-in-right-to-left-layout/
+ let css = document.createElement("style");
+ css.type = "text/css";
+ css.textContent = `
+.ui-tabs { direction: rtl; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected,
+ .ui-tabs .ui-tabs-nav li.ui-state-default { float: right; }
+.ui-tabs .ui-tabs-nav li a { float: right; }
+`;
+ document.body.appendChild(css);
+
+ // fix floats
+ ['.btn-silo', '.btn-silo div', '#allowlist-form > div > div > div'].forEach((selector) => {
+ toggle_css_value(selector, "float", "left", "right");
+ });
+ }
+}
+
+/**
+ * Loads and inserts i18n strings into matching elements.
+ */
+function loadI18nStrings() {
+ let els = document.querySelectorAll("[class^='i18n_']");
+
+ // replace element contents by their class names
+ for (let el of els) {
+ const key = el.className.split(/\s/)[0].slice(5),
+ prop = ("innerHTML" in el ? "innerHTML" : "textContent");
+
+ // get chrome.i18n placeholders, if any
+ let placeholders = el.dataset.i18n_contents_placeholders;
+ placeholders = (placeholders ? placeholders.split("@@") : []);
+
+ // replace contents
+ el[prop] = chrome.i18n.getMessage(key, placeholders);
+ }
+
+ // also replace alt, placeholder and title attributes
+ const ATTRS = [
+ 'alt',
+ 'placeholder',
+ 'title',
+ ];
+
+ // get all the elements that contain one or more of these attributes
+ els = document.querySelectorAll(
+ // for example: "[placeholder^='i18n_'], [title^='i18n_']"
+ "[" + ATTRS.join("^='i18n_'], [") + "^='i18n_']"
+ );
+
+ // for each element
+ for (let el of els) {
+ // for each attribute
+ for (let attr_type of ATTRS) {
+ // get the translation message key
+ let key = el.getAttribute(attr_type);
+
+ // attribute exists
+ if (key) {
+ // remove the i18n_ prefix
+ key = key.startsWith("i18n_") && key.slice(5);
+ }
+
+ if (!key) {
+ continue;
+ }
+
+ // get chrome.i18n placeholders, if any
+ // TODO multiple attributes are not supported
+ let placeholders = el.dataset.i18n_attribute_placeholders;
+ placeholders = (placeholders ? placeholders.split("@@") : []);
+
+ // update the attribute with the result of a translation lookup by KEY
+ el.setAttribute(attr_type, chrome.i18n.getMessage(key, placeholders));
+ }
+ }
+}
+
+// Fill in the strings as soon as possible
+window.addEventListener("DOMContentLoaded", function () {
+ localizeFaqLink();
+ setTextDirection();
+ loadI18nStrings();
+}, true);
+
+}());
diff --git a/src/lib/options.js b/src/lib/options.js
new file mode 100644
index 0000000..8e6bec7
--- /dev/null
+++ b/src/lib/options.js
@@ -0,0 +1,120 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2018 Electronic Frontier Foundation
+ *
+ * Privacy Badger is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Privacy Badger is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.optionslib = (function () {
+
+/**
+ * Gets array of encountered origins.
+ *
+ * @param {Object} origins The starting set of domains to be filtered.
+ * @param {String} [filter_text] Text to filter origins with.
+ * @param {String} [type_filter] Type: user-controlled/DNT-compliant
+ * @param {String} [status_filter] Status: blocked/cookieblocked/allowed
+ * @param {Boolean} [show_not_yet_blocked] Whether to show domains your Badger
+ * hasn't yet learned to block.
+ *
+ * @return {Array} The array of origins.
+ */
+function getOriginsArray(origins, filter_text, type_filter, status_filter, show_not_yet_blocked) {
+ // Make sure filter_text is lower case for case-insensitive matching.
+ if (filter_text) {
+ filter_text = filter_text.toLowerCase();
+ } else {
+ filter_text = "";
+ }
+
+ /**
+ * @param {String} origin The origin to test.
+ * @return {Boolean} Does the origin pass filters?
+ */
+ function matchesFormFilters(origin) {
+ const value = origins[origin];
+
+ if (!show_not_yet_blocked) {
+ // hide the not-yet-seen-on-enough-sites potential trackers
+ if (value == "allow") {
+ return false;
+ }
+ }
+
+ // filter by type
+ if (type_filter) {
+ if (type_filter == "user") {
+ if (!value.startsWith("user")) {
+ return false;
+ }
+ } else {
+ if (value != type_filter) {
+ return false;
+ }
+ }
+ }
+
+ // filter by status
+ if (status_filter) {
+ if (status_filter != value.replace("user_", "") && !(
+ status_filter == "allow" && value == "dnt"
+ )) {
+ return false;
+ }
+ }
+
+ // filter by search text
+ // treat spaces as OR operators
+ // treat "-" prefixes as NOT operators
+ let textFilters = filter_text.split(" ").filter(i=>i); // remove empties
+
+ // no text filters, we have a match
+ if (!textFilters.length) {
+ return true;
+ }
+
+ let positiveFilters = textFilters.filter(i => i[0] != "-"),
+ lorigin = origin.toLowerCase();
+
+ // if we have any positive filters, and we don't match any,
+ // don't bother checking negative filters
+ if (positiveFilters.length) {
+ let result = positiveFilters.some(text => {
+ return lorigin.indexOf(text) != -1;
+ });
+ if (!result) {
+ return false;
+ }
+ }
+
+ // we either matched a positive filter,
+ // or we don't have any positive filters
+
+ // if we match any negative filters, discard the match
+ return textFilters.every(text => {
+ if (text[0] != "-" || text == "-") {
+ return true;
+ }
+ return lorigin.indexOf(text.slice(1)) == -1;
+ });
+ }
+
+ // Include only origins that match given filters.
+ return Object.keys(origins).filter(matchesFormFilters);
+}
+
+return {
+ getOriginsArray,
+};
+
+}()); // end of require.scopes
diff --git a/src/lib/publicSuffixList.js b/src/lib/publicSuffixList.js
new file mode 100644
index 0000000..548b768
--- /dev/null
+++ b/src/lib/publicSuffixList.js
@@ -0,0 +1,7497 @@
+window.publicSuffixes = {
+ "0.bg": 1,
+ "001www.com": 1,
+ "0e.vc": 1,
+ "0emm.com": 2,
+ "1.bg": 1,
+ "12hp.at": 1,
+ "12hp.ch": 1,
+ "12hp.de": 1,
+ "1337.pictures": 1,
+ "16-b.it": 1,
+ "1kapp.com": 1,
+ "2.bg": 1,
+ "2000.hu": 1,
+ "2038.io": 1,
+ "2ix.at": 1,
+ "2ix.ch": 1,
+ "2ix.de": 1,
+ "3.bg": 1,
+ "32-b.it": 1,
+ "3utilities.com": 1,
+ "4.bg": 1,
+ "4lima.at": 1,
+ "4lima.ch": 1,
+ "4lima.de": 1,
+ "4u.com": 1,
+ "5.bg": 1,
+ "6.bg": 1,
+ "611.to": 1,
+ "64-b.it": 1,
+ "7.bg": 1,
+ "8.bg": 1,
+ "9.bg": 1,
+ "9guacu.br": 1,
+ "a.bg": 1,
+ "a.prod.fastly.net": 1,
+ "a.run.app": 1,
+ "a.se": 1,
+ "a.ssl.fastly.net": 1,
+ "aa.no": 1,
+ "aaa.pro": 1,
+ "aarborte.no": 1,
+ "ab.ca": 1,
+ "abashiri.hokkaido.jp": 1,
+ "abc.br": 1,
+ "abeno.osaka.jp": 1,
+ "abiko.chiba.jp": 1,
+ "abira.hokkaido.jp": 1,
+ "abkhazia.su": 1,
+ "abo.pa": 1,
+ "abr.it": 1,
+ "abruzzo.it": 1,
+ "abu.yamaguchi.jp": 1,
+ "ac.ae": 1,
+ "ac.at": 1,
+ "ac.be": 1,
+ "ac.ci": 1,
+ "ac.cn": 1,
+ "ac.cr": 1,
+ "ac.cy": 1,
+ "ac.fj": 1,
+ "ac.gn": 1,
+ "ac.gov.br": 1,
+ "ac.id": 1,
+ "ac.il": 1,
+ "ac.im": 1,
+ "ac.in": 1,
+ "ac.ir": 1,
+ "ac.jp": 1,
+ "ac.ke": 1,
+ "ac.kr": 1,
+ "ac.leg.br": 1,
+ "ac.lk": 1,
+ "ac.ls": 1,
+ "ac.ma": 1,
+ "ac.me": 1,
+ "ac.mu": 1,
+ "ac.mw": 1,
+ "ac.mz": 1,
+ "ac.ni": 1,
+ "ac.nz": 1,
+ "ac.pa": 1,
+ "ac.pr": 1,
+ "ac.rs": 1,
+ "ac.ru": 1,
+ "ac.rw": 1,
+ "ac.se": 1,
+ "ac.sz": 1,
+ "ac.th": 1,
+ "ac.tj": 1,
+ "ac.tz": 1,
+ "ac.ug": 1,
+ "ac.uk": 1,
+ "ac.vn": 1,
+ "ac.za": 1,
+ "ac.zm": 1,
+ "ac.zw": 1,
+ "aca.pro": 1,
+ "academia.bo": 1,
+ "academy.museum": 1,
+ "accesscam.org": 1,
+ "accident-investigation.aero": 1,
+ "accident-prevention.aero": 1,
+ "acct.pro": 1,
+ "achi.nagano.jp": 1,
+ "act.au": 1,
+ "act.edu.au": 1,
+ "ad.jp": 1,
+ "adachi.tokyo.jp": 1,
+ "adm.br": 1,
+ "adobeaemcloud.com": 1,
+ "adobeaemcloud.net": 1,
+ "adult.ht": 1,
+ "adv.br": 1,
+ "adv.mz": 1,
+ "advisor.ws": 2,
+ "adygeya.ru": 1,
+ "adygeya.su": 1,
+ "ae.org": 1,
+ "aejrie.no": 1,
+ "aero.mv": 1,
+ "aero.tt": 1,
+ "aerobatic.aero": 1,
+ "aeroclub.aero": 1,
+ "aerodrome.aero": 1,
+ "aeroport.fr": 1,
+ "afjord.no": 1,
+ "africa.com": 1,
+ "ag.it": 1,
+ "aga.niigata.jp": 1,
+ "agano.niigata.jp": 1,
+ "agdenes.no": 1,
+ "agematsu.nagano.jp": 1,
+ "agents.aero": 1,
+ "agr.br": 1,
+ "agrar.hu": 1,
+ "agric.za": 1,
+ "agriculture.museum": 1,
+ "agrigento.it": 1,
+ "agrinet.tn": 1,
+ "agro.bo": 1,
+ "agro.pl": 1,
+ "aguni.okinawa.jp": 1,
+ "ah.cn": 1,
+ "ah.no": 1,
+ "aibetsu.hokkaido.jp": 1,
+ "aichi.jp": 1,
+ "aid.pl": 1,
+ "aikawa.kanagawa.jp": 1,
+ "ainan.ehime.jp": 1,
+ "aioi.hyogo.jp": 1,
+ "aip.ee": 1,
+ "air-surveillance.aero": 1,
+ "air-traffic-control.aero": 1,
+ "air.museum": 1,
+ "aircraft.aero": 1,
+ "airguard.museum": 1,
+ "airline.aero": 1,
+ "airport.aero": 1,
+ "airtraffic.aero": 1,
+ "aisai.aichi.jp": 1,
+ "aisho.shiga.jp": 1,
+ "aizubange.fukushima.jp": 1,
+ "aizumi.tokushima.jp": 1,
+ "aizumisato.fukushima.jp": 1,
+ "aizuwakamatsu.fukushima.jp": 1,
+ "aju.br": 1,
+ "ak.us": 1,
+ "akabira.hokkaido.jp": 1,
+ "akagi.shimane.jp": 1,
+ "akaiwa.okayama.jp": 1,
+ "akashi.hyogo.jp": 1,
+ "aki.kochi.jp": 1,
+ "akiruno.tokyo.jp": 1,
+ "akishima.tokyo.jp": 1,
+ "akita.akita.jp": 1,
+ "akita.jp": 1,
+ "akkeshi.hokkaido.jp": 1,
+ "aknoluokta.no": 1,
+ "ako.hyogo.jp": 1,
+ "akrehamn.no": 1,
+ "aktyubinsk.su": 1,
+ "akune.kagoshima.jp": 1,
+ "al.eu.org": 1,
+ "al.gov.br": 1,
+ "al.it": 1,
+ "al.leg.br": 1,
+ "al.no": 1,
+ "al.us": 1,
+ "alabama.museum": 1,
+ "alaheadju.no": 1,
+ "aland.fi": 1,
+ "alaska.museum": 1,
+ "alces.network": 2,
+ "alessandria.it": 1,
+ "alesund.no": 1,
+ "algard.no": 1,
+ "algorithmia.com": 2,
+ "alpha-myqnapcloud.com": 1,
+ "alpha.bounty-full.com": 1,
+ "alstahaug.no": 1,
+ "alt.za": 1,
+ "alta.no": 1,
+ "altervista.org": 1,
+ "alto-adige.it": 1,
+ "altoadige.it": 1,
+ "alvdal.no": 1,
+ "alwaysdata.net": 1,
+ "am.br": 1,
+ "am.gov.br": 1,
+ "am.leg.br": 1,
+ "ama.aichi.jp": 1,
+ "ama.shimane.jp": 1,
+ "amagasaki.hyogo.jp": 1,
+ "amakusa.kumamoto.jp": 1,
+ "amami.kagoshima.jp": 1,
+ "amber.museum": 1,
+ "ambulance.aero": 1,
+ "ambulance.museum": 1,
+ "american.museum": 1,
+ "americana.museum": 1,
+ "americanantiques.museum": 1,
+ "americanart.museum": 1,
+ "ami.ibaraki.jp": 1,
+ "amli.no": 1,
+ "amot.no": 1,
+ "amsterdam.museum": 1,
+ "amsw.nl": 1,
+ "amusement.aero": 1,
+ "an.it": 1,
+ "anamizu.ishikawa.jp": 1,
+ "anan.nagano.jp": 1,
+ "anan.tokushima.jp": 1,
+ "anani.br": 1,
+ "ancona.it": 1,
+ "and.mom": 1,
+ "and.museum": 1,
+ "andasuolo.no": 1,
+ "andebu.no": 1,
+ "ando.nara.jp": 1,
+ "andoy.no": 1,
+ "andria-barletta-trani.it": 1,
+ "andria-trani-barletta.it": 1,
+ "andriabarlettatrani.it": 1,
+ "andriatranibarletta.it": 1,
+ "and\u00f8y.no": 1,
+ "anjo.aichi.jp": 1,
+ "ann-arbor.mi.us": 1,
+ "annaka.gunma.jp": 1,
+ "annefrank.museum": 1,
+ "anpachi.gifu.jp": 1,
+ "anthro.museum": 1,
+ "anthropology.museum": 1,
+ "antiques.museum": 1,
+ "ao.it": 1,
+ "aogaki.hyogo.jp": 1,
+ "aogashima.tokyo.jp": 1,
+ "aoki.nagano.jp": 1,
+ "aomori.aomori.jp": 1,
+ "aomori.jp": 1,
+ "aosta-valley.it": 1,
+ "aosta.it": 1,
+ "aostavalley.it": 1,
+ "aoste.it": 1,
+ "ap-northeast-1.elasticbeanstalk.com": 1,
+ "ap-northeast-2.elasticbeanstalk.com": 1,
+ "ap-northeast-3.elasticbeanstalk.com": 1,
+ "ap-south-1.elasticbeanstalk.com": 1,
+ "ap-southeast-1.elasticbeanstalk.com": 1,
+ "ap-southeast-2.elasticbeanstalk.com": 1,
+ "ap.gov.br": 1,
+ "ap.gov.pl": 1,
+ "ap.it": 1,
+ "ap.leg.br": 1,
+ "aparecida.br": 1,
+ "api.stdlib.com": 1,
+ "apigee.io": 1,
+ "app.banzaicloud.io": 1,
+ "app.br": 1,
+ "app.gp": 1,
+ "app.lmpm.com": 1,
+ "app.os.fedoraproject.org": 1,
+ "app.os.stg.fedoraproject.org": 1,
+ "app.render.com": 1,
+ "appchizi.com": 1,
+ "appengine.flow.ch": 1,
+ "applicationcloud.io": 1,
+ "applinzi.com": 1,
+ "apps.fbsbx.com": 1,
+ "apps.lair.io": 1,
+ "appspot.com": 1,
+ "aprendemas.cl": 1,
+ "aq.it": 1,
+ "aquarium.museum": 1,
+ "aquila.it": 1,
+ "ar.com": 1,
+ "ar.it": 1,
+ "ar.us": 1,
+ "arai.shizuoka.jp": 1,
+ "arakawa.saitama.jp": 1,
+ "arakawa.tokyo.jp": 1,
+ "arao.kumamoto.jp": 1,
+ "arboretum.museum": 1,
+ "archaeological.museum": 1,
+ "archaeology.museum": 1,
+ "architecture.museum": 1,
+ "ardal.no": 1,
+ "aremark.no": 1,
+ "arendal.no": 1,
+ "arezzo.it": 1,
+ "ariake.saga.jp": 1,
+ "arida.wakayama.jp": 1,
+ "aridagawa.wakayama.jp": 1,
+ "arita.saga.jp": 1,
+ "arkhangelsk.su": 1,
+ "armenia.su": 1,
+ "arna.no": 1,
+ "arq.br": 1,
+ "art.br": 1,
+ "art.do": 1,
+ "art.dz": 1,
+ "art.ht": 1,
+ "art.museum": 1,
+ "art.pl": 1,
+ "art.sn": 1,
+ "artanddesign.museum": 1,
+ "artcenter.museum": 1,
+ "artdeco.museum": 1,
+ "arte.bo": 1,
+ "arteducation.museum": 1,
+ "artgallery.museum": 1,
+ "arts.co": 1,
+ "arts.museum": 1,
+ "arts.nf": 1,
+ "arts.ro": 1,
+ "arts.ve": 1,
+ "artsandcrafts.museum": 1,
+ "arvo.network": 1,
+ "as.us": 1,
+ "asago.hyogo.jp": 1,
+ "asahi.chiba.jp": 1,
+ "asahi.ibaraki.jp": 1,
+ "asahi.mie.jp": 1,
+ "asahi.nagano.jp": 1,
+ "asahi.toyama.jp": 1,
+ "asahi.yamagata.jp": 1,
+ "asahikawa.hokkaido.jp": 1,
+ "asaka.saitama.jp": 1,
+ "asakawa.fukushima.jp": 1,
+ "asakuchi.okayama.jp": 1,
+ "asaminami.hiroshima.jp": 1,
+ "ascoli-piceno.it": 1,
+ "ascolipiceno.it": 1,
+ "aseral.no": 1,
+ "ashgabad.su": 1,
+ "ashibetsu.hokkaido.jp": 1,
+ "ashikaga.tochigi.jp": 1,
+ "ashiya.fukuoka.jp": 1,
+ "ashiya.hyogo.jp": 1,
+ "ashoro.hokkaido.jp": 1,
+ "asker.no": 1,
+ "askim.no": 1,
+ "askoy.no": 1,
+ "askvoll.no": 1,
+ "ask\u00f8y.no": 1,
+ "asmatart.museum": 1,
+ "asn.au": 1,
+ "asn.lv": 1,
+ "asnes.no": 1,
+ "aso.kumamoto.jp": 1,
+ "ass.km": 1,
+ "assabu.hokkaido.jp": 1,
+ "assassination.museum": 1,
+ "assisi.museum": 1,
+ "assn.lk": 1,
+ "asso.bj": 1,
+ "asso.ci": 1,
+ "asso.dz": 1,
+ "asso.eu.org": 1,
+ "asso.fr": 1,
+ "asso.gp": 1,
+ "asso.ht": 1,
+ "asso.km": 1,
+ "asso.mc": 1,
+ "asso.nc": 1,
+ "asso.re": 1,
+ "association.aero": 1,
+ "association.museum": 1,
+ "asti.it": 1,
+ "astronomy.museum": 1,
+ "asuke.aichi.jp": 1,
+ "at-band-camp.net": 1,
+ "at.eu.org": 1,
+ "at.it": 1,
+ "at.md": 1,
+ "at.vg": 1,
+ "atami.shizuoka.jp": 1,
+ "ath.cx": 1,
+ "atlanta.museum": 1,
+ "atm.pl": 1,
+ "ato.br": 1,
+ "atsugi.kanagawa.jp": 1,
+ "atsuma.hokkaido.jp": 1,
+ "au.eu.org": 1,
+ "audnedaln.no": 1,
+ "augustow.pl": 1,
+ "aukra.no": 1,
+ "aure.no": 1,
+ "aurland.no": 1,
+ "aurskog-holand.no": 1,
+ "aurskog-h\u00f8land.no": 1,
+ "aus.basketball": 1,
+ "austevoll.no": 1,
+ "austin.museum": 1,
+ "australia.museum": 1,
+ "austrheim.no": 1,
+ "author.aero": 1,
+ "auto.pl": 1,
+ "automotive.museum": 1,
+ "av.it": 1,
+ "av.tr": 1,
+ "avellino.it": 1,
+ "averoy.no": 1,
+ "aver\u00f8y.no": 1,
+ "aviation.museum": 1,
+ "avocat.fr": 1,
+ "avocat.pro": 1,
+ "avoues.fr": 1,
+ "awaji.hyogo.jp": 1,
+ "awdev.ca": 2,
+ "awsmppl.com": 1,
+ "axis.museum": 1,
+ "aya.miyazaki.jp": 1,
+ "ayabe.kyoto.jp": 1,
+ "ayagawa.kagawa.jp": 1,
+ "ayase.kanagawa.jp": 1,
+ "az.us": 1,
+ "azerbaijan.su": 1,
+ "azimuth.network": 1,
+ "azumino.nagano.jp": 1,
+ "azure-mobile.net": 1,
+ "azurecontainer.io": 2,
+ "azurewebsites.net": 1,
+ "a\u00e9roport.ci": 1,
+ "b-data.io": 1,
+ "b.bg": 1,
+ "b.br": 1,
+ "b.se": 1,
+ "b.ssl.fastly.net": 1,
+ "ba.gov.br": 1,
+ "ba.it": 1,
+ "ba.leg.br": 1,
+ "babia-gora.pl": 1,
+ "backplaneapp.io": 1,
+ "backyards.banzaicloud.io": 2,
+ "badaddja.no": 1,
+ "badajoz.museum": 1,
+ "baghdad.museum": 1,
+ "bahcavuotna.no": 1,
+ "bahccavuotna.no": 1,
+ "bahn.museum": 1,
+ "baidar.no": 1,
+ "bajddar.no": 1,
+ "balashov.su": 1,
+ "balat.no": 1,
+ "bale.museum": 1,
+ "balena-devices.com": 1,
+ "balestrand.no": 1,
+ "ballangen.no": 1,
+ "ballooning.aero": 1,
+ "balsan-sudtirol.it": 1,
+ "balsan-suedtirol.it": 1,
+ "balsan-s\u00fcdtirol.it": 1,
+ "balsan.it": 1,
+ "balsfjord.no": 1,
+ "baltimore.museum": 1,
+ "bamble.no": 1,
+ "bandai.fukushima.jp": 1,
+ "bando.ibaraki.jp": 1,
+ "banzai.cloud": 2,
+ "bar.pro": 1,
+ "bar0.net": 1,
+ "bar1.net": 1,
+ "bar2.net": 1,
+ "barcelona.museum": 1,
+ "bardu.no": 1,
+ "bari.it": 1,
+ "barletta-trani-andria.it": 1,
+ "barlettatraniandria.it": 1,
+ "barreau.bj": 1,
+ "barrel-of-knowledge.info": 1,
+ "barrell-of-knowledge.info": 1,
+ "barsy.bg": 1,
+ "barsy.ca": 1,
+ "barsy.club": 1,
+ "barsy.co.uk": 1,
+ "barsy.de": 1,
+ "barsy.eu": 1,
+ "barsy.in": 1,
+ "barsy.info": 1,
+ "barsy.io": 1,
+ "barsy.me": 1,
+ "barsy.menu": 1,
+ "barsy.mobi": 1,
+ "barsy.net": 1,
+ "barsy.online": 1,
+ "barsy.org": 1,
+ "barsy.pro": 1,
+ "barsy.pub": 1,
+ "barsy.shop": 1,
+ "barsy.site": 1,
+ "barsy.support": 1,
+ "barsy.uk": 1,
+ "barsycenter.com": 1,
+ "barsyonline.co.uk": 1,
+ "barsyonline.com": 1,
+ "barueri.br": 1,
+ "barum.no": 1,
+ "bas.it": 1,
+ "baseball.museum": 1,
+ "basel.museum": 1,
+ "bashkiria.ru": 1,
+ "bashkiria.su": 1,
+ "basicserver.io": 1,
+ "basilicata.it": 1,
+ "baths.museum": 1,
+ "bato.tochigi.jp": 1,
+ "batsfjord.no": 1,
+ "bauern.museum": 1,
+ "bbs.tr": 1,
+ "bc.ca": 1,
+ "bc.platform.sh": 1,
+ "bci.dnstrace.pro": 1,
+ "bd": 2,
+ "bd.se": 1,
+ "be.ax": 1,
+ "be.eu.org": 1,
+ "be.gy": 1,
+ "bearalvahki.no": 1,
+ "bearalv\u00e1hki.no": 1,
+ "beardu.no": 1,
+ "beauxarts.museum": 1,
+ "bedzin.pl": 1,
+ "beeldengeluid.museum": 1,
+ "beep.pl": 1,
+ "beiarn.no": 1,
+ "bel.tr": 1,
+ "belau.pw": 1,
+ "belem.br": 1,
+ "bellevue.museum": 1,
+ "belluno.it": 1,
+ "benevento.it": 1,
+ "beppu.oita.jp": 1,
+ "berg.no": 1,
+ "bergamo.it": 1,
+ "bergbau.museum": 1,
+ "bergen.no": 1,
+ "berkeley.museum": 1,
+ "berlevag.no": 1,
+ "berlev\u00e5g.no": 1,
+ "berlin.museum": 1,
+ "bern.museum": 1,
+ "beskidy.pl": 1,
+ "beta.bounty-full.com": 1,
+ "betainabox.com": 1,
+ "better-than.tv": 1,
+ "bg.eu.org": 1,
+ "bg.it": 1,
+ "bhz.br": 1,
+ "bi.it": 1,
+ "bialowieza.pl": 1,
+ "bialystok.pl": 1,
+ "bib.br": 1,
+ "bibai.hokkaido.jp": 1,
+ "bible.museum": 1,
+ "biei.hokkaido.jp": 1,
+ "bielawa.pl": 1,
+ "biella.it": 1,
+ "bieszczady.pl": 1,
+ "bievat.no": 1,
+ "biev\u00e1t.no": 1,
+ "bifuka.hokkaido.jp": 1,
+ "bihoro.hokkaido.jp": 1,
+ "bilbao.museum": 1,
+ "bill.museum": 1,
+ "bindal.no": 1,
+ "bio.br": 1,
+ "bip.sh": 1,
+ "bir.ru": 1,
+ "biratori.hokkaido.jp": 1,
+ "birdart.museum": 1,
+ "birkenes.no": 1,
+ "birthplace.museum": 1,
+ "bitbridge.net": 1,
+ "biz.at": 1,
+ "biz.az": 1,
+ "biz.bb": 1,
+ "biz.cy": 1,
+ "biz.dk": 1,
+ "biz.et": 1,
+ "biz.fj": 1,
+ "biz.gl": 1,
+ "biz.id": 1,
+ "biz.ki": 1,
+ "biz.ls": 1,
+ "biz.mv": 1,
+ "biz.mw": 1,
+ "biz.ni": 1,
+ "biz.nr": 1,
+ "biz.pk": 1,
+ "biz.pl": 1,
+ "biz.pr": 1,
+ "biz.ss": 1,
+ "biz.tj": 1,
+ "biz.tr": 1,
+ "biz.tt": 1,
+ "biz.ua": 1,
+ "biz.vn": 1,
+ "biz.zm": 1,
+ "bizen.okayama.jp": 1,
+ "bj.cn": 1,
+ "bjarkoy.no": 1,
+ "bjark\u00f8y.no": 1,
+ "bjerkreim.no": 1,
+ "bjugn.no": 1,
+ "bl.it": 1,
+ "blackbaudcdn.net": 1,
+ "blog.bo": 1,
+ "blog.br": 1,
+ "blog.gt": 1,
+ "blog.kg": 1,
+ "blog.vu": 1,
+ "blogdns.com": 1,
+ "blogdns.net": 1,
+ "blogdns.org": 1,
+ "blogsite.org": 1,
+ "blogsite.xyz": 1,
+ "blogspot.ae": 1,
+ "blogspot.al": 1,
+ "blogspot.am": 1,
+ "blogspot.ba": 1,
+ "blogspot.be": 1,
+ "blogspot.bg": 1,
+ "blogspot.bj": 1,
+ "blogspot.ca": 1,
+ "blogspot.cf": 1,
+ "blogspot.ch": 1,
+ "blogspot.cl": 1,
+ "blogspot.co.at": 1,
+ "blogspot.co.id": 1,
+ "blogspot.co.il": 1,
+ "blogspot.co.ke": 1,
+ "blogspot.co.nz": 1,
+ "blogspot.co.uk": 1,
+ "blogspot.co.za": 1,
+ "blogspot.com": 1,
+ "blogspot.com.ar": 1,
+ "blogspot.com.au": 1,
+ "blogspot.com.br": 1,
+ "blogspot.com.by": 1,
+ "blogspot.com.co": 1,
+ "blogspot.com.cy": 1,
+ "blogspot.com.ee": 1,
+ "blogspot.com.eg": 1,
+ "blogspot.com.es": 1,
+ "blogspot.com.mt": 1,
+ "blogspot.com.ng": 1,
+ "blogspot.com.tr": 1,
+ "blogspot.com.uy": 1,
+ "blogspot.cv": 1,
+ "blogspot.cz": 1,
+ "blogspot.de": 1,
+ "blogspot.dk": 1,
+ "blogspot.fi": 1,
+ "blogspot.fr": 1,
+ "blogspot.gr": 1,
+ "blogspot.hk": 1,
+ "blogspot.hr": 1,
+ "blogspot.hu": 1,
+ "blogspot.ie": 1,
+ "blogspot.in": 1,
+ "blogspot.is": 1,
+ "blogspot.it": 1,
+ "blogspot.jp": 1,
+ "blogspot.kr": 1,
+ "blogspot.li": 1,
+ "blogspot.lt": 1,
+ "blogspot.lu": 1,
+ "blogspot.md": 1,
+ "blogspot.mk": 1,
+ "blogspot.mr": 1,
+ "blogspot.mx": 1,
+ "blogspot.my": 1,
+ "blogspot.nl": 1,
+ "blogspot.no": 1,
+ "blogspot.pe": 1,
+ "blogspot.pt": 1,
+ "blogspot.qa": 1,
+ "blogspot.re": 1,
+ "blogspot.ro": 1,
+ "blogspot.rs": 1,
+ "blogspot.ru": 1,
+ "blogspot.se": 1,
+ "blogspot.sg": 1,
+ "blogspot.si": 1,
+ "blogspot.sk": 1,
+ "blogspot.sn": 1,
+ "blogspot.td": 1,
+ "blogspot.tw": 1,
+ "blogspot.ug": 1,
+ "blogspot.vn": 1,
+ "blogsyte.com": 1,
+ "bloxcms.com": 1,
+ "bmd.br": 1,
+ "bmoattachments.org": 1,
+ "bn.it": 1,
+ "bnr.la": 1,
+ "bo.it": 1,
+ "bo.nordland.no": 1,
+ "bo.telemark.no": 1,
+ "boavista.br": 1,
+ "bodo.no": 1,
+ "bod\u00f8.no": 1,
+ "bokn.no": 1,
+ "boldlygoingnowhere.org": 1,
+ "boleslawiec.pl": 1,
+ "bolivia.bo": 1,
+ "bologna.it": 1,
+ "bolt.hu": 1,
+ "bolzano-altoadige.it": 1,
+ "bolzano.it": 1,
+ "bomlo.no": 1,
+ "bonn.museum": 1,
+ "boomla.net": 1,
+ "boston.museum": 1,
+ "botanical.museum": 1,
+ "botanicalgarden.museum": 1,
+ "botanicgarden.museum": 1,
+ "botany.museum": 1,
+ "bounceme.net": 1,
+ "bounty-full.com": 1,
+ "boxfuse.io": 1,
+ "bozen-sudtirol.it": 1,
+ "bozen-suedtirol.it": 1,
+ "bozen-s\u00fcdtirol.it": 1,
+ "bozen.it": 1,
+ "bpl.biz": 1,
+ "bplaced.com": 1,
+ "bplaced.de": 1,
+ "bplaced.net": 1,
+ "br.com": 1,
+ "br.it": 1,
+ "brand.se": 1,
+ "brandywinevalley.museum": 1,
+ "brasil.museum": 1,
+ "brasilia.me": 1,
+ "bremanger.no": 1,
+ "brescia.it": 1,
+ "brindisi.it": 1,
+ "bristol.museum": 1,
+ "british.museum": 1,
+ "britishcolumbia.museum": 1,
+ "broadcast.museum": 1,
+ "broke-it.net": 1,
+ "broker.aero": 1,
+ "bronnoy.no": 1,
+ "bronnoysund.no": 1,
+ "browsersafetymark.io": 1,
+ "brumunddal.no": 1,
+ "brunel.museum": 1,
+ "brussel.museum": 1,
+ "brussels.museum": 1,
+ "bruxelles.museum": 1,
+ "bryansk.su": 1,
+ "bryne.no": 1,
+ "br\u00f8nn\u00f8y.no": 1,
+ "br\u00f8nn\u00f8ysund.no": 1,
+ "bs.it": 1,
+ "bsb.br": 1,
+ "bss.design": 1,
+ "bt.it": 1,
+ "bu.no": 1,
+ "budejju.no": 1,
+ "building.museum": 1,
+ "builtwithdark.com": 1,
+ "bukhara.su": 1,
+ "bulsan-sudtirol.it": 1,
+ "bulsan-suedtirol.it": 1,
+ "bulsan-s\u00fcdtirol.it": 1,
+ "bulsan.it": 1,
+ "bungoono.oita.jp": 1,
+ "bungotakada.oita.jp": 1,
+ "bunkyo.tokyo.jp": 1,
+ "burghof.museum": 1,
+ "bus.museum": 1,
+ "busan.kr": 1,
+ "bushey.museum": 1,
+ "buyshouses.net": 1,
+ "buzen.fukuoka.jp": 1,
+ "bydgoszcz.pl": 1,
+ "byen.site": 1,
+ "bygland.no": 1,
+ "bykle.no": 1,
+ "bytom.pl": 1,
+ "bz.it": 1,
+ "bzz.dapps.earth": 2,
+ "b\u00e1hcavuotna.no": 1,
+ "b\u00e1hccavuotna.no": 1,
+ "b\u00e1id\u00e1r.no": 1,
+ "b\u00e1jddar.no": 1,
+ "b\u00e1l\u00e1t.no": 1,
+ "b\u00e5d\u00e5ddj\u00e5.no": 1,
+ "b\u00e5tsfjord.no": 1,
+ "b\u00e6rum.no": 1,
+ "b\u00f8.nordland.no": 1,
+ "b\u00f8.telemark.no": 1,
+ "b\u00f8mlo.no": 1,
+ "c.bg": 1,
+ "c.cdn77.org": 1,
+ "c.la": 1,
+ "c.se": 1,
+ "c66.me": 1,
+ "ca-central-1.elasticbeanstalk.com": 1,
+ "ca.eu.org": 1,
+ "ca.it": 1,
+ "ca.na": 1,
+ "ca.us": 1,
+ "caa.aero": 1,
+ "caa.li": 1,
+ "cable-modem.org": 1,
+ "cadaques.museum": 1,
+ "cagliari.it": 1,
+ "cahcesuolo.no": 1,
+ "cal.it": 1,
+ "calabria.it": 1,
+ "california.museum": 1,
+ "caltanissetta.it": 1,
+ "cam.it": 1,
+ "cambridge.museum": 1,
+ "camdvr.org": 1,
+ "campania.it": 1,
+ "campidano-medio.it": 1,
+ "campidanomedio.it": 1,
+ "campinagrande.br": 1,
+ "campinas.br": 1,
+ "campobasso.it": 1,
+ "can.museum": 1,
+ "canada.museum": 1,
+ "capebreton.museum": 1,
+ "carbonia-iglesias.it": 1,
+ "carboniaiglesias.it": 1,
+ "cargo.aero": 1,
+ "carrara-massa.it": 1,
+ "carraramassa.it": 1,
+ "carrd.co": 1,
+ "carrier.museum": 1,
+ "cartoonart.museum": 1,
+ "casacam.net": 1,
+ "casadelamoneda.museum": 1,
+ "caserta.it": 1,
+ "casino.hu": 1,
+ "castle.museum": 1,
+ "castres.museum": 1,
+ "cat.ax": 1,
+ "catania.it": 1,
+ "catanzaro.it": 1,
+ "catering.aero": 1,
+ "catholic.edu.au": 1,
+ "caxias.br": 1,
+ "cb.it": 1,
+ "cbg.ru": 1,
+ "cc.ak.us": 1,
+ "cc.al.us": 1,
+ "cc.ar.us": 1,
+ "cc.as.us": 1,
+ "cc.az.us": 1,
+ "cc.ca.us": 1,
+ "cc.co.us": 1,
+ "cc.ct.us": 1,
+ "cc.dc.us": 1,
+ "cc.de.us": 1,
+ "cc.fl.us": 1,
+ "cc.ga.us": 1,
+ "cc.gu.us": 1,
+ "cc.hi.us": 1,
+ "cc.hn": 1,
+ "cc.ia.us": 1,
+ "cc.id.us": 1,
+ "cc.il.us": 1,
+ "cc.in.us": 1,
+ "cc.ks.us": 1,
+ "cc.ky.us": 1,
+ "cc.la.us": 1,
+ "cc.ma.us": 1,
+ "cc.md.us": 1,
+ "cc.me.us": 1,
+ "cc.mi.us": 1,
+ "cc.mn.us": 1,
+ "cc.mo.us": 1,
+ "cc.ms.us": 1,
+ "cc.mt.us": 1,
+ "cc.na": 1,
+ "cc.nc.us": 1,
+ "cc.nd.us": 1,
+ "cc.ne.us": 1,
+ "cc.nh.us": 1,
+ "cc.nj.us": 1,
+ "cc.nm.us": 1,
+ "cc.nv.us": 1,
+ "cc.ny.us": 1,
+ "cc.oh.us": 1,
+ "cc.ok.us": 1,
+ "cc.or.us": 1,
+ "cc.pa.us": 1,
+ "cc.pr.us": 1,
+ "cc.ri.us": 1,
+ "cc.sc.us": 1,
+ "cc.sd.us": 1,
+ "cc.tn.us": 1,
+ "cc.tx.us": 1,
+ "cc.ua": 1,
+ "cc.ut.us": 1,
+ "cc.va.us": 1,
+ "cc.vi.us": 1,
+ "cc.vt.us": 1,
+ "cc.wa.us": 1,
+ "cc.wi.us": 1,
+ "cc.wv.us": 1,
+ "cc.wy.us": 1,
+ "cci.fr": 1,
+ "cd.eu.org": 1,
+ "cdn77-ssl.net": 1,
+ "ce.gov.br": 1,
+ "ce.it": 1,
+ "ce.leg.br": 1,
+ "cechire.com": 1,
+ "celtic.museum": 1,
+ "center.museum": 1,
+ "certification.aero": 1,
+ "certmgr.org": 1,
+ "cesena-forli.it": 1,
+ "cesena-forl\u00ec.it": 1,
+ "cesenaforli.it": 1,
+ "cesenaforl\u00ec.it": 1,
+ "ch.eu.org": 1,
+ "ch.it": 1,
+ "ch.tc": 1,
+ "chambagri.fr": 1,
+ "championship.aero": 1,
+ "channelsdvr.net": 1,
+ "charter.aero": 1,
+ "chattanooga.museum": 1,
+ "cheltenham.museum": 1,
+ "cherkassy.ua": 1,
+ "cherkasy.ua": 1,
+ "chernigov.ua": 1,
+ "chernihiv.ua": 1,
+ "chernivtsi.ua": 1,
+ "chernovtsy.ua": 1,
+ "chesapeakebay.museum": 1,
+ "chiba.jp": 1,
+ "chicago.museum": 1,
+ "chichibu.saitama.jp": 1,
+ "chieti.it": 1,
+ "chigasaki.kanagawa.jp": 1,
+ "chihayaakasaka.osaka.jp": 1,
+ "chijiwa.nagasaki.jp": 1,
+ "chikugo.fukuoka.jp": 1,
+ "chikuho.fukuoka.jp": 1,
+ "chikuhoku.nagano.jp": 1,
+ "chikujo.fukuoka.jp": 1,
+ "chikuma.nagano.jp": 1,
+ "chikusei.ibaraki.jp": 1,
+ "chikushino.fukuoka.jp": 1,
+ "chikuzen.fukuoka.jp": 1,
+ "children.museum": 1,
+ "childrens.museum": 1,
+ "childrensgarden.museum": 1,
+ "chimkent.su": 1,
+ "chino.nagano.jp": 1,
+ "chippubetsu.hokkaido.jp": 1,
+ "chiropractic.museum": 1,
+ "chirurgiens-dentistes-en-france.fr": 1,
+ "chirurgiens-dentistes.fr": 1,
+ "chiryu.aichi.jp": 1,
+ "chita.aichi.jp": 1,
+ "chitose.hokkaido.jp": 1,
+ "chiyoda.gunma.jp": 1,
+ "chiyoda.tokyo.jp": 1,
+ "chizu.tottori.jp": 1,
+ "chocolate.museum": 1,
+ "chofu.tokyo.jp": 1,
+ "chonan.chiba.jp": 1,
+ "chosei.chiba.jp": 1,
+ "choshi.chiba.jp": 1,
+ "choyo.kumamoto.jp": 1,
+ "christiansburg.museum": 1,
+ "chtr.k12.ma.us": 1,
+ "chungbuk.kr": 1,
+ "chungnam.kr": 1,
+ "chuo.chiba.jp": 1,
+ "chuo.fukuoka.jp": 1,
+ "chuo.osaka.jp": 1,
+ "chuo.tokyo.jp": 1,
+ "chuo.yamanashi.jp": 1,
+ "ci.it": 1,
+ "ciencia.bo": 1,
+ "cieszyn.pl": 1,
+ "cim.br": 1,
+ "cincinnati.museum": 1,
+ "cinema.museum": 1,
+ "circus.museum": 1,
+ "ciscofreak.com": 1,
+ "cistron.nl": 1,
+ "city.hu": 1,
+ "city.kawasaki.jp": 0,
+ "city.kitakyushu.jp": 0,
+ "city.kobe.jp": 0,
+ "city.nagoya.jp": 0,
+ "city.sapporo.jp": 0,
+ "city.sendai.jp": 0,
+ "city.yokohama.jp": 0,
+ "civilaviation.aero": 1,
+ "civilisation.museum": 1,
+ "civilization.museum": 1,
+ "civilwar.museum": 1,
+ "ck": 2,
+ "ck.ua": 1,
+ "cl.it": 1,
+ "clan.rip": 1,
+ "cleverapps.io": 1,
+ "clic2000.net": 1,
+ "clinton.museum": 1,
+ "clock.museum": 1,
+ "cloud.fedoraproject.org": 1,
+ "cloud.goog": 1,
+ "cloud.metacentrum.cz": 2,
+ "cloud66.ws": 1,
+ "cloud66.zone": 1,
+ "cloudaccess.host": 1,
+ "cloudaccess.net": 1,
+ "cloudapp.net": 1,
+ "cloudapps.digital": 1,
+ "cloudcontrolapp.com": 1,
+ "cloudcontrolled.com": 1,
+ "cloudeity.net": 1,
+ "cloudera.site": 1,
+ "cloudfront.net": 1,
+ "cloudfunctions.net": 1,
+ "cloudjiffy.net": 1,
+ "cloudns.asia": 1,
+ "cloudns.biz": 1,
+ "cloudns.cc": 1,
+ "cloudns.club": 1,
+ "cloudns.eu": 1,
+ "cloudns.in": 1,
+ "cloudns.info": 1,
+ "cloudns.org": 1,
+ "cloudns.pro": 1,
+ "cloudns.pw": 1,
+ "cloudns.us": 1,
+ "cloudycluster.net": 1,
+ "club.aero": 1,
+ "club.tw": 1,
+ "cn-north-1.eb.amazonaws.com.cn": 1,
+ "cn-northwest-1.eb.amazonaws.com.cn": 1,
+ "cn.com": 1,
+ "cn.eu.org": 1,
+ "cn.it": 1,
+ "cn.ua": 1,
+ "cn.vu": 1,
+ "cng.br": 1,
+ "cnpy.gdn": 1,
+ "cns.joyent.com": 2,
+ "cnt.br": 1,
+ "co.ae": 1,
+ "co.ag": 1,
+ "co.am": 1,
+ "co.ao": 1,
+ "co.at": 1,
+ "co.bb": 1,
+ "co.bi": 1,
+ "co.bn": 1,
+ "co.business": 1,
+ "co.bw": 1,
+ "co.ca": 1,
+ "co.ci": 1,
+ "co.cl": 1,
+ "co.cm": 1,
+ "co.com": 1,
+ "co.cr": 1,
+ "co.cz": 1,
+ "co.dk": 1,
+ "co.education": 1,
+ "co.events": 1,
+ "co.financial": 1,
+ "co.gg": 1,
+ "co.gl": 1,
+ "co.gy": 1,
+ "co.hu": 1,
+ "co.id": 1,
+ "co.il": 1,
+ "co.im": 1,
+ "co.in": 1,
+ "co.ir": 1,
+ "co.it": 1,
+ "co.je": 1,
+ "co.jp": 1,
+ "co.ke": 1,
+ "co.kr": 1,
+ "co.krd": 1,
+ "co.lc": 1,
+ "co.ls": 1,
+ "co.ma": 1,
+ "co.me": 1,
+ "co.mg": 1,
+ "co.mu": 1,
+ "co.mw": 1,
+ "co.mz": 1,
+ "co.na": 1,
+ "co.network": 1,
+ "co.ni": 1,
+ "co.nl": 1,
+ "co.no": 1,
+ "co.nz": 1,
+ "co.om": 1,
+ "co.pl": 1,
+ "co.place": 1,
+ "co.pn": 1,
+ "co.pw": 1,
+ "co.ro": 1,
+ "co.rs": 1,
+ "co.rw": 1,
+ "co.st": 1,
+ "co.sz": 1,
+ "co.technology": 1,
+ "co.th": 1,
+ "co.tj": 1,
+ "co.tm": 1,
+ "co.tt": 1,
+ "co.tz": 1,
+ "co.ua": 1,
+ "co.ug": 1,
+ "co.uk": 1,
+ "co.us": 1,
+ "co.uz": 1,
+ "co.ve": 1,
+ "co.vi": 1,
+ "co.za": 1,
+ "co.zm": 1,
+ "co.zw": 1,
+ "coal.museum": 1,
+ "coastaldefence.museum": 1,
+ "codespot.com": 1,
+ "cody.museum": 1,
+ "cog.mi.us": 1,
+ "col.ng": 1,
+ "coldwar.museum": 1,
+ "collection.museum": 1,
+ "collegefan.org": 1,
+ "colonialwilliamsburg.museum": 1,
+ "coloradoplateau.museum": 1,
+ "columbia.museum": 1,
+ "columbus.museum": 1,
+ "com.ac": 1,
+ "com.af": 1,
+ "com.ag": 1,
+ "com.ai": 1,
+ "com.al": 1,
+ "com.am": 1,
+ "com.ar": 1,
+ "com.au": 1,
+ "com.aw": 1,
+ "com.az": 1,
+ "com.ba": 1,
+ "com.bb": 1,
+ "com.bh": 1,
+ "com.bi": 1,
+ "com.bm": 1,
+ "com.bn": 1,
+ "com.bo": 1,
+ "com.br": 1,
+ "com.bs": 1,
+ "com.bt": 1,
+ "com.by": 1,
+ "com.bz": 1,
+ "com.ci": 1,
+ "com.cm": 1,
+ "com.cn": 1,
+ "com.co": 1,
+ "com.cu": 1,
+ "com.cw": 1,
+ "com.cy": 1,
+ "com.de": 1,
+ "com.dm": 1,
+ "com.do": 1,
+ "com.dz": 1,
+ "com.ec": 1,
+ "com.ee": 1,
+ "com.eg": 1,
+ "com.es": 1,
+ "com.et": 1,
+ "com.fj": 1,
+ "com.fm": 1,
+ "com.fr": 1,
+ "com.ge": 1,
+ "com.gh": 1,
+ "com.gi": 1,
+ "com.gl": 1,
+ "com.gn": 1,
+ "com.gp": 1,
+ "com.gr": 1,
+ "com.gt": 1,
+ "com.gu": 1,
+ "com.gy": 1,
+ "com.hk": 1,
+ "com.hn": 1,
+ "com.hr": 1,
+ "com.ht": 1,
+ "com.im": 1,
+ "com.io": 1,
+ "com.iq": 1,
+ "com.is": 1,
+ "com.jo": 1,
+ "com.kg": 1,
+ "com.ki": 1,
+ "com.km": 1,
+ "com.kp": 1,
+ "com.kw": 1,
+ "com.ky": 1,
+ "com.kz": 1,
+ "com.la": 1,
+ "com.lb": 1,
+ "com.lc": 1,
+ "com.lk": 1,
+ "com.lr": 1,
+ "com.lv": 1,
+ "com.ly": 1,
+ "com.mg": 1,
+ "com.mk": 1,
+ "com.ml": 1,
+ "com.mo": 1,
+ "com.ms": 1,
+ "com.mt": 1,
+ "com.mu": 1,
+ "com.mv": 1,
+ "com.mw": 1,
+ "com.mx": 1,
+ "com.my": 1,
+ "com.na": 1,
+ "com.nf": 1,
+ "com.ng": 1,
+ "com.ni": 1,
+ "com.nr": 1,
+ "com.om": 1,
+ "com.pa": 1,
+ "com.pe": 1,
+ "com.pf": 1,
+ "com.ph": 1,
+ "com.pk": 1,
+ "com.pl": 1,
+ "com.pr": 1,
+ "com.ps": 1,
+ "com.pt": 1,
+ "com.py": 1,
+ "com.qa": 1,
+ "com.re": 1,
+ "com.ro": 1,
+ "com.ru": 1,
+ "com.sa": 1,
+ "com.sb": 1,
+ "com.sc": 1,
+ "com.sd": 1,
+ "com.se": 1,
+ "com.sg": 1,
+ "com.sh": 1,
+ "com.sl": 1,
+ "com.sn": 1,
+ "com.so": 1,
+ "com.ss": 1,
+ "com.st": 1,
+ "com.sv": 1,
+ "com.sy": 1,
+ "com.tj": 1,
+ "com.tm": 1,
+ "com.tn": 1,
+ "com.to": 1,
+ "com.tr": 1,
+ "com.tt": 1,
+ "com.tw": 1,
+ "com.ua": 1,
+ "com.ug": 1,
+ "com.uy": 1,
+ "com.uz": 1,
+ "com.vc": 1,
+ "com.ve": 1,
+ "com.vi": 1,
+ "com.vn": 1,
+ "com.vu": 1,
+ "com.ws": 1,
+ "com.zm": 1,
+ "commune.am": 1,
+ "communication.museum": 1,
+ "communications.museum": 1,
+ "community-pro.de": 1,
+ "community-pro.net": 1,
+ "community.museum": 1,
+ "como.it": 1,
+ "compute-1.amazonaws.com": 2,
+ "compute.amazonaws.com": 2,
+ "compute.amazonaws.com.cn": 2,
+ "compute.estate": 2,
+ "computer.museum": 1,
+ "computerhistory.museum": 1,
+ "comunica\u00e7\u00f5es.museum": 1,
+ "conf.au": 1,
+ "conf.lv": 1,
+ "conf.se": 1,
+ "conference.aero": 1,
+ "conn.uk": 1,
+ "consulado.st": 1,
+ "consultant.aero": 1,
+ "consulting.aero": 1,
+ "contagem.br": 1,
+ "contemporary.museum": 1,
+ "contemporaryart.museum": 1,
+ "control.aero": 1,
+ "convent.museum": 1,
+ "coop.br": 1,
+ "coop.ht": 1,
+ "coop.km": 1,
+ "coop.mv": 1,
+ "coop.mw": 1,
+ "coop.py": 1,
+ "coop.rw": 1,
+ "coop.tt": 1,
+ "cooperativa.bo": 1,
+ "copenhagen.museum": 1,
+ "copro.uk": 1,
+ "corporation.museum": 1,
+ "correios-e-telecomunica\u00e7\u00f5es.museum": 1,
+ "corvette.museum": 1,
+ "cosenza.it": 1,
+ "costume.museum": 1,
+ "couchpotatofries.org": 1,
+ "couk.me": 1,
+ "council.aero": 1,
+ "countryestate.museum": 1,
+ "county.museum": 1,
+ "coz.br": 1,
+ "cpa.pro": 1,
+ "cq.cn": 1,
+ "cr.it": 1,
+ "cr.ua": 1,
+ "crafting.xyz": 1,
+ "crafts.museum": 1,
+ "cranbrook.museum": 1,
+ "crd.co": 1,
+ "creation.museum": 1,
+ "cremona.it": 1,
+ "crew.aero": 1,
+ "cri.br": 1,
+ "cri.nz": 1,
+ "crimea.ua": 1,
+ "crotone.it": 1,
+ "cryptonomic.net": 2,
+ "cs.it": 1,
+ "csx.cc": 1,
+ "ct.it": 1,
+ "ct.us": 1,
+ "cuiaba.br": 1,
+ "cultural.museum": 1,
+ "culturalcenter.museum": 1,
+ "culture.museum": 1,
+ "cuneo.it": 1,
+ "cupcake.is": 1,
+ "curitiba.br": 1,
+ "curv.dev": 1,
+ "cust.dev.thingdust.io": 1,
+ "cust.disrec.thingdust.io": 1,
+ "cust.prod.thingdust.io": 1,
+ "cust.retrosnub.co.uk": 1,
+ "cust.testing.thingdust.io": 1,
+ "custom.metacentrum.cz": 1,
+ "customer-oci.com": 2,
+ "customer.enonic.io": 1,
+ "customer.mythic-beasts.com": 1,
+ "customer.speedpartner.de": 1,
+ "cv.ua": 1,
+ "cx.ua": 1,
+ "cy.eu.org": 1,
+ "cya.gg": 1,
+ "cyber.museum": 1,
+ "cymru.museum": 1,
+ "cyon.link": 1,
+ "cyon.site": 1,
+ "cz.eu.org": 1,
+ "cz.it": 1,
+ "czeladz.pl": 1,
+ "czest.pl": 1,
+ "d.bg": 1,
+ "d.gv.vc": 1,
+ "d.se": 1,
+ "daegu.kr": 1,
+ "daejeon.kr": 1,
+ "daemon.panel.gg": 1,
+ "dagestan.ru": 1,
+ "dagestan.su": 1,
+ "daigo.ibaraki.jp": 1,
+ "daisen.akita.jp": 1,
+ "daito.osaka.jp": 1,
+ "daiwa.hiroshima.jp": 1,
+ "dali.museum": 1,
+ "dallas.museum": 1,
+ "damnserver.com": 1,
+ "daplie.me": 1,
+ "dapps.earth": 2,
+ "database.museum": 1,
+ "date.fukushima.jp": 1,
+ "date.hokkaido.jp": 1,
+ "dattolocal.com": 1,
+ "dattolocal.net": 1,
+ "dattorelay.com": 1,
+ "dattoweb.com": 1,
+ "davvenjarga.no": 1,
+ "davvenj\u00e1rga.no": 1,
+ "davvesiida.no": 1,
+ "dazaifu.fukuoka.jp": 1,
+ "dc.us": 1,
+ "dd-dns.de": 1,
+ "ddns.me": 1,
+ "ddns.net": 1,
+ "ddnsfree.com": 1,
+ "ddnsgeek.com": 1,
+ "ddnsking.com": 1,
+ "ddnslive.com": 1,
+ "ddnss.de": 1,
+ "ddnss.org": 1,
+ "ddr.museum": 1,
+ "de.com": 1,
+ "de.cool": 1,
+ "de.eu.org": 1,
+ "de.gt": 1,
+ "de.ls": 1,
+ "de.md": 1,
+ "de.us": 1,
+ "deatnu.no": 1,
+ "debian.net": 1,
+ "decorativearts.museum": 1,
+ "dedyn.io": 1,
+ "def.br": 1,
+ "defense.tn": 1,
+ "definima.io": 1,
+ "definima.net": 1,
+ "delaware.museum": 1,
+ "dell-ogliastra.it": 1,
+ "dellogliastra.it": 1,
+ "delmenhorst.museum": 1,
+ "demo.jelastic.com": 1,
+ "democracia.bo": 1,
+ "demon.nl": 1,
+ "denmark.museum": 1,
+ "dep.no": 1,
+ "deporte.bo": 1,
+ "depot.museum": 1,
+ "des.br": 1,
+ "desa.id": 1,
+ "design.aero": 1,
+ "design.museum": 1,
+ "det.br": 1,
+ "detroit.museum": 1,
+ "dev-myqnapcloud.com": 1,
+ "dev.adobeaemcloud.com": 2,
+ "dev.br": 1,
+ "dev.static.land": 1,
+ "dev.vu": 1,
+ "development.run": 1,
+ "devices.resinstaging.io": 1,
+ "df.gov.br": 1,
+ "df.leg.br": 1,
+ "dgca.aero": 1,
+ "dh.bytemark.co.uk": 1,
+ "dielddanuorri.no": 1,
+ "dinosaur.museum": 1,
+ "direct.quickconnect.to": 1,
+ "discourse.group": 1,
+ "discourse.team": 1,
+ "discovery.museum": 1,
+ "diskstation.eu": 1,
+ "diskstation.me": 1,
+ "diskstation.org": 1,
+ "diskussionsbereich.de": 1,
+ "ditchyourip.com": 1,
+ "divtasvuodna.no": 1,
+ "divttasvuotna.no": 1,
+ "dk.eu.org": 1,
+ "dlugoleka.pl": 1,
+ "dn.ua": 1,
+ "dnepropetrovsk.ua": 1,
+ "dni.us": 1,
+ "dnipropetrovsk.ua": 1,
+ "dnsalias.com": 1,
+ "dnsalias.net": 1,
+ "dnsalias.org": 1,
+ "dnsdojo.com": 1,
+ "dnsdojo.net": 1,
+ "dnsdojo.org": 1,
+ "dnsfor.me": 1,
+ "dnshome.de": 1,
+ "dnsiskinky.com": 1,
+ "dnsking.ch": 1,
+ "dnsup.net": 1,
+ "dnsupdate.info": 1,
+ "dnsupdater.de": 1,
+ "does-it.net": 1,
+ "doesntexist.com": 1,
+ "doesntexist.org": 1,
+ "dolls.museum": 1,
+ "donetsk.ua": 1,
+ "donna.no": 1,
+ "donostia.museum": 1,
+ "dontexist.com": 1,
+ "dontexist.net": 1,
+ "dontexist.org": 1,
+ "doomdns.com": 1,
+ "doomdns.org": 1,
+ "dopaas.com": 1,
+ "doshi.yamanashi.jp": 1,
+ "dovre.no": 1,
+ "dp.ua": 1,
+ "dr.na": 1,
+ "dr.tr": 1,
+ "drammen.no": 1,
+ "drangedal.no": 1,
+ "dray-dns.de": 1,
+ "drayddns.com": 1,
+ "draydns.de": 1,
+ "dreamhosters.com": 1,
+ "drobak.no": 1,
+ "drud.io": 1,
+ "drud.us": 1,
+ "dr\u00f8bak.no": 1,
+ "dscloud.biz": 1,
+ "dscloud.me": 1,
+ "dscloud.mobi": 1,
+ "dsmynas.com": 1,
+ "dsmynas.net": 1,
+ "dsmynas.org": 1,
+ "dst.mi.us": 1,
+ "duckdns.org": 1,
+ "durham.museum": 1,
+ "dvrcam.info": 1,
+ "dvrdns.org": 1,
+ "dweb.link": 2,
+ "dy.fi": 1,
+ "dyn-berlin.de": 1,
+ "dyn-ip24.de": 1,
+ "dyn-o-saur.com": 1,
+ "dyn-vpn.de": 1,
+ "dyn.cosidns.de": 1,
+ "dyn.ddnss.de": 1,
+ "dyn.home-webserver.de": 1,
+ "dyn53.io": 1,
+ "dynalias.com": 1,
+ "dynalias.net": 1,
+ "dynalias.org": 1,
+ "dynamic-dns.info": 1,
+ "dynamisches-dns.de": 1,
+ "dynathome.net": 1,
+ "dyndns-at-home.com": 1,
+ "dyndns-at-work.com": 1,
+ "dyndns-blog.com": 1,
+ "dyndns-free.com": 1,
+ "dyndns-home.com": 1,
+ "dyndns-ip.com": 1,
+ "dyndns-mail.com": 1,
+ "dyndns-office.com": 1,
+ "dyndns-pics.com": 1,
+ "dyndns-remote.com": 1,
+ "dyndns-server.com": 1,
+ "dyndns-web.com": 1,
+ "dyndns-wiki.com": 1,
+ "dyndns-work.com": 1,
+ "dyndns.biz": 1,
+ "dyndns.dappnode.io": 1,
+ "dyndns.ddnss.de": 1,
+ "dyndns.info": 1,
+ "dyndns.org": 1,
+ "dyndns.tv": 1,
+ "dyndns.ws": 1,
+ "dyndns1.de": 1,
+ "dynns.com": 1,
+ "dynserv.org": 1,
+ "dynu.net": 1,
+ "dynv6.net": 1,
+ "dynvpn.de": 1,
+ "dyroy.no": 1,
+ "dyr\u00f8y.no": 1,
+ "d\u00f8nna.no": 1,
+ "e.bg": 1,
+ "e.se": 1,
+ "e12.ve": 1,
+ "e164.arpa": 1,
+ "e4.cz": 1,
+ "east-kazakhstan.su": 1,
+ "eastafrica.museum": 1,
+ "eastcoast.museum": 1,
+ "eating-organic.net": 1,
+ "eaton.mi.us": 1,
+ "ebetsu.hokkaido.jp": 1,
+ "ebina.kanagawa.jp": 1,
+ "ebino.miyazaki.jp": 1,
+ "ebiz.tw": 1,
+ "echizen.fukui.jp": 1,
+ "ecn.br": 1,
+ "eco.br": 1,
+ "ecologia.bo": 1,
+ "economia.bo": 1,
+ "ed.ao": 1,
+ "ed.ci": 1,
+ "ed.cr": 1,
+ "ed.jp": 1,
+ "ed.pw": 1,
+ "edgeapp.net": 1,
+ "edgestack.me": 1,
+ "edogawa.tokyo.jp": 1,
+ "edu.ac": 1,
+ "edu.af": 1,
+ "edu.al": 1,
+ "edu.ar": 1,
+ "edu.au": 1,
+ "edu.az": 1,
+ "edu.ba": 1,
+ "edu.bb": 1,
+ "edu.bh": 1,
+ "edu.bi": 1,
+ "edu.bm": 1,
+ "edu.bn": 1,
+ "edu.bo": 1,
+ "edu.br": 1,
+ "edu.bs": 1,
+ "edu.bt": 1,
+ "edu.bz": 1,
+ "edu.ci": 1,
+ "edu.cn": 1,
+ "edu.co": 1,
+ "edu.cu": 1,
+ "edu.cw": 1,
+ "edu.dm": 1,
+ "edu.do": 1,
+ "edu.dz": 1,
+ "edu.ec": 1,
+ "edu.ee": 1,
+ "edu.eg": 1,
+ "edu.es": 1,
+ "edu.et": 1,
+ "edu.eu.org": 1,
+ "edu.fm": 1,
+ "edu.gd": 1,
+ "edu.ge": 1,
+ "edu.gh": 1,
+ "edu.gi": 1,
+ "edu.gl": 1,
+ "edu.gn": 1,
+ "edu.gp": 1,
+ "edu.gr": 1,
+ "edu.gt": 1,
+ "edu.gu": 1,
+ "edu.gy": 1,
+ "edu.hk": 1,
+ "edu.hn": 1,
+ "edu.ht": 1,
+ "edu.in": 1,
+ "edu.iq": 1,
+ "edu.is": 1,
+ "edu.it": 1,
+ "edu.jo": 1,
+ "edu.kg": 1,
+ "edu.ki": 1,
+ "edu.km": 1,
+ "edu.kn": 1,
+ "edu.kp": 1,
+ "edu.krd": 1,
+ "edu.kw": 1,
+ "edu.ky": 1,
+ "edu.kz": 1,
+ "edu.la": 1,
+ "edu.lb": 1,
+ "edu.lc": 1,
+ "edu.lk": 1,
+ "edu.lr": 1,
+ "edu.ls": 1,
+ "edu.lv": 1,
+ "edu.ly": 1,
+ "edu.me": 1,
+ "edu.mg": 1,
+ "edu.mk": 1,
+ "edu.ml": 1,
+ "edu.mn": 1,
+ "edu.mo": 1,
+ "edu.ms": 1,
+ "edu.mt": 1,
+ "edu.mv": 1,
+ "edu.mw": 1,
+ "edu.mx": 1,
+ "edu.my": 1,
+ "edu.mz": 1,
+ "edu.ng": 1,
+ "edu.ni": 1,
+ "edu.nr": 1,
+ "edu.om": 1,
+ "edu.pa": 1,
+ "edu.pe": 1,
+ "edu.pf": 1,
+ "edu.ph": 1,
+ "edu.pk": 1,
+ "edu.pl": 1,
+ "edu.pn": 1,
+ "edu.pr": 1,
+ "edu.ps": 1,
+ "edu.pt": 1,
+ "edu.py": 1,
+ "edu.qa": 1,
+ "edu.rs": 1,
+ "edu.ru": 1,
+ "edu.sa": 1,
+ "edu.sb": 1,
+ "edu.sc": 1,
+ "edu.sd": 1,
+ "edu.sg": 1,
+ "edu.sl": 1,
+ "edu.sn": 1,
+ "edu.so": 1,
+ "edu.ss": 1,
+ "edu.st": 1,
+ "edu.sv": 1,
+ "edu.sy": 1,
+ "edu.tj": 1,
+ "edu.tm": 1,
+ "edu.to": 1,
+ "edu.tr": 1,
+ "edu.tt": 1,
+ "edu.tw": 1,
+ "edu.ua": 1,
+ "edu.uy": 1,
+ "edu.vc": 1,
+ "edu.ve": 1,
+ "edu.vn": 1,
+ "edu.vu": 1,
+ "edu.ws": 1,
+ "edu.za": 1,
+ "edu.zm": 1,
+ "education.museum": 1,
+ "educational.museum": 1,
+ "educator.aero": 1,
+ "edugit.org": 1,
+ "edunet.tn": 1,
+ "ee.eu.org": 1,
+ "egersund.no": 1,
+ "egyptian.museum": 1,
+ "ehime.jp": 1,
+ "eid.no": 1,
+ "eidfjord.no": 1,
+ "eidsberg.no": 1,
+ "eidskog.no": 1,
+ "eidsvoll.no": 1,
+ "eigersund.no": 1,
+ "eiheiji.fukui.jp": 1,
+ "eisenbahn.museum": 1,
+ "ekloges.cy": 1,
+ "elasticbeanstalk.com": 1,
+ "elb.amazonaws.com": 2,
+ "elb.amazonaws.com.cn": 2,
+ "elblag.pl": 1,
+ "elburg.museum": 1,
+ "elk.pl": 1,
+ "elvendrell.museum": 1,
+ "elverum.no": 1,
+ "emb.kw": 1,
+ "embaixada.st": 1,
+ "embetsu.hokkaido.jp": 1,
+ "embroidery.museum": 1,
+ "emergency.aero": 1,
+ "emilia-romagna.it": 1,
+ "emiliaromagna.it": 1,
+ "emp.br": 1,
+ "empresa.bo": 1,
+ "emr.it": 1,
+ "en-root.fr": 1,
+ "en.it": 1,
+ "ena.gifu.jp": 1,
+ "encyclopedic.museum": 1,
+ "endofinternet.net": 1,
+ "endofinternet.org": 1,
+ "endoftheinternet.org": 1,
+ "enebakk.no": 1,
+ "enf.br": 1,
+ "eng.br": 1,
+ "eng.pro": 1,
+ "engerdal.no": 1,
+ "engine.aero": 1,
+ "engineer.aero": 1,
+ "england.museum": 1,
+ "eniwa.hokkaido.jp": 1,
+ "enna.it": 1,
+ "enonic.io": 1,
+ "ens.tn": 1,
+ "ent.platform.sh": 1,
+ "enterprisecloud.nu": 1,
+ "entertainment.aero": 1,
+ "entomology.museum": 1,
+ "environment.museum": 1,
+ "environmentalconservation.museum": 1,
+ "epilepsy.museum": 1,
+ "equipment.aero": 1,
+ "er": 2,
+ "erimo.hokkaido.jp": 1,
+ "erotica.hu": 1,
+ "erotika.hu": 1,
+ "es.ax": 1,
+ "es.eu.org": 1,
+ "es.gov.br": 1,
+ "es.kr": 1,
+ "es.leg.br": 1,
+ "esan.hokkaido.jp": 1,
+ "esashi.hokkaido.jp": 1,
+ "esp.br": 1,
+ "essex.museum": 1,
+ "est-a-la-maison.com": 1,
+ "est-a-la-masion.com": 1,
+ "est-le-patron.com": 1,
+ "est-mon-blogueur.com": 1,
+ "est.pr": 1,
+ "estate.museum": 1,
+ "etajima.hiroshima.jp": 1,
+ "etc.br": 1,
+ "ethnology.museum": 1,
+ "eti.br": 1,
+ "etne.no": 1,
+ "etnedal.no": 1,
+ "eu-1.evennode.com": 1,
+ "eu-2.evennode.com": 1,
+ "eu-3.evennode.com": 1,
+ "eu-4.evennode.com": 1,
+ "eu-central-1.elasticbeanstalk.com": 1,
+ "eu-west-1.elasticbeanstalk.com": 1,
+ "eu-west-2.elasticbeanstalk.com": 1,
+ "eu-west-3.elasticbeanstalk.com": 1,
+ "eu.ax": 1,
+ "eu.com": 1,
+ "eu.int": 1,
+ "eu.meteorapp.com": 1,
+ "eu.org": 1,
+ "eu.platform.sh": 1,
+ "eun.eg": 1,
+ "evenassi.no": 1,
+ "evenes.no": 1,
+ "even\u00e1\u0161\u0161i.no": 1,
+ "evje-og-hornnes.no": 1,
+ "ex.futurecms.at": 2,
+ "ex.ortsinfo.at": 2,
+ "exchange.aero": 1,
+ "exeter.museum": 1,
+ "exhibition.museum": 1,
+ "exnet.su": 1,
+ "experts-comptables.fr": 1,
+ "express.aero": 1,
+ "f.bg": 1,
+ "f.se": 1,
+ "fam.pk": 1,
+ "family.museum": 1,
+ "familyds.com": 1,
+ "familyds.net": 1,
+ "familyds.org": 1,
+ "fantasyleague.cc": 1,
+ "far.br": 1,
+ "farm.museum": 1,
+ "farmequipment.museum": 1,
+ "farmers.museum": 1,
+ "farmstead.museum": 1,
+ "farsund.no": 1,
+ "fastly-terrarium.com": 1,
+ "fastlylb.net": 1,
+ "fastvps-server.com": 1,
+ "fastvps.host": 1,
+ "fastvps.site": 1,
+ "fauske.no": 1,
+ "fbx-os.fr": 1,
+ "fbxos.fr": 1,
+ "fc.it": 1,
+ "fe.it": 1,
+ "fed.us": 1,
+ "federation.aero": 1,
+ "fedje.no": 1,
+ "fedorainfracloud.org": 1,
+ "fedorapeople.org": 1,
+ "feira.br": 1,
+ "fermo.it": 1,
+ "ferrara.it": 1,
+ "feste-ip.net": 1,
+ "fet.no": 1,
+ "fetsund.no": 1,
+ "fg.it": 1,
+ "fh.se": 1,
+ "fhapp.xyz": 1,
+ "fhs.no": 1,
+ "fhsk.se": 1,
+ "fhv.se": 1,
+ "fi.cloudplatform.fi": 1,
+ "fi.cr": 1,
+ "fi.eu.org": 1,
+ "fi.it": 1,
+ "fie.ee": 1,
+ "field.museum": 1,
+ "figueres.museum": 1,
+ "filatelia.museum": 1,
+ "filegear-au.me": 1,
+ "filegear-de.me": 1,
+ "filegear-gb.me": 1,
+ "filegear-ie.me": 1,
+ "filegear-jp.me": 1,
+ "filegear-sg.me": 1,
+ "filegear.me": 1,
+ "film.hu": 1,
+ "film.museum": 1,
+ "fin.ci": 1,
+ "fin.ec": 1,
+ "fin.tn": 1,
+ "fineart.museum": 1,
+ "finearts.museum": 1,
+ "finland.museum": 1,
+ "finnoy.no": 1,
+ "finn\u00f8y.no": 1,
+ "firebaseapp.com": 1,
+ "firenet.ch": 2,
+ "firenze.it": 1,
+ "firewall-gateway.com": 1,
+ "firewall-gateway.de": 1,
+ "firewall-gateway.net": 1,
+ "firm.co": 1,
+ "firm.dk": 1,
+ "firm.ht": 1,
+ "firm.in": 1,
+ "firm.nf": 1,
+ "firm.ng": 1,
+ "firm.ro": 1,
+ "firm.ve": 1,
+ "fitjar.no": 1,
+ "fj.cn": 1,
+ "fjaler.no": 1,
+ "fjell.no": 1,
+ "fk": 2,
+ "fl.us": 1,
+ "fla.no": 1,
+ "flakstad.no": 1,
+ "flanders.museum": 1,
+ "flatanger.no": 1,
+ "flekkefjord.no": 1,
+ "flesberg.no": 1,
+ "flight.aero": 1,
+ "flog.br": 1,
+ "flora.no": 1,
+ "florence.it": 1,
+ "florida.museum": 1,
+ "floripa.br": 1,
+ "floro.no": 1,
+ "flor\u00f8.no": 1,
+ "flt.cloud.muni.cz": 1,
+ "fly.dev": 1,
+ "flynnhosting.net": 1,
+ "fl\u00e5.no": 1,
+ "fm.br": 1,
+ "fm.it": 1,
+ "fm.no": 1,
+ "fnd.br": 1,
+ "fnwk.site": 1,
+ "foggia.it": 1,
+ "folionetwork.site": 1,
+ "folkebibl.no": 1,
+ "folldal.no": 1,
+ "for-better.biz": 1,
+ "for-more.biz": 1,
+ "for-our.info": 1,
+ "for-some.biz": 1,
+ "for-the.biz": 1,
+ "for.men": 1,
+ "for.mom": 1,
+ "for.one": 1,
+ "for.sale": 1,
+ "force.museum": 1,
+ "forde.no": 1,
+ "forgot.her.name": 1,
+ "forgot.his.name": 1,
+ "forli-cesena.it": 1,
+ "forlicesena.it": 1,
+ "forl\u00ec-cesena.it": 1,
+ "forl\u00eccesena.it": 1,
+ "forsand.no": 1,
+ "fortal.br": 1,
+ "forte.id": 1,
+ "fortmissoula.museum": 1,
+ "fortworth.museum": 1,
+ "forum.hu": 1,
+ "forumz.info": 1,
+ "fosnes.no": 1,
+ "fot.br": 1,
+ "foundation.museum": 1,
+ "foz.br": 1,
+ "fr.eu.org": 1,
+ "fr.it": 1,
+ "frana.no": 1,
+ "francaise.museum": 1,
+ "frankfurt.museum": 1,
+ "franziskaner.museum": 1,
+ "fredrikstad.no": 1,
+ "free.hr": 1,
+ "freebox-os.com": 1,
+ "freebox-os.fr": 1,
+ "freeboxos.com": 1,
+ "freeboxos.fr": 1,
+ "freeddns.org": 1,
+ "freeddns.us": 1,
+ "freedesktop.org": 1,
+ "freemasonry.museum": 1,
+ "freesite.host": 1,
+ "freetls.fastly.net": 1,
+ "frei.no": 1,
+ "freiburg.museum": 1,
+ "fribourg.museum": 1,
+ "friuli-v-giulia.it": 1,
+ "friuli-ve-giulia.it": 1,
+ "friuli-vegiulia.it": 1,
+ "friuli-venezia-giulia.it": 1,
+ "friuli-veneziagiulia.it": 1,
+ "friuli-vgiulia.it": 1,
+ "friuliv-giulia.it": 1,
+ "friulive-giulia.it": 1,
+ "friulivegiulia.it": 1,
+ "friulivenezia-giulia.it": 1,
+ "friuliveneziagiulia.it": 1,
+ "friulivgiulia.it": 1,
+ "frog.museum": 1,
+ "frogn.no": 1,
+ "froland.no": 1,
+ "from-ak.com": 1,
+ "from-al.com": 1,
+ "from-ar.com": 1,
+ "from-az.net": 1,
+ "from-ca.com": 1,
+ "from-co.net": 1,
+ "from-ct.com": 1,
+ "from-dc.com": 1,
+ "from-de.com": 1,
+ "from-fl.com": 1,
+ "from-ga.com": 1,
+ "from-hi.com": 1,
+ "from-ia.com": 1,
+ "from-id.com": 1,
+ "from-il.com": 1,
+ "from-in.com": 1,
+ "from-ks.com": 1,
+ "from-ky.com": 1,
+ "from-la.net": 1,
+ "from-ma.com": 1,
+ "from-md.com": 1,
+ "from-me.org": 1,
+ "from-mi.com": 1,
+ "from-mn.com": 1,
+ "from-mo.com": 1,
+ "from-ms.com": 1,
+ "from-mt.com": 1,
+ "from-nc.com": 1,
+ "from-nd.com": 1,
+ "from-ne.com": 1,
+ "from-nh.com": 1,
+ "from-nj.com": 1,
+ "from-nm.com": 1,
+ "from-nv.com": 1,
+ "from-ny.net": 1,
+ "from-oh.com": 1,
+ "from-ok.com": 1,
+ "from-or.com": 1,
+ "from-pa.com": 1,
+ "from-pr.com": 1,
+ "from-ri.com": 1,
+ "from-sc.com": 1,
+ "from-sd.com": 1,
+ "from-tn.com": 1,
+ "from-tx.com": 1,
+ "from-ut.com": 1,
+ "from-va.com": 1,
+ "from-vt.com": 1,
+ "from-wa.com": 1,
+ "from-wi.com": 1,
+ "from-wv.com": 1,
+ "from-wy.com": 1,
+ "from.hr": 1,
+ "frosinone.it": 1,
+ "frosta.no": 1,
+ "froya.no": 1,
+ "fr\u00e6na.no": 1,
+ "fr\u00f8ya.no": 1,
+ "fst.br": 1,
+ "ftpaccess.cc": 1,
+ "fuchu.hiroshima.jp": 1,
+ "fuchu.tokyo.jp": 1,
+ "fuchu.toyama.jp": 1,
+ "fudai.iwate.jp": 1,
+ "fuefuki.yamanashi.jp": 1,
+ "fuel.aero": 1,
+ "fuettertdasnetz.de": 1,
+ "fuji.shizuoka.jp": 1,
+ "fujieda.shizuoka.jp": 1,
+ "fujiidera.osaka.jp": 1,
+ "fujikawa.shizuoka.jp": 1,
+ "fujikawa.yamanashi.jp": 1,
+ "fujikawaguchiko.yamanashi.jp": 1,
+ "fujimi.nagano.jp": 1,
+ "fujimi.saitama.jp": 1,
+ "fujimino.saitama.jp": 1,
+ "fujinomiya.shizuoka.jp": 1,
+ "fujioka.gunma.jp": 1,
+ "fujisato.akita.jp": 1,
+ "fujisawa.iwate.jp": 1,
+ "fujisawa.kanagawa.jp": 1,
+ "fujishiro.ibaraki.jp": 1,
+ "fujiyoshida.yamanashi.jp": 1,
+ "fukagawa.hokkaido.jp": 1,
+ "fukaya.saitama.jp": 1,
+ "fukuchi.fukuoka.jp": 1,
+ "fukuchiyama.kyoto.jp": 1,
+ "fukudomi.saga.jp": 1,
+ "fukui.fukui.jp": 1,
+ "fukui.jp": 1,
+ "fukumitsu.toyama.jp": 1,
+ "fukuoka.jp": 1,
+ "fukuroi.shizuoka.jp": 1,
+ "fukusaki.hyogo.jp": 1,
+ "fukushima.fukushima.jp": 1,
+ "fukushima.hokkaido.jp": 1,
+ "fukushima.jp": 1,
+ "fukuyama.hiroshima.jp": 1,
+ "funabashi.chiba.jp": 1,
+ "funagata.yamagata.jp": 1,
+ "funahashi.toyama.jp": 1,
+ "fundacio.museum": 1,
+ "fuoisku.no": 1,
+ "fuossko.no": 1,
+ "furano.hokkaido.jp": 1,
+ "furniture.museum": 1,
+ "furubira.hokkaido.jp": 1,
+ "furudono.fukushima.jp": 1,
+ "furukawa.miyagi.jp": 1,
+ "fusa.no": 1,
+ "fuso.aichi.jp": 1,
+ "fussa.tokyo.jp": 1,
+ "futaba.fukushima.jp": 1,
+ "futsu.nagasaki.jp": 1,
+ "futtsu.chiba.jp": 1,
+ "futurecms.at": 2,
+ "futurehosting.at": 1,
+ "futuremailing.at": 1,
+ "fvg.it": 1,
+ "fylkesbibl.no": 1,
+ "fyresdal.no": 1,
+ "f\u00f8rde.no": 1,
+ "g.bg": 1,
+ "g.se": 1,
+ "g.vbrplsbx.io": 1,
+ "g12.br": 1,
+ "ga.us": 1,
+ "gaivuotna.no": 1,
+ "gallery.museum": 1,
+ "galsa.no": 1,
+ "gamagori.aichi.jp": 1,
+ "game-host.org": 1,
+ "game-server.cc": 1,
+ "game.tw": 1,
+ "games.hu": 1,
+ "gamo.shiga.jp": 1,
+ "gamvik.no": 1,
+ "gangaviika.no": 1,
+ "gangwon.kr": 1,
+ "garden.museum": 1,
+ "gateway.museum": 1,
+ "gaular.no": 1,
+ "gausdal.no": 1,
+ "gb.com": 1,
+ "gb.net": 1,
+ "gc.ca": 1,
+ "gd.cn": 1,
+ "gda.pl": 1,
+ "gdansk.pl": 1,
+ "gdynia.pl": 1,
+ "ge.it": 1,
+ "geek.nz": 1,
+ "geekgalaxy.com": 1,
+ "geelvinck.museum": 1,
+ "gehirn.ne.jp": 1,
+ "geisei.kochi.jp": 1,
+ "gemological.museum": 1,
+ "gen.in": 1,
+ "gen.mi.us": 1,
+ "gen.ng": 1,
+ "gen.nz": 1,
+ "gen.tr": 1,
+ "genkai.saga.jp": 1,
+ "genoa.it": 1,
+ "genova.it": 1,
+ "gentapps.com": 1,
+ "gentlentapis.com": 1,
+ "geo.br": 1,
+ "geology.museum": 1,
+ "geometre-expert.fr": 1,
+ "georgia.museum": 1,
+ "georgia.su": 1,
+ "getmyip.com": 1,
+ "gets-it.net": 1,
+ "gg.ax": 1,
+ "ggf.br": 1,
+ "giehtavuoatna.no": 1,
+ "giessen.museum": 1,
+ "gifu.gifu.jp": 1,
+ "gifu.jp": 1,
+ "giize.com": 1,
+ "gildeskal.no": 1,
+ "gildesk\u00e5l.no": 1,
+ "ginan.gifu.jp": 1,
+ "ginowan.okinawa.jp": 1,
+ "ginoza.okinawa.jp": 1,
+ "giske.no": 1,
+ "git-pages.rit.edu": 1,
+ "git-repos.de": 1,
+ "gitapp.si": 1,
+ "github.io": 1,
+ "githubusercontent.com": 1,
+ "gitlab.io": 1,
+ "gitpage.si": 1,
+ "gjemnes.no": 1,
+ "gjerdrum.no": 1,
+ "gjerstad.no": 1,
+ "gjesdal.no": 1,
+ "gjovik.no": 1,
+ "gj\u00f8vik.no": 1,
+ "glas.museum": 1,
+ "glass.museum": 1,
+ "gleeze.com": 1,
+ "gliding.aero": 1,
+ "glitch.me": 1,
+ "gliwice.pl": 1,
+ "global.prod.fastly.net": 1,
+ "global.ssl.fastly.net": 1,
+ "glogow.pl": 1,
+ "gloppen.no": 1,
+ "glug.org.uk": 1,
+ "gmina.pl": 1,
+ "gniezno.pl": 1,
+ "go.ci": 1,
+ "go.cr": 1,
+ "go.dyndns.org": 1,
+ "go.gov.br": 1,
+ "go.id": 1,
+ "go.it": 1,
+ "go.jp": 1,
+ "go.ke": 1,
+ "go.kr": 1,
+ "go.leg.br": 1,
+ "go.pw": 1,
+ "go.th": 1,
+ "go.tj": 1,
+ "go.tz": 1,
+ "go.ug": 1,
+ "gob.ar": 1,
+ "gob.bo": 1,
+ "gob.cl": 1,
+ "gob.do": 1,
+ "gob.ec": 1,
+ "gob.es": 1,
+ "gob.gt": 1,
+ "gob.hn": 1,
+ "gob.mx": 1,
+ "gob.ni": 1,
+ "gob.pa": 1,
+ "gob.pe": 1,
+ "gob.pk": 1,
+ "gob.sv": 1,
+ "gob.ve": 1,
+ "gobo.wakayama.jp": 1,
+ "godo.gifu.jp": 1,
+ "goiania.br": 1,
+ "goip.de": 1,
+ "gojome.akita.jp": 1,
+ "gok.pk": 1,
+ "gokase.miyazaki.jp": 1,
+ "gol.no": 1,
+ "golffan.us": 1,
+ "gon.pk": 1,
+ "gonohe.aomori.jp": 1,
+ "googleapis.com": 1,
+ "googlecode.com": 1,
+ "gop.pk": 1,
+ "gorge.museum": 1,
+ "gorizia.it": 1,
+ "gorlice.pl": 1,
+ "gos.pk": 1,
+ "gose.nara.jp": 1,
+ "gosen.niigata.jp": 1,
+ "goshiki.hyogo.jp": 1,
+ "gotdns.ch": 1,
+ "gotdns.com": 1,
+ "gotdns.org": 1,
+ "gotemba.shizuoka.jp": 1,
+ "goto.nagasaki.jp": 1,
+ "gotpantheon.com": 1,
+ "gotsu.shimane.jp": 1,
+ "gouv.bj": 1,
+ "gouv.ci": 1,
+ "gouv.fr": 1,
+ "gouv.ht": 1,
+ "gouv.km": 1,
+ "gouv.ml": 1,
+ "gouv.sn": 1,
+ "gov.ac": 1,
+ "gov.ae": 1,
+ "gov.af": 1,
+ "gov.al": 1,
+ "gov.ar": 1,
+ "gov.as": 1,
+ "gov.au": 1,
+ "gov.az": 1,
+ "gov.ba": 1,
+ "gov.bb": 1,
+ "gov.bf": 1,
+ "gov.bh": 1,
+ "gov.bm": 1,
+ "gov.bn": 1,
+ "gov.br": 1,
+ "gov.bs": 1,
+ "gov.bt": 1,
+ "gov.by": 1,
+ "gov.bz": 1,
+ "gov.cd": 1,
+ "gov.cl": 1,
+ "gov.cm": 1,
+ "gov.cn": 1,
+ "gov.co": 1,
+ "gov.cu": 1,
+ "gov.cx": 1,
+ "gov.cy": 1,
+ "gov.dm": 1,
+ "gov.do": 1,
+ "gov.dz": 1,
+ "gov.ec": 1,
+ "gov.ee": 1,
+ "gov.eg": 1,
+ "gov.et": 1,
+ "gov.fj": 1,
+ "gov.gd": 1,
+ "gov.ge": 1,
+ "gov.gh": 1,
+ "gov.gi": 1,
+ "gov.gn": 1,
+ "gov.gr": 1,
+ "gov.gu": 1,
+ "gov.gy": 1,
+ "gov.hk": 1,
+ "gov.ie": 1,
+ "gov.il": 1,
+ "gov.in": 1,
+ "gov.iq": 1,
+ "gov.ir": 1,
+ "gov.is": 1,
+ "gov.it": 1,
+ "gov.jo": 1,
+ "gov.kg": 1,
+ "gov.ki": 1,
+ "gov.km": 1,
+ "gov.kn": 1,
+ "gov.kp": 1,
+ "gov.kw": 1,
+ "gov.ky": 1,
+ "gov.kz": 1,
+ "gov.la": 1,
+ "gov.lb": 1,
+ "gov.lc": 1,
+ "gov.lk": 1,
+ "gov.lr": 1,
+ "gov.ls": 1,
+ "gov.lt": 1,
+ "gov.lv": 1,
+ "gov.ly": 1,
+ "gov.ma": 1,
+ "gov.me": 1,
+ "gov.mg": 1,
+ "gov.mk": 1,
+ "gov.ml": 1,
+ "gov.mn": 1,
+ "gov.mo": 1,
+ "gov.mr": 1,
+ "gov.ms": 1,
+ "gov.mu": 1,
+ "gov.mv": 1,
+ "gov.mw": 1,
+ "gov.my": 1,
+ "gov.mz": 1,
+ "gov.nc.tr": 1,
+ "gov.ng": 1,
+ "gov.nr": 1,
+ "gov.om": 1,
+ "gov.ph": 1,
+ "gov.pk": 1,
+ "gov.pl": 1,
+ "gov.pn": 1,
+ "gov.pr": 1,
+ "gov.ps": 1,
+ "gov.pt": 1,
+ "gov.py": 1,
+ "gov.qa": 1,
+ "gov.rs": 1,
+ "gov.ru": 1,
+ "gov.rw": 1,
+ "gov.sa": 1,
+ "gov.sb": 1,
+ "gov.sc": 1,
+ "gov.scot": 1,
+ "gov.sd": 1,
+ "gov.sg": 1,
+ "gov.sh": 1,
+ "gov.sl": 1,
+ "gov.so": 1,
+ "gov.ss": 1,
+ "gov.st": 1,
+ "gov.sx": 1,
+ "gov.sy": 1,
+ "gov.tj": 1,
+ "gov.tl": 1,
+ "gov.tm": 1,
+ "gov.tn": 1,
+ "gov.to": 1,
+ "gov.tr": 1,
+ "gov.tt": 1,
+ "gov.tw": 1,
+ "gov.ua": 1,
+ "gov.uk": 1,
+ "gov.vc": 1,
+ "gov.ve": 1,
+ "gov.vn": 1,
+ "gov.ws": 1,
+ "gov.za": 1,
+ "gov.zm": 1,
+ "gov.zw": 1,
+ "government.aero": 1,
+ "govt.nz": 1,
+ "gr.com": 1,
+ "gr.eu.org": 1,
+ "gr.it": 1,
+ "gr.jp": 1,
+ "grajewo.pl": 1,
+ "gran.no": 1,
+ "grandrapids.museum": 1,
+ "grane.no": 1,
+ "granvin.no": 1,
+ "graphox.us": 1,
+ "gratangen.no": 1,
+ "graz.museum": 1,
+ "greta.fr": 1,
+ "grimstad.no": 1,
+ "griw.gov.pl": 1,
+ "groks-the.info": 1,
+ "groks-this.info": 1,
+ "grondar.za": 1,
+ "grong.no": 1,
+ "grosseto.it": 1,
+ "groundhandling.aero": 1,
+ "group.aero": 1,
+ "grozny.ru": 1,
+ "grozny.su": 1,
+ "grp.lk": 1,
+ "gru.br": 1,
+ "grue.no": 1,
+ "gs.aa.no": 1,
+ "gs.ah.no": 1,
+ "gs.bu.no": 1,
+ "gs.cn": 1,
+ "gs.fm.no": 1,
+ "gs.hl.no": 1,
+ "gs.hm.no": 1,
+ "gs.jan-mayen.no": 1,
+ "gs.mr.no": 1,
+ "gs.nl.no": 1,
+ "gs.nt.no": 1,
+ "gs.of.no": 1,
+ "gs.ol.no": 1,
+ "gs.oslo.no": 1,
+ "gs.rl.no": 1,
+ "gs.sf.no": 1,
+ "gs.st.no": 1,
+ "gs.svalbard.no": 1,
+ "gs.tm.no": 1,
+ "gs.tr.no": 1,
+ "gs.va.no": 1,
+ "gs.vf.no": 1,
+ "gsj.bz": 1,
+ "gsm.pl": 1,
+ "gu.us": 1,
+ "guam.gu": 1,
+ "gub.uy": 1,
+ "guernsey.museum": 1,
+ "gujo.gifu.jp": 1,
+ "gulen.no": 1,
+ "gunma.jp": 1,
+ "guovdageaidnu.no": 1,
+ "gushikami.okinawa.jp": 1,
+ "gv.ao": 1,
+ "gv.at": 1,
+ "gv.vc": 1,
+ "gwangju.kr": 1,
+ "gwiddle.co.uk": 1,
+ "gx.cn": 1,
+ "gyeongbuk.kr": 1,
+ "gyeonggi.kr": 1,
+ "gyeongnam.kr": 1,
+ "gyokuto.kumamoto.jp": 1,
+ "gz.cn": 1,
+ "g\u00e1ivuotna.no": 1,
+ "g\u00e1ls\u00e1.no": 1,
+ "g\u00e1\u014bgaviika.no": 1,
+ "h.bg": 1,
+ "h.se": 1,
+ "ha.cn": 1,
+ "ha.no": 1,
+ "habikino.osaka.jp": 1,
+ "habmer.no": 1,
+ "haboro.hokkaido.jp": 1,
+ "hachijo.tokyo.jp": 1,
+ "hachinohe.aomori.jp": 1,
+ "hachioji.tokyo.jp": 1,
+ "hachirogata.akita.jp": 1,
+ "hadano.kanagawa.jp": 1,
+ "hadsel.no": 1,
+ "haebaru.okinawa.jp": 1,
+ "haga.tochigi.jp": 1,
+ "hagebostad.no": 1,
+ "hagi.yamaguchi.jp": 1,
+ "haibara.shizuoka.jp": 1,
+ "hakata.fukuoka.jp": 1,
+ "hakodate.hokkaido.jp": 1,
+ "hakone.kanagawa.jp": 1,
+ "hakuba.nagano.jp": 1,
+ "hakui.ishikawa.jp": 1,
+ "hakusan.ishikawa.jp": 1,
+ "halden.no": 1,
+ "half.host": 1,
+ "halloffame.museum": 1,
+ "halsa.no": 1,
+ "ham-radio-op.net": 1,
+ "hamada.shimane.jp": 1,
+ "hamamatsu.shizuoka.jp": 1,
+ "hamar.no": 1,
+ "hamaroy.no": 1,
+ "hamatama.saga.jp": 1,
+ "hamatonbetsu.hokkaido.jp": 1,
+ "hamburg.museum": 1,
+ "hammarfeasta.no": 1,
+ "hammerfest.no": 1,
+ "hamura.tokyo.jp": 1,
+ "hanamaki.iwate.jp": 1,
+ "hanamigawa.chiba.jp": 1,
+ "hanawa.fukushima.jp": 1,
+ "handa.aichi.jp": 1,
+ "handson.museum": 1,
+ "hanggliding.aero": 1,
+ "hannan.osaka.jp": 1,
+ "hanno.saitama.jp": 1,
+ "hanyu.saitama.jp": 1,
+ "hapmir.no": 1,
+ "happou.akita.jp": 1,
+ "hara.nagano.jp": 1,
+ "haram.no": 1,
+ "hareid.no": 1,
+ "harima.hyogo.jp": 1,
+ "harstad.no": 1,
+ "harvestcelebration.museum": 1,
+ "hasama.oita.jp": 1,
+ "hasami.nagasaki.jp": 1,
+ "hashbang.sh": 1,
+ "hashikami.aomori.jp": 1,
+ "hashima.gifu.jp": 1,
+ "hashimoto.wakayama.jp": 1,
+ "hasuda.saitama.jp": 1,
+ "hasura-app.io": 1,
+ "hasura.app": 1,
+ "hasvik.no": 1,
+ "hatogaya.saitama.jp": 1,
+ "hatoyama.saitama.jp": 1,
+ "hatsukaichi.hiroshima.jp": 1,
+ "hattfjelldal.no": 1,
+ "haugesund.no": 1,
+ "hawaii.museum": 1,
+ "hayakawa.yamanashi.jp": 1,
+ "hayashima.okayama.jp": 1,
+ "hazu.aichi.jp": 1,
+ "hb.cldmail.ru": 1,
+ "hb.cn": 1,
+ "he.cn": 1,
+ "health-carereform.com": 1,
+ "health.museum": 1,
+ "health.nz": 1,
+ "health.vn": 1,
+ "heguri.nara.jp": 1,
+ "heimatunduhren.museum": 1,
+ "hekinan.aichi.jp": 1,
+ "hellas.museum": 1,
+ "helsinki.museum": 1,
+ "hembygdsforbund.museum": 1,
+ "hemne.no": 1,
+ "hemnes.no": 1,
+ "hemsedal.no": 1,
+ "hepforge.org": 1,
+ "herad.no": 1,
+ "here-for-more.info": 1,
+ "heritage.museum": 1,
+ "herokuapp.com": 1,
+ "herokussl.com": 1,
+ "heroy.more-og-romsdal.no": 1,
+ "heroy.nordland.no": 1,
+ "her\u00f8y.m\u00f8re-og-romsdal.no": 1,
+ "her\u00f8y.nordland.no": 1,
+ "hi.cn": 1,
+ "hi.us": 1,
+ "hicam.net": 1,
+ "hichiso.gifu.jp": 1,
+ "hida.gifu.jp": 1,
+ "hidaka.hokkaido.jp": 1,
+ "hidaka.kochi.jp": 1,
+ "hidaka.saitama.jp": 1,
+ "hidaka.wakayama.jp": 1,
+ "hidora.com": 1,
+ "higashi.fukuoka.jp": 1,
+ "higashi.fukushima.jp": 1,
+ "higashi.okinawa.jp": 1,
+ "higashiagatsuma.gunma.jp": 1,
+ "higashichichibu.saitama.jp": 1,
+ "higashihiroshima.hiroshima.jp": 1,
+ "higashiizu.shizuoka.jp": 1,
+ "higashiizumo.shimane.jp": 1,
+ "higashikagawa.kagawa.jp": 1,
+ "higashikagura.hokkaido.jp": 1,
+ "higashikawa.hokkaido.jp": 1,
+ "higashikurume.tokyo.jp": 1,
+ "higashimatsushima.miyagi.jp": 1,
+ "higashimatsuyama.saitama.jp": 1,
+ "higashimurayama.tokyo.jp": 1,
+ "higashinaruse.akita.jp": 1,
+ "higashine.yamagata.jp": 1,
+ "higashiomi.shiga.jp": 1,
+ "higashiosaka.osaka.jp": 1,
+ "higashishirakawa.gifu.jp": 1,
+ "higashisumiyoshi.osaka.jp": 1,
+ "higashitsuno.kochi.jp": 1,
+ "higashiura.aichi.jp": 1,
+ "higashiyama.kyoto.jp": 1,
+ "higashiyamato.tokyo.jp": 1,
+ "higashiyodogawa.osaka.jp": 1,
+ "higashiyoshino.nara.jp": 1,
+ "hiji.oita.jp": 1,
+ "hikari.yamaguchi.jp": 1,
+ "hikawa.shimane.jp": 1,
+ "hikimi.shimane.jp": 1,
+ "hikone.shiga.jp": 1,
+ "himeji.hyogo.jp": 1,
+ "himeshima.oita.jp": 1,
+ "himi.toyama.jp": 1,
+ "hino.tokyo.jp": 1,
+ "hino.tottori.jp": 1,
+ "hinode.tokyo.jp": 1,
+ "hinohara.tokyo.jp": 1,
+ "hioki.kagoshima.jp": 1,
+ "hirado.nagasaki.jp": 1,
+ "hiraizumi.iwate.jp": 1,
+ "hirakata.osaka.jp": 1,
+ "hiranai.aomori.jp": 1,
+ "hirara.okinawa.jp": 1,
+ "hirata.fukushima.jp": 1,
+ "hiratsuka.kanagawa.jp": 1,
+ "hiraya.nagano.jp": 1,
+ "hirogawa.wakayama.jp": 1,
+ "hirokawa.fukuoka.jp": 1,
+ "hirono.fukushima.jp": 1,
+ "hirono.iwate.jp": 1,
+ "hiroo.hokkaido.jp": 1,
+ "hirosaki.aomori.jp": 1,
+ "hiroshima.jp": 1,
+ "hisayama.fukuoka.jp": 1,
+ "histoire.museum": 1,
+ "historical.museum": 1,
+ "historicalsociety.museum": 1,
+ "historichouses.museum": 1,
+ "historisch.museum": 1,
+ "historisches.museum": 1,
+ "history.museum": 1,
+ "historyofscience.museum": 1,
+ "hita.oita.jp": 1,
+ "hitachi.ibaraki.jp": 1,
+ "hitachinaka.ibaraki.jp": 1,
+ "hitachiomiya.ibaraki.jp": 1,
+ "hitachiota.ibaraki.jp": 1,
+ "hitra.no": 1,
+ "hizen.saga.jp": 1,
+ "hjartdal.no": 1,
+ "hjelmeland.no": 1,
+ "hk.cn": 1,
+ "hk.com": 1,
+ "hk.org": 1,
+ "hl.cn": 1,
+ "hl.no": 1,
+ "hm.no": 1,
+ "hn.cn": 1,
+ "hobby-site.com": 1,
+ "hobby-site.org": 1,
+ "hobol.no": 1,
+ "hob\u00f8l.no": 1,
+ "hof.no": 1,
+ "hofu.yamaguchi.jp": 1,
+ "hokkaido.jp": 1,
+ "hokksund.no": 1,
+ "hokuryu.hokkaido.jp": 1,
+ "hokuto.hokkaido.jp": 1,
+ "hokuto.yamanashi.jp": 1,
+ "hol.no": 1,
+ "hole.no": 1,
+ "holmestrand.no": 1,
+ "holtalen.no": 1,
+ "holt\u00e5len.no": 1,
+ "home-webserver.de": 1,
+ "home.dyndns.org": 1,
+ "homebuilt.aero": 1,
+ "homedns.org": 1,
+ "homeftp.net": 1,
+ "homeftp.org": 1,
+ "homeip.net": 1,
+ "homelink.one": 1,
+ "homelinux.com": 1,
+ "homelinux.net": 1,
+ "homelinux.org": 1,
+ "homeoffice.gov.uk": 1,
+ "homesecuritymac.com": 1,
+ "homesecuritypc.com": 1,
+ "homeunix.com": 1,
+ "homeunix.net": 1,
+ "homeunix.org": 1,
+ "honai.ehime.jp": 1,
+ "honbetsu.hokkaido.jp": 1,
+ "honefoss.no": 1,
+ "hongo.hiroshima.jp": 1,
+ "honjo.akita.jp": 1,
+ "honjo.saitama.jp": 1,
+ "honjyo.akita.jp": 1,
+ "hopto.me": 1,
+ "hopto.org": 1,
+ "hornindal.no": 1,
+ "horokanai.hokkaido.jp": 1,
+ "horology.museum": 1,
+ "horonobe.hokkaido.jp": 1,
+ "horten.no": 1,
+ "hostedpi.com": 1,
+ "hosting-cluster.nl": 1,
+ "hosting.myjino.ru": 2,
+ "hostyhosting.io": 1,
+ "hotel.hu": 1,
+ "hotel.lk": 1,
+ "hotel.tz": 1,
+ "house.museum": 1,
+ "hoyanger.no": 1,
+ "hoylandet.no": 1,
+ "hr.eu.org": 1,
+ "hs.kr": 1,
+ "hs.run": 1,
+ "hs.zone": 1,
+ "hu.com": 1,
+ "hu.eu.org": 1,
+ "hu.net": 1,
+ "huissier-justice.fr": 1,
+ "humanities.museum": 1,
+ "hurdal.no": 1,
+ "hurum.no": 1,
+ "hvaler.no": 1,
+ "hyllestad.no": 1,
+ "hyogo.jp": 1,
+ "hyuga.miyazaki.jp": 1,
+ "hzc.io": 1,
+ "h\u00e1bmer.no": 1,
+ "h\u00e1mm\u00e1rfeasta.no": 1,
+ "h\u00e1pmir.no": 1,
+ "h\u00e4kkinen.fi": 1,
+ "h\u00e5.no": 1,
+ "h\u00e6gebostad.no": 1,
+ "h\u00f8nefoss.no": 1,
+ "h\u00f8yanger.no": 1,
+ "h\u00f8ylandet.no": 1,
+ "i.bg": 1,
+ "i.ng": 1,
+ "i.ph": 1,
+ "i.se": 1,
+ "i234.me": 1,
+ "ia.us": 1,
+ "iamallama.com": 1,
+ "ibara.okayama.jp": 1,
+ "ibaraki.ibaraki.jp": 1,
+ "ibaraki.jp": 1,
+ "ibaraki.osaka.jp": 1,
+ "ibestad.no": 1,
+ "ibigawa.gifu.jp": 1,
+ "ic.gov.pl": 1,
+ "ichiba.tokushima.jp": 1,
+ "ichihara.chiba.jp": 1,
+ "ichikai.tochigi.jp": 1,
+ "ichikawa.chiba.jp": 1,
+ "ichikawa.hyogo.jp": 1,
+ "ichikawamisato.yamanashi.jp": 1,
+ "ichinohe.iwate.jp": 1,
+ "ichinomiya.aichi.jp": 1,
+ "ichinomiya.chiba.jp": 1,
+ "ichinoseki.iwate.jp": 1,
+ "id.au": 1,
+ "id.ir": 1,
+ "id.lv": 1,
+ "id.ly": 1,
+ "id.us": 1,
+ "ide.kyoto.jp": 1,
+ "idf.il": 1,
+ "idrett.no": 1,
+ "idv.hk": 1,
+ "idv.tw": 1,
+ "ie.eu.org": 1,
+ "if.ua": 1,
+ "iglesias-carbonia.it": 1,
+ "iglesiascarbonia.it": 1,
+ "iheya.okinawa.jp": 1,
+ "iida.nagano.jp": 1,
+ "iide.yamagata.jp": 1,
+ "iijima.nagano.jp": 1,
+ "iitate.fukushima.jp": 1,
+ "iiyama.nagano.jp": 1,
+ "iizuka.fukuoka.jp": 1,
+ "iizuna.nagano.jp": 1,
+ "ikaruga.nara.jp": 1,
+ "ikata.ehime.jp": 1,
+ "ikawa.akita.jp": 1,
+ "ikeda.fukui.jp": 1,
+ "ikeda.gifu.jp": 1,
+ "ikeda.hokkaido.jp": 1,
+ "ikeda.nagano.jp": 1,
+ "ikeda.osaka.jp": 1,
+ "iki.fi": 1,
+ "iki.nagasaki.jp": 1,
+ "ikoma.nara.jp": 1,
+ "ikusaka.nagano.jp": 1,
+ "il.eu.org": 1,
+ "il.us": 1,
+ "ilawa.pl": 1,
+ "illustration.museum": 1,
+ "ilovecollege.info": 1,
+ "im.it": 1,
+ "imabari.ehime.jp": 1,
+ "imageandsound.museum": 1,
+ "imakane.hokkaido.jp": 1,
+ "imari.saga.jp": 1,
+ "imb.br": 1,
+ "imizu.toyama.jp": 1,
+ "imperia.it": 1,
+ "impertrix.com": 1,
+ "impertrixcdn.com": 1,
+ "in-addr.arpa": 1,
+ "in-berlin.de": 1,
+ "in-brb.de": 1,
+ "in-butter.de": 1,
+ "in-dsl.de": 1,
+ "in-dsl.net": 1,
+ "in-dsl.org": 1,
+ "in-the-band.net": 1,
+ "in-vpn.de": 1,
+ "in-vpn.net": 1,
+ "in-vpn.org": 1,
+ "in.eu.org": 1,
+ "in.futurecms.at": 2,
+ "in.london": 1,
+ "in.na": 1,
+ "in.net": 1,
+ "in.ni": 1,
+ "in.rs": 1,
+ "in.th": 1,
+ "in.ua": 1,
+ "in.us": 1,
+ "ina.ibaraki.jp": 1,
+ "ina.nagano.jp": 1,
+ "ina.saitama.jp": 1,
+ "inabe.mie.jp": 1,
+ "inagawa.hyogo.jp": 1,
+ "inagi.tokyo.jp": 1,
+ "inami.toyama.jp": 1,
+ "inami.wakayama.jp": 1,
+ "inashiki.ibaraki.jp": 1,
+ "inatsuki.fukuoka.jp": 1,
+ "inawashiro.fukushima.jp": 1,
+ "inazawa.aichi.jp": 1,
+ "inc.hk": 1,
+ "incheon.kr": 1,
+ "ind.br": 1,
+ "ind.gt": 1,
+ "ind.in": 1,
+ "ind.kw": 1,
+ "ind.tn": 1,
+ "inderoy.no": 1,
+ "inder\u00f8y.no": 1,
+ "indian.museum": 1,
+ "indiana.museum": 1,
+ "indianapolis.museum": 1,
+ "indianmarket.museum": 1,
+ "indie.porn": 1,
+ "indigena.bo": 1,
+ "industria.bo": 1,
+ "ine.kyoto.jp": 1,
+ "inf.br": 1,
+ "inf.cu": 1,
+ "inf.mk": 1,
+ "inf.ua": 1,
+ "info.at": 1,
+ "info.au": 1,
+ "info.az": 1,
+ "info.bb": 1,
+ "info.bo": 1,
+ "info.co": 1,
+ "info.cx": 1,
+ "info.ec": 1,
+ "info.et": 1,
+ "info.fj": 1,
+ "info.gu": 1,
+ "info.ht": 1,
+ "info.hu": 1,
+ "info.ke": 1,
+ "info.ki": 1,
+ "info.la": 1,
+ "info.ls": 1,
+ "info.mv": 1,
+ "info.na": 1,
+ "info.nf": 1,
+ "info.ni": 1,
+ "info.nr": 1,
+ "info.pk": 1,
+ "info.pl": 1,
+ "info.pr": 1,
+ "info.ro": 1,
+ "info.sd": 1,
+ "info.tn": 1,
+ "info.tr": 1,
+ "info.tt": 1,
+ "info.tz": 1,
+ "info.ve": 1,
+ "info.vn": 1,
+ "info.zm": 1,
+ "ing.pa": 1,
+ "ingatlan.hu": 1,
+ "ino.kochi.jp": 1,
+ "instantcloud.cn": 1,
+ "insurance.aero": 1,
+ "int.ar": 1,
+ "int.az": 1,
+ "int.bo": 1,
+ "int.ci": 1,
+ "int.co": 1,
+ "int.eu.org": 1,
+ "int.is": 1,
+ "int.la": 1,
+ "int.lk": 1,
+ "int.mv": 1,
+ "int.mw": 1,
+ "int.ni": 1,
+ "int.pt": 1,
+ "int.ru": 1,
+ "int.tj": 1,
+ "int.tt": 1,
+ "int.ve": 1,
+ "int.vn": 1,
+ "intelligence.museum": 1,
+ "interactive.museum": 1,
+ "internet-dns.de": 1,
+ "intl.tn": 1,
+ "inuyama.aichi.jp": 1,
+ "inzai.chiba.jp": 1,
+ "io.kg": 1,
+ "iobb.net": 1,
+ "ip6.arpa": 1,
+ "ipifony.net": 1,
+ "iraq.museum": 1,
+ "iris.arpa": 1,
+ "iron.museum": 1,
+ "iruma.saitama.jp": 1,
+ "is-a-anarchist.com": 1,
+ "is-a-blogger.com": 1,
+ "is-a-bookkeeper.com": 1,
+ "is-a-bruinsfan.org": 1,
+ "is-a-bulls-fan.com": 1,
+ "is-a-candidate.org": 1,
+ "is-a-caterer.com": 1,
+ "is-a-celticsfan.org": 1,
+ "is-a-chef.com": 1,
+ "is-a-chef.net": 1,
+ "is-a-chef.org": 1,
+ "is-a-conservative.com": 1,
+ "is-a-cpa.com": 1,
+ "is-a-cubicle-slave.com": 1,
+ "is-a-democrat.com": 1,
+ "is-a-designer.com": 1,
+ "is-a-doctor.com": 1,
+ "is-a-financialadvisor.com": 1,
+ "is-a-geek.com": 1,
+ "is-a-geek.net": 1,
+ "is-a-geek.org": 1,
+ "is-a-green.com": 1,
+ "is-a-guru.com": 1,
+ "is-a-hard-worker.com": 1,
+ "is-a-hunter.com": 1,
+ "is-a-knight.org": 1,
+ "is-a-landscaper.com": 1,
+ "is-a-lawyer.com": 1,
+ "is-a-liberal.com": 1,
+ "is-a-libertarian.com": 1,
+ "is-a-linux-user.org": 1,
+ "is-a-llama.com": 1,
+ "is-a-musician.com": 1,
+ "is-a-nascarfan.com": 1,
+ "is-a-nurse.com": 1,
+ "is-a-painter.com": 1,
+ "is-a-patsfan.org": 1,
+ "is-a-personaltrainer.com": 1,
+ "is-a-photographer.com": 1,
+ "is-a-player.com": 1,
+ "is-a-republican.com": 1,
+ "is-a-rockstar.com": 1,
+ "is-a-socialist.com": 1,
+ "is-a-soxfan.org": 1,
+ "is-a-student.com": 1,
+ "is-a-teacher.com": 1,
+ "is-a-techie.com": 1,
+ "is-a-therapist.com": 1,
+ "is-an-accountant.com": 1,
+ "is-an-actor.com": 1,
+ "is-an-actress.com": 1,
+ "is-an-anarchist.com": 1,
+ "is-an-artist.com": 1,
+ "is-an-engineer.com": 1,
+ "is-an-entertainer.com": 1,
+ "is-by.us": 1,
+ "is-certified.com": 1,
+ "is-found.org": 1,
+ "is-gone.com": 1,
+ "is-into-anime.com": 1,
+ "is-into-cars.com": 1,
+ "is-into-cartoons.com": 1,
+ "is-into-games.com": 1,
+ "is-leet.com": 1,
+ "is-lost.org": 1,
+ "is-not-certified.com": 1,
+ "is-saved.org": 1,
+ "is-slick.com": 1,
+ "is-uberleet.com": 1,
+ "is-very-bad.org": 1,
+ "is-very-evil.org": 1,
+ "is-very-good.org": 1,
+ "is-very-nice.org": 1,
+ "is-very-sweet.org": 1,
+ "is-with-theband.com": 1,
+ "is.eu.org": 1,
+ "is.gov.pl": 1,
+ "is.it": 1,
+ "isa-geek.com": 1,
+ "isa-geek.net": 1,
+ "isa-geek.org": 1,
+ "isa-hockeynut.com": 1,
+ "isa.kagoshima.jp": 1,
+ "isa.us": 1,
+ "isahaya.nagasaki.jp": 1,
+ "ise.mie.jp": 1,
+ "isehara.kanagawa.jp": 1,
+ "isen.kagoshima.jp": 1,
+ "isernia.it": 1,
+ "iserv.dev": 1,
+ "isesaki.gunma.jp": 1,
+ "ishigaki.okinawa.jp": 1,
+ "ishikari.hokkaido.jp": 1,
+ "ishikawa.fukushima.jp": 1,
+ "ishikawa.jp": 1,
+ "ishikawa.okinawa.jp": 1,
+ "ishinomaki.miyagi.jp": 1,
+ "isla.pr": 1,
+ "isleofman.museum": 1,
+ "isshiki.aichi.jp": 1,
+ "issmarterthanyou.com": 1,
+ "isteingeek.de": 1,
+ "istmein.de": 1,
+ "isumi.chiba.jp": 1,
+ "it.ao": 1,
+ "it.eu.org": 1,
+ "itabashi.tokyo.jp": 1,
+ "itako.ibaraki.jp": 1,
+ "itakura.gunma.jp": 1,
+ "itami.hyogo.jp": 1,
+ "itano.tokushima.jp": 1,
+ "itayanagi.aomori.jp": 1,
+ "ito.shizuoka.jp": 1,
+ "itoigawa.niigata.jp": 1,
+ "itoman.okinawa.jp": 1,
+ "its.me": 1,
+ "ivano-frankivsk.ua": 1,
+ "ivanovo.su": 1,
+ "iveland.no": 1,
+ "ivgu.no": 1,
+ "iwade.wakayama.jp": 1,
+ "iwafune.tochigi.jp": 1,
+ "iwaizumi.iwate.jp": 1,
+ "iwaki.fukushima.jp": 1,
+ "iwakuni.yamaguchi.jp": 1,
+ "iwakura.aichi.jp": 1,
+ "iwama.ibaraki.jp": 1,
+ "iwamizawa.hokkaido.jp": 1,
+ "iwanai.hokkaido.jp": 1,
+ "iwanuma.miyagi.jp": 1,
+ "iwata.shizuoka.jp": 1,
+ "iwate.iwate.jp": 1,
+ "iwate.jp": 1,
+ "iwatsuki.saitama.jp": 1,
+ "iwi.nz": 1,
+ "iyo.ehime.jp": 1,
+ "iz.hr": 1,
+ "izena.okinawa.jp": 1,
+ "izu.shizuoka.jp": 1,
+ "izumi.kagoshima.jp": 1,
+ "izumi.osaka.jp": 1,
+ "izumiotsu.osaka.jp": 1,
+ "izumisano.osaka.jp": 1,
+ "izumizaki.fukushima.jp": 1,
+ "izumo.shimane.jp": 1,
+ "izumozaki.niigata.jp": 1,
+ "izunokuni.shizuoka.jp": 1,
+ "j.bg": 1,
+ "j.layershift.co.uk": 1,
+ "j.scaleforce.com.cy": 1,
+ "jab.br": 1,
+ "jambyl.su": 1,
+ "jamison.museum": 1,
+ "jampa.br": 1,
+ "jan-mayen.no": 1,
+ "jaworzno.pl": 1,
+ "jcloud.ik-server.com": 1,
+ "jdevcloud.com": 1,
+ "jdf.br": 1,
+ "jefferson.museum": 1,
+ "jeju.kr": 1,
+ "jelastic.dogado.eu": 1,
+ "jelastic.regruhosting.ru": 1,
+ "jelastic.saveincloud.net": 1,
+ "jelastic.team": 1,
+ "jele.cloud": 1,
+ "jele.club": 1,
+ "jele.host": 1,
+ "jele.io": 1,
+ "jele.site": 1,
+ "jelenia-gora.pl": 1,
+ "jeonbuk.kr": 1,
+ "jeonnam.kr": 1,
+ "jerusalem.museum": 1,
+ "jessheim.no": 1,
+ "jevnaker.no": 1,
+ "jewelry.museum": 1,
+ "jewish.museum": 1,
+ "jewishart.museum": 1,
+ "jfk.museum": 1,
+ "jgora.pl": 1,
+ "jinsekikogen.hiroshima.jp": 1,
+ "jl.cn": 1,
+ "jls-sto1.elastx.net": 1,
+ "jm": 2,
+ "joboji.iwate.jp": 1,
+ "jobs.tt": 1,
+ "joetsu.niigata.jp": 1,
+ "jogasz.hu": 1,
+ "johana.toyama.jp": 1,
+ "joinville.br": 1,
+ "jolster.no": 1,
+ "jondal.no": 1,
+ "jor.br": 1,
+ "jorpeland.no": 1,
+ "joso.ibaraki.jp": 1,
+ "journal.aero": 1,
+ "journalism.museum": 1,
+ "journalist.aero": 1,
+ "joyo.kyoto.jp": 1,
+ "jozi.biz": 1,
+ "jp.eu.org": 1,
+ "jp.kg": 1,
+ "jp.md": 1,
+ "jp.net": 1,
+ "jpn.com": 1,
+ "js.cn": 1,
+ "js.org": 1,
+ "js.wpenginepowered.com": 1,
+ "judaica.museum": 1,
+ "judygarland.museum": 1,
+ "juedisches.museum": 1,
+ "juif.museum": 1,
+ "jur.pro": 1,
+ "jus.br": 1,
+ "jx.cn": 1,
+ "j\u00f8lster.no": 1,
+ "j\u00f8rpeland.no": 1,
+ "k.bg": 1,
+ "k.se": 1,
+ "k12.ak.us": 1,
+ "k12.al.us": 1,
+ "k12.ar.us": 1,
+ "k12.as.us": 1,
+ "k12.az.us": 1,
+ "k12.ca.us": 1,
+ "k12.co.us": 1,
+ "k12.ct.us": 1,
+ "k12.dc.us": 1,
+ "k12.de.us": 1,
+ "k12.ec": 1,
+ "k12.fl.us": 1,
+ "k12.ga.us": 1,
+ "k12.gu.us": 1,
+ "k12.ia.us": 1,
+ "k12.id.us": 1,
+ "k12.il": 1,
+ "k12.il.us": 1,
+ "k12.in.us": 1,
+ "k12.ks.us": 1,
+ "k12.ky.us": 1,
+ "k12.la.us": 1,
+ "k12.ma.us": 1,
+ "k12.md.us": 1,
+ "k12.me.us": 1,
+ "k12.mi.us": 1,
+ "k12.mn.us": 1,
+ "k12.mo.us": 1,
+ "k12.ms.us": 1,
+ "k12.mt.us": 1,
+ "k12.nc.us": 1,
+ "k12.ne.us": 1,
+ "k12.nh.us": 1,
+ "k12.nj.us": 1,
+ "k12.nm.us": 1,
+ "k12.nv.us": 1,
+ "k12.ny.us": 1,
+ "k12.oh.us": 1,
+ "k12.ok.us": 1,
+ "k12.or.us": 1,
+ "k12.pa.us": 1,
+ "k12.pr.us": 1,
+ "k12.sc.us": 1,
+ "k12.tn.us": 1,
+ "k12.tr": 1,
+ "k12.tx.us": 1,
+ "k12.ut.us": 1,
+ "k12.va.us": 1,
+ "k12.vi": 1,
+ "k12.vi.us": 1,
+ "k12.vt.us": 1,
+ "k12.wa.us": 1,
+ "k12.wi.us": 1,
+ "k12.wy.us": 1,
+ "kaas.gg": 1,
+ "kadena.okinawa.jp": 1,
+ "kadogawa.miyazaki.jp": 1,
+ "kadoma.osaka.jp": 1,
+ "kafjord.no": 1,
+ "kaga.ishikawa.jp": 1,
+ "kagami.kochi.jp": 1,
+ "kagamiishi.fukushima.jp": 1,
+ "kagamino.okayama.jp": 1,
+ "kagawa.jp": 1,
+ "kagoshima.jp": 1,
+ "kagoshima.kagoshima.jp": 1,
+ "kaho.fukuoka.jp": 1,
+ "kahoku.ishikawa.jp": 1,
+ "kahoku.yamagata.jp": 1,
+ "kai.yamanashi.jp": 1,
+ "kainan.tokushima.jp": 1,
+ "kainan.wakayama.jp": 1,
+ "kaisei.kanagawa.jp": 1,
+ "kaita.hiroshima.jp": 1,
+ "kaizuka.osaka.jp": 1,
+ "kakamigahara.gifu.jp": 1,
+ "kakegawa.shizuoka.jp": 1,
+ "kakinoki.shimane.jp": 1,
+ "kakogawa.hyogo.jp": 1,
+ "kakuda.miyagi.jp": 1,
+ "kalisz.pl": 1,
+ "kalmykia.ru": 1,
+ "kalmykia.su": 1,
+ "kaluga.su": 1,
+ "kamagaya.chiba.jp": 1,
+ "kamaishi.iwate.jp": 1,
+ "kamakura.kanagawa.jp": 1,
+ "kameoka.kyoto.jp": 1,
+ "kameyama.mie.jp": 1,
+ "kami.kochi.jp": 1,
+ "kami.miyagi.jp": 1,
+ "kamiamakusa.kumamoto.jp": 1,
+ "kamifurano.hokkaido.jp": 1,
+ "kamigori.hyogo.jp": 1,
+ "kamiichi.toyama.jp": 1,
+ "kamiizumi.saitama.jp": 1,
+ "kamijima.ehime.jp": 1,
+ "kamikawa.hokkaido.jp": 1,
+ "kamikawa.hyogo.jp": 1,
+ "kamikawa.saitama.jp": 1,
+ "kamikitayama.nara.jp": 1,
+ "kamikoani.akita.jp": 1,
+ "kamimine.saga.jp": 1,
+ "kaminokawa.tochigi.jp": 1,
+ "kaminoyama.yamagata.jp": 1,
+ "kamioka.akita.jp": 1,
+ "kamisato.saitama.jp": 1,
+ "kamishihoro.hokkaido.jp": 1,
+ "kamisu.ibaraki.jp": 1,
+ "kamisunagawa.hokkaido.jp": 1,
+ "kamitonda.wakayama.jp": 1,
+ "kamitsue.oita.jp": 1,
+ "kamo.kyoto.jp": 1,
+ "kamo.niigata.jp": 1,
+ "kamoenai.hokkaido.jp": 1,
+ "kamogawa.chiba.jp": 1,
+ "kanagawa.jp": 1,
+ "kanan.osaka.jp": 1,
+ "kanazawa.ishikawa.jp": 1,
+ "kanegasaki.iwate.jp": 1,
+ "kaneyama.fukushima.jp": 1,
+ "kaneyama.yamagata.jp": 1,
+ "kani.gifu.jp": 1,
+ "kanie.aichi.jp": 1,
+ "kanmaki.nara.jp": 1,
+ "kanna.gunma.jp": 1,
+ "kannami.shizuoka.jp": 1,
+ "kanonji.kagawa.jp": 1,
+ "kanoya.kagoshima.jp": 1,
+ "kanra.gunma.jp": 1,
+ "kanuma.tochigi.jp": 1,
+ "kanzaki.saga.jp": 1,
+ "karacol.su": 1,
+ "karaganda.su": 1,
+ "karasjohka.no": 1,
+ "karasjok.no": 1,
+ "karasuyama.tochigi.jp": 1,
+ "karate.museum": 1,
+ "karatsu.saga.jp": 1,
+ "karelia.su": 1,
+ "karikatur.museum": 1,
+ "kariwa.niigata.jp": 1,
+ "kariya.aichi.jp": 1,
+ "karlsoy.no": 1,
+ "karmoy.no": 1,
+ "karm\u00f8y.no": 1,
+ "karpacz.pl": 1,
+ "kartuzy.pl": 1,
+ "karuizawa.nagano.jp": 1,
+ "karumai.iwate.jp": 1,
+ "kasahara.gifu.jp": 1,
+ "kasai.hyogo.jp": 1,
+ "kasama.ibaraki.jp": 1,
+ "kasamatsu.gifu.jp": 1,
+ "kasaoka.okayama.jp": 1,
+ "kashiba.nara.jp": 1,
+ "kashihara.nara.jp": 1,
+ "kashima.ibaraki.jp": 1,
+ "kashima.saga.jp": 1,
+ "kashiwa.chiba.jp": 1,
+ "kashiwara.osaka.jp": 1,
+ "kashiwazaki.niigata.jp": 1,
+ "kasserver.com": 1,
+ "kasuga.fukuoka.jp": 1,
+ "kasuga.hyogo.jp": 1,
+ "kasugai.aichi.jp": 1,
+ "kasukabe.saitama.jp": 1,
+ "kasumigaura.ibaraki.jp": 1,
+ "kasuya.fukuoka.jp": 1,
+ "kaszuby.pl": 1,
+ "katagami.akita.jp": 1,
+ "katano.osaka.jp": 1,
+ "katashina.gunma.jp": 1,
+ "katori.chiba.jp": 1,
+ "katowice.pl": 1,
+ "katsuragi.nara.jp": 1,
+ "katsuragi.wakayama.jp": 1,
+ "katsushika.tokyo.jp": 1,
+ "katsuura.chiba.jp": 1,
+ "katsuyama.fukui.jp": 1,
+ "kautokeino.no": 1,
+ "kawaba.gunma.jp": 1,
+ "kawachinagano.osaka.jp": 1,
+ "kawagoe.mie.jp": 1,
+ "kawagoe.saitama.jp": 1,
+ "kawaguchi.saitama.jp": 1,
+ "kawahara.tottori.jp": 1,
+ "kawai.iwate.jp": 1,
+ "kawai.nara.jp": 1,
+ "kawajima.saitama.jp": 1,
+ "kawakami.nagano.jp": 1,
+ "kawakami.nara.jp": 1,
+ "kawakita.ishikawa.jp": 1,
+ "kawamata.fukushima.jp": 1,
+ "kawaminami.miyazaki.jp": 1,
+ "kawanabe.kagoshima.jp": 1,
+ "kawanehon.shizuoka.jp": 1,
+ "kawanishi.hyogo.jp": 1,
+ "kawanishi.nara.jp": 1,
+ "kawanishi.yamagata.jp": 1,
+ "kawara.fukuoka.jp": 1,
+ "kawasaki.jp": 2,
+ "kawasaki.miyagi.jp": 1,
+ "kawatana.nagasaki.jp": 1,
+ "kawaue.gifu.jp": 1,
+ "kawazu.shizuoka.jp": 1,
+ "kayabe.hokkaido.jp": 1,
+ "kazimierz-dolny.pl": 1,
+ "kazo.saitama.jp": 1,
+ "kazuno.akita.jp": 1,
+ "keisen.fukuoka.jp": 1,
+ "kembuchi.hokkaido.jp": 1,
+ "kep.tr": 1,
+ "kepno.pl": 1,
+ "ketrzyn.pl": 1,
+ "keymachine.de": 1,
+ "kg.kr": 1,
+ "kh": 2,
+ "kh.ua": 1,
+ "khakassia.su": 1,
+ "kharkiv.ua": 1,
+ "kharkov.ua": 1,
+ "kherson.ua": 1,
+ "khmelnitskiy.ua": 1,
+ "khmelnytskyi.ua": 1,
+ "khplay.nl": 1,
+ "kibichuo.okayama.jp": 1,
+ "kicks-ass.net": 1,
+ "kicks-ass.org": 1,
+ "kids.museum": 1,
+ "kids.us": 1,
+ "kiev.ua": 1,
+ "kiho.mie.jp": 1,
+ "kihoku.ehime.jp": 1,
+ "kijo.miyazaki.jp": 1,
+ "kikonai.hokkaido.jp": 1,
+ "kikuchi.kumamoto.jp": 1,
+ "kikugawa.shizuoka.jp": 1,
+ "kimino.wakayama.jp": 1,
+ "kimitsu.chiba.jp": 1,
+ "kimobetsu.hokkaido.jp": 1,
+ "kin.okinawa.jp": 1,
+ "kinghost.net": 1,
+ "kinko.kagoshima.jp": 1,
+ "kinokawa.wakayama.jp": 1,
+ "kira.aichi.jp": 1,
+ "kirkenes.no": 1,
+ "kirovograd.ua": 1,
+ "kiryu.gunma.jp": 1,
+ "kisarazu.chiba.jp": 1,
+ "kishiwada.osaka.jp": 1,
+ "kiso.nagano.jp": 1,
+ "kisofukushima.nagano.jp": 1,
+ "kisosaki.mie.jp": 1,
+ "kita.kyoto.jp": 1,
+ "kita.osaka.jp": 1,
+ "kita.tokyo.jp": 1,
+ "kitaaiki.nagano.jp": 1,
+ "kitaakita.akita.jp": 1,
+ "kitadaito.okinawa.jp": 1,
+ "kitagata.gifu.jp": 1,
+ "kitagata.saga.jp": 1,
+ "kitagawa.kochi.jp": 1,
+ "kitagawa.miyazaki.jp": 1,
+ "kitahata.saga.jp": 1,
+ "kitahiroshima.hokkaido.jp": 1,
+ "kitakami.iwate.jp": 1,
+ "kitakata.fukushima.jp": 1,
+ "kitakata.miyazaki.jp": 1,
+ "kitakyushu.jp": 2,
+ "kitami.hokkaido.jp": 1,
+ "kitamoto.saitama.jp": 1,
+ "kitanakagusuku.okinawa.jp": 1,
+ "kitashiobara.fukushima.jp": 1,
+ "kitaura.miyazaki.jp": 1,
+ "kitayama.wakayama.jp": 1,
+ "kiwa.mie.jp": 1,
+ "kiwi.nz": 1,
+ "kiyama.saga.jp": 1,
+ "kiyokawa.kanagawa.jp": 1,
+ "kiyosato.hokkaido.jp": 1,
+ "kiyose.tokyo.jp": 1,
+ "kiyosu.aichi.jp": 1,
+ "kizu.kyoto.jp": 1,
+ "klabu.no": 1,
+ "klepp.no": 1,
+ "klodzko.pl": 1,
+ "kl\u00e6bu.no": 1,
+ "km.ua": 1,
+ "kmpsp.gov.pl": 1,
+ "knightpoint.systems": 1,
+ "knowsitall.info": 1,
+ "knx-server.net": 1,
+ "kobayashi.miyazaki.jp": 1,
+ "kobe.jp": 2,
+ "kobierzyce.pl": 1,
+ "kochi.jp": 1,
+ "kochi.kochi.jp": 1,
+ "kodaira.tokyo.jp": 1,
+ "koebenhavn.museum": 1,
+ "koeln.museum": 1,
+ "kofu.yamanashi.jp": 1,
+ "koga.fukuoka.jp": 1,
+ "koga.ibaraki.jp": 1,
+ "koganei.tokyo.jp": 1,
+ "koge.tottori.jp": 1,
+ "koka.shiga.jp": 1,
+ "kokonoe.oita.jp": 1,
+ "kokubunji.tokyo.jp": 1,
+ "kolobrzeg.pl": 1,
+ "komae.tokyo.jp": 1,
+ "komagane.nagano.jp": 1,
+ "komaki.aichi.jp": 1,
+ "komatsu.ishikawa.jp": 1,
+ "komatsushima.tokushima.jp": 1,
+ "komforb.se": 1,
+ "kommunalforbund.se": 1,
+ "kommune.no": 1,
+ "komono.mie.jp": 1,
+ "komoro.nagano.jp": 1,
+ "komvux.se": 1,
+ "konan.aichi.jp": 1,
+ "konan.shiga.jp": 1,
+ "kongsberg.no": 1,
+ "kongsvinger.no": 1,
+ "konin.pl": 1,
+ "konskowola.pl": 1,
+ "konsulat.gov.pl": 1,
+ "konyvelo.hu": 1,
+ "koori.fukushima.jp": 1,
+ "kopervik.no": 1,
+ "koriyama.fukushima.jp": 1,
+ "koryo.nara.jp": 1,
+ "kosai.shizuoka.jp": 1,
+ "kosaka.akita.jp": 1,
+ "kosei.shiga.jp": 1,
+ "koshigaya.saitama.jp": 1,
+ "koshimizu.hokkaido.jp": 1,
+ "koshu.yamanashi.jp": 1,
+ "kosuge.yamanashi.jp": 1,
+ "kota.aichi.jp": 1,
+ "koto.shiga.jp": 1,
+ "koto.tokyo.jp": 1,
+ "kotohira.kagawa.jp": 1,
+ "kotoura.tottori.jp": 1,
+ "kouhoku.saga.jp": 1,
+ "kounosu.saitama.jp": 1,
+ "kouyama.kagoshima.jp": 1,
+ "kouzushima.tokyo.jp": 1,
+ "koya.wakayama.jp": 1,
+ "koza.wakayama.jp": 1,
+ "kozagawa.wakayama.jp": 1,
+ "kozaki.chiba.jp": 1,
+ "kozow.com": 1,
+ "kppsp.gov.pl": 1,
+ "kr.com": 1,
+ "kr.eu.org": 1,
+ "kr.it": 1,
+ "kr.ua": 1,
+ "kraanghke.no": 1,
+ "kragero.no": 1,
+ "krager\u00f8.no": 1,
+ "krakow.pl": 1,
+ "krasnik.pl": 1,
+ "krasnodar.su": 1,
+ "kristiansand.no": 1,
+ "kristiansund.no": 1,
+ "krodsherad.no": 1,
+ "krokstadelva.no": 1,
+ "krym.ua": 1,
+ "kr\u00e5anghke.no": 1,
+ "kr\u00f8dsherad.no": 1,
+ "ks.ua": 1,
+ "ks.us": 1,
+ "kuchinotsu.nagasaki.jp": 1,
+ "kudamatsu.yamaguchi.jp": 1,
+ "kudoyama.wakayama.jp": 1,
+ "kui.hiroshima.jp": 1,
+ "kuji.iwate.jp": 1,
+ "kuju.oita.jp": 1,
+ "kujukuri.chiba.jp": 1,
+ "kuki.saitama.jp": 1,
+ "kumagaya.saitama.jp": 1,
+ "kumakogen.ehime.jp": 1,
+ "kumamoto.jp": 1,
+ "kumamoto.kumamoto.jp": 1,
+ "kumano.hiroshima.jp": 1,
+ "kumano.mie.jp": 1,
+ "kumatori.osaka.jp": 1,
+ "kumejima.okinawa.jp": 1,
+ "kumenan.okayama.jp": 1,
+ "kumiyama.kyoto.jp": 1,
+ "kunden.ortsinfo.at": 2,
+ "kunigami.okinawa.jp": 1,
+ "kunimi.fukushima.jp": 1,
+ "kunisaki.oita.jp": 1,
+ "kunitachi.tokyo.jp": 1,
+ "kunitomi.miyazaki.jp": 1,
+ "kunneppu.hokkaido.jp": 1,
+ "kunohe.iwate.jp": 1,
+ "kunst.museum": 1,
+ "kunstsammlung.museum": 1,
+ "kunstunddesign.museum": 1,
+ "kurashiki.okayama.jp": 1,
+ "kurate.fukuoka.jp": 1,
+ "kure.hiroshima.jp": 1,
+ "kurgan.su": 1,
+ "kuriyama.hokkaido.jp": 1,
+ "kurobe.toyama.jp": 1,
+ "kurogi.fukuoka.jp": 1,
+ "kuroishi.aomori.jp": 1,
+ "kuroiso.tochigi.jp": 1,
+ "kuromatsunai.hokkaido.jp": 1,
+ "kurotaki.nara.jp": 1,
+ "kurume.fukuoka.jp": 1,
+ "kusatsu.gunma.jp": 1,
+ "kusatsu.shiga.jp": 1,
+ "kushima.miyazaki.jp": 1,
+ "kushimoto.wakayama.jp": 1,
+ "kushiro.hokkaido.jp": 1,
+ "kustanai.ru": 1,
+ "kustanai.su": 1,
+ "kusu.oita.jp": 1,
+ "kutchan.hokkaido.jp": 1,
+ "kutno.pl": 1,
+ "kuwana.mie.jp": 1,
+ "kuzumaki.iwate.jp": 1,
+ "kv.ua": 1,
+ "kvafjord.no": 1,
+ "kvalsund.no": 1,
+ "kvam.no": 1,
+ "kvanangen.no": 1,
+ "kvinesdal.no": 1,
+ "kvinnherad.no": 1,
+ "kviteseid.no": 1,
+ "kvitsoy.no": 1,
+ "kvits\u00f8y.no": 1,
+ "kv\u00e6fjord.no": 1,
+ "kv\u00e6nangen.no": 1,
+ "kwp.gov.pl": 1,
+ "kwpsp.gov.pl": 1,
+ "ky.us": 1,
+ "kyiv.ua": 1,
+ "kyonan.chiba.jp": 1,
+ "kyotamba.kyoto.jp": 1,
+ "kyotanabe.kyoto.jp": 1,
+ "kyotango.kyoto.jp": 1,
+ "kyoto.jp": 1,
+ "kyowa.akita.jp": 1,
+ "kyowa.hokkaido.jp": 1,
+ "kyuragi.saga.jp": 1,
+ "k\u00e1r\u00e1\u0161johka.no": 1,
+ "k\u00e5fjord.no": 1,
+ "l-o-g-i-n.de": 1,
+ "l.bg": 1,
+ "l.se": 1,
+ "la-spezia.it": 1,
+ "la.us": 1,
+ "laakesvuemie.no": 1,
+ "lab.ms": 1,
+ "labor.museum": 1,
+ "labour.museum": 1,
+ "lahppi.no": 1,
+ "lajolla.museum": 1,
+ "lakas.hu": 1,
+ "lanbib.se": 1,
+ "lancashire.museum": 1,
+ "land-4-sale.us": 1,
+ "landes.museum": 1,
+ "landing.myjino.ru": 2,
+ "langevag.no": 1,
+ "langev\u00e5g.no": 1,
+ "lans.museum": 1,
+ "lapy.pl": 1,
+ "laquila.it": 1,
+ "lardal.no": 1,
+ "larsson.museum": 1,
+ "larvik.no": 1,
+ "laspezia.it": 1,
+ "latina.it": 1,
+ "lavagis.no": 1,
+ "lavangen.no": 1,
+ "law.pro": 1,
+ "law.za": 1,
+ "laz.it": 1,
+ "lazio.it": 1,
+ "lc.it": 1,
+ "lcl.dev": 2,
+ "lcube-server.de": 1,
+ "le.it": 1,
+ "leadpages.co": 1,
+ "leangaviika.no": 1,
+ "leasing.aero": 1,
+ "lea\u014bgaviika.no": 1,
+ "lebesby.no": 1,
+ "lebork.pl": 1,
+ "lebtimnetz.de": 1,
+ "lecce.it": 1,
+ "lecco.it": 1,
+ "leczna.pl": 1,
+ "leg.br": 1,
+ "legnica.pl": 1,
+ "leikanger.no": 1,
+ "leirfjord.no": 1,
+ "leirvik.no": 1,
+ "leitungsen.de": 1,
+ "leka.no": 1,
+ "leksvik.no": 1,
+ "lel.br": 1,
+ "lelux.site": 1,
+ "lenug.su": 1,
+ "lenvik.no": 1,
+ "lerdal.no": 1,
+ "lesja.no": 1,
+ "levanger.no": 1,
+ "lewismiller.museum": 1,
+ "lezajsk.pl": 1,
+ "lg.jp": 1,
+ "lg.ua": 1,
+ "li.it": 1,
+ "lib.ak.us": 1,
+ "lib.al.us": 1,
+ "lib.ar.us": 1,
+ "lib.as.us": 1,
+ "lib.az.us": 1,
+ "lib.ca.us": 1,
+ "lib.co.us": 1,
+ "lib.ct.us": 1,
+ "lib.dc.us": 1,
+ "lib.de.us": 1,
+ "lib.ee": 1,
+ "lib.fl.us": 1,
+ "lib.ga.us": 1,
+ "lib.gu.us": 1,
+ "lib.hi.us": 1,
+ "lib.ia.us": 1,
+ "lib.id.us": 1,
+ "lib.il.us": 1,
+ "lib.in.us": 1,
+ "lib.ks.us": 1,
+ "lib.ky.us": 1,
+ "lib.la.us": 1,
+ "lib.ma.us": 1,
+ "lib.md.us": 1,
+ "lib.me.us": 1,
+ "lib.mi.us": 1,
+ "lib.mn.us": 1,
+ "lib.mo.us": 1,
+ "lib.ms.us": 1,
+ "lib.mt.us": 1,
+ "lib.nc.us": 1,
+ "lib.nd.us": 1,
+ "lib.ne.us": 1,
+ "lib.nh.us": 1,
+ "lib.nj.us": 1,
+ "lib.nm.us": 1,
+ "lib.nv.us": 1,
+ "lib.ny.us": 1,
+ "lib.oh.us": 1,
+ "lib.ok.us": 1,
+ "lib.or.us": 1,
+ "lib.pa.us": 1,
+ "lib.pr.us": 1,
+ "lib.ri.us": 1,
+ "lib.sc.us": 1,
+ "lib.sd.us": 1,
+ "lib.tn.us": 1,
+ "lib.tx.us": 1,
+ "lib.ut.us": 1,
+ "lib.va.us": 1,
+ "lib.vi.us": 1,
+ "lib.vt.us": 1,
+ "lib.wa.us": 1,
+ "lib.wi.us": 1,
+ "lib.wy.us": 1,
+ "lier.no": 1,
+ "lierne.no": 1,
+ "lig.it": 1,
+ "liguria.it": 1,
+ "likes-pie.com": 1,
+ "likescandy.com": 1,
+ "lillehammer.no": 1,
+ "lillesand.no": 1,
+ "lima-city.at": 1,
+ "lima-city.ch": 1,
+ "lima-city.de": 1,
+ "lima-city.rocks": 1,
+ "lima.zone": 1,
+ "limanowa.pl": 1,
+ "lincoln.museum": 1,
+ "lindas.no": 1,
+ "lindesnes.no": 1,
+ "lind\u00e5s.no": 1,
+ "linkitools.space": 1,
+ "linkyard-cloud.ch": 1,
+ "linkyard.cloud": 1,
+ "linodeobjects.com": 2,
+ "linz.museum": 1,
+ "living.museum": 1,
+ "livinghistory.museum": 1,
+ "livorno.it": 1,
+ "ln.cn": 1,
+ "lo.it": 1,
+ "loabat.no": 1,
+ "loab\u00e1t.no": 1,
+ "localhistory.museum": 1,
+ "localhost.daplie.me": 1,
+ "localzone.xyz": 1,
+ "lodi.it": 1,
+ "lodingen.no": 1,
+ "log.br": 1,
+ "loginline.app": 1,
+ "loginline.dev": 1,
+ "loginline.io": 1,
+ "loginline.services": 1,
+ "loginline.site": 1,
+ "loginto.me": 1,
+ "logistics.aero": 1,
+ "logoip.com": 1,
+ "logoip.de": 1,
+ "lolipop.io": 1,
+ "lom.it": 1,
+ "lom.no": 1,
+ "lombardia.it": 1,
+ "lombardy.it": 1,
+ "lomza.pl": 1,
+ "london.cloudapps.digital": 1,
+ "london.museum": 1,
+ "londrina.br": 1,
+ "loppa.no": 1,
+ "lorenskog.no": 1,
+ "losangeles.museum": 1,
+ "loseyourip.com": 1,
+ "loten.no": 1,
+ "louvre.museum": 1,
+ "lowicz.pl": 1,
+ "loyalist.museum": 1,
+ "lpages.co": 1,
+ "lpusercontent.com": 1,
+ "lt.eu.org": 1,
+ "lt.it": 1,
+ "lt.ua": 1,
+ "ltd.co.im": 1,
+ "ltd.cy": 1,
+ "ltd.gi": 1,
+ "ltd.hk": 1,
+ "ltd.lk": 1,
+ "ltd.ng": 1,
+ "ltd.ua": 1,
+ "ltd.uk": 1,
+ "lu.eu.org": 1,
+ "lu.it": 1,
+ "lubartow.pl": 1,
+ "lubin.pl": 1,
+ "lublin.pl": 1,
+ "lucania.it": 1,
+ "lucca.it": 1,
+ "lucerne.museum": 1,
+ "lug.org.uk": 1,
+ "lugansk.ua": 1,
+ "lugs.org.uk": 1,
+ "lukow.pl": 1,
+ "lund.no": 1,
+ "lunner.no": 1,
+ "luroy.no": 1,
+ "lur\u00f8y.no": 1,
+ "luster.no": 1,
+ "lutsk.ua": 1,
+ "luxembourg.museum": 1,
+ "luzern.museum": 1,
+ "lv.eu.org": 1,
+ "lv.ua": 1,
+ "lviv.ua": 1,
+ "lyngdal.no": 1,
+ "lyngen.no": 1,
+ "lynx.mythic-beasts.com": 1,
+ "l\u00e1hppi.no": 1,
+ "l\u00e4ns.museum": 1,
+ "l\u00e6rdal.no": 1,
+ "l\u00f8dingen.no": 1,
+ "l\u00f8renskog.no": 1,
+ "l\u00f8ten.no": 1,
+ "m.bg": 1,
+ "m.se": 1,
+ "ma.gov.br": 1,
+ "ma.leg.br": 1,
+ "ma.us": 1,
+ "macapa.br": 1,
+ "maceio.br": 1,
+ "macerata.it": 1,
+ "machida.tokyo.jp": 1,
+ "mad.museum": 1,
+ "madrid.museum": 1,
+ "maebashi.gunma.jp": 1,
+ "magazine.aero": 1,
+ "magentosite.cloud": 2,
+ "maibara.shiga.jp": 1,
+ "mail.pl": 1,
+ "maintenance.aero": 1,
+ "maizuru.kyoto.jp": 1,
+ "makinohara.shizuoka.jp": 1,
+ "makurazaki.kagoshima.jp": 1,
+ "malatvuopmi.no": 1,
+ "malbork.pl": 1,
+ "mallorca.museum": 1,
+ "malopolska.pl": 1,
+ "malselv.no": 1,
+ "malvik.no": 1,
+ "mamurogawa.yamagata.jp": 1,
+ "manaus.br": 1,
+ "manchester.museum": 1,
+ "mandal.no": 1,
+ "mangyshlak.su": 1,
+ "maniwa.okayama.jp": 1,
+ "manno.kagawa.jp": 1,
+ "mansion.museum": 1,
+ "mansions.museum": 1,
+ "mantova.it": 1,
+ "manx.museum": 1,
+ "maori.nz": 1,
+ "map.fastly.net": 1,
+ "map.fastlylb.net": 1,
+ "mar.it": 1,
+ "marburg.museum": 1,
+ "marche.it": 1,
+ "marine.ru": 1,
+ "maringa.br": 1,
+ "maritime.museum": 1,
+ "maritimo.museum": 1,
+ "marker.no": 1,
+ "marnardal.no": 1,
+ "marugame.kagawa.jp": 1,
+ "marumori.miyagi.jp": 1,
+ "maryland.museum": 1,
+ "marylhurst.museum": 1,
+ "masaki.ehime.jp": 1,
+ "masfjorden.no": 1,
+ "mashike.hokkaido.jp": 1,
+ "mashiki.kumamoto.jp": 1,
+ "mashiko.tochigi.jp": 1,
+ "masoy.no": 1,
+ "massa-carrara.it": 1,
+ "massacarrara.it": 1,
+ "masuda.shimane.jp": 1,
+ "mat.br": 1,
+ "matera.it": 1,
+ "matsubara.osaka.jp": 1,
+ "matsubushi.saitama.jp": 1,
+ "matsuda.kanagawa.jp": 1,
+ "matsudo.chiba.jp": 1,
+ "matsue.shimane.jp": 1,
+ "matsukawa.nagano.jp": 1,
+ "matsumae.hokkaido.jp": 1,
+ "matsumoto.kagoshima.jp": 1,
+ "matsumoto.nagano.jp": 1,
+ "matsuno.ehime.jp": 1,
+ "matsusaka.mie.jp": 1,
+ "matsushige.tokushima.jp": 1,
+ "matsushima.miyagi.jp": 1,
+ "matsuura.nagasaki.jp": 1,
+ "matsuyama.ehime.jp": 1,
+ "matsuzaki.shizuoka.jp": 1,
+ "matta-varjjat.no": 1,
+ "mayfirst.info": 1,
+ "mayfirst.org": 1,
+ "mazowsze.pl": 1,
+ "mazury.pl": 1,
+ "mb.ca": 1,
+ "mb.it": 1,
+ "mc.ax": 1,
+ "mc.eu.org": 1,
+ "mc.it": 1,
+ "mcdir.ru": 1,
+ "mcpe.me": 1,
+ "md.ci": 1,
+ "md.us": 1,
+ "me.eu.org": 1,
+ "me.it": 1,
+ "me.ke": 1,
+ "me.so": 1,
+ "me.tc": 1,
+ "me.tz": 1,
+ "me.uk": 1,
+ "me.us": 1,
+ "me.vu": 1,
+ "med.br": 1,
+ "med.ec": 1,
+ "med.ee": 1,
+ "med.ht": 1,
+ "med.ly": 1,
+ "med.om": 1,
+ "med.pa": 1,
+ "med.pl": 1,
+ "med.pro": 1,
+ "med.sa": 1,
+ "med.sd": 1,
+ "medecin.fr": 1,
+ "medecin.km": 1,
+ "media.aero": 1,
+ "media.hu": 1,
+ "media.museum": 1,
+ "media.pl": 1,
+ "medical.museum": 1,
+ "medicina.bo": 1,
+ "medio-campidano.it": 1,
+ "mediocampidano.it": 1,
+ "medizinhistorisches.museum": 1,
+ "meeres.museum": 1,
+ "meguro.tokyo.jp": 1,
+ "mein-iserv.de": 1,
+ "mein-vigor.de": 1,
+ "meinforum.net": 1,
+ "meiwa.gunma.jp": 1,
+ "meiwa.mie.jp": 1,
+ "meland.no": 1,
+ "meldal.no": 1,
+ "melhus.no": 1,
+ "meloy.no": 1,
+ "mel\u00f8y.no": 1,
+ "members.linode.com": 1,
+ "memorial.museum": 1,
+ "memset.net": 1,
+ "meraker.no": 1,
+ "merseine.nu": 1,
+ "mer\u00e5ker.no": 1,
+ "mesaverde.museum": 1,
+ "messina.it": 1,
+ "meteorapp.com": 1,
+ "mex.com": 1,
+ "mg.gov.br": 1,
+ "mg.leg.br": 1,
+ "mi.it": 1,
+ "mi.th": 1,
+ "mi.us": 1,
+ "miasa.nagano.jp": 1,
+ "miasta.pl": 1,
+ "mibu.tochigi.jp": 1,
+ "michigan.museum": 1,
+ "microlight.aero": 1,
+ "midatlantic.museum": 1,
+ "midori.chiba.jp": 1,
+ "midori.gunma.jp": 1,
+ "midsund.no": 1,
+ "midtre-gauldal.no": 1,
+ "mie.jp": 1,
+ "mielec.pl": 1,
+ "mielno.pl": 1,
+ "mifune.kumamoto.jp": 1,
+ "mihama.aichi.jp": 1,
+ "mihama.chiba.jp": 1,
+ "mihama.fukui.jp": 1,
+ "mihama.mie.jp": 1,
+ "mihama.wakayama.jp": 1,
+ "mihara.hiroshima.jp": 1,
+ "mihara.kochi.jp": 1,
+ "miharu.fukushima.jp": 1,
+ "miho.ibaraki.jp": 1,
+ "mikasa.hokkaido.jp": 1,
+ "mikawa.yamagata.jp": 1,
+ "miki.hyogo.jp": 1,
+ "mil.ac": 1,
+ "mil.ae": 1,
+ "mil.al": 1,
+ "mil.ar": 1,
+ "mil.az": 1,
+ "mil.ba": 1,
+ "mil.bo": 1,
+ "mil.br": 1,
+ "mil.by": 1,
+ "mil.cl": 1,
+ "mil.cn": 1,
+ "mil.co": 1,
+ "mil.do": 1,
+ "mil.ec": 1,
+ "mil.eg": 1,
+ "mil.fj": 1,
+ "mil.ge": 1,
+ "mil.gh": 1,
+ "mil.gt": 1,
+ "mil.hn": 1,
+ "mil.id": 1,
+ "mil.in": 1,
+ "mil.iq": 1,
+ "mil.jo": 1,
+ "mil.kg": 1,
+ "mil.km": 1,
+ "mil.kr": 1,
+ "mil.kz": 1,
+ "mil.lv": 1,
+ "mil.mg": 1,
+ "mil.mv": 1,
+ "mil.my": 1,
+ "mil.mz": 1,
+ "mil.ng": 1,
+ "mil.ni": 1,
+ "mil.no": 1,
+ "mil.nz": 1,
+ "mil.pe": 1,
+ "mil.ph": 1,
+ "mil.pl": 1,
+ "mil.py": 1,
+ "mil.qa": 1,
+ "mil.ru": 1,
+ "mil.rw": 1,
+ "mil.sh": 1,
+ "mil.st": 1,
+ "mil.sy": 1,
+ "mil.tj": 1,
+ "mil.tm": 1,
+ "mil.to": 1,
+ "mil.tr": 1,
+ "mil.tw": 1,
+ "mil.tz": 1,
+ "mil.uy": 1,
+ "mil.vc": 1,
+ "mil.ve": 1,
+ "mil.za": 1,
+ "mil.zm": 1,
+ "mil.zw": 1,
+ "milan.it": 1,
+ "milano.it": 1,
+ "military.museum": 1,
+ "mill.museum": 1,
+ "mima.tokushima.jp": 1,
+ "mimata.miyazaki.jp": 1,
+ "minakami.gunma.jp": 1,
+ "minamata.kumamoto.jp": 1,
+ "minami-alps.yamanashi.jp": 1,
+ "minami.fukuoka.jp": 1,
+ "minami.kyoto.jp": 1,
+ "minami.tokushima.jp": 1,
+ "minamiaiki.nagano.jp": 1,
+ "minamiashigara.kanagawa.jp": 1,
+ "minamiawaji.hyogo.jp": 1,
+ "minamiboso.chiba.jp": 1,
+ "minamidaito.okinawa.jp": 1,
+ "minamiechizen.fukui.jp": 1,
+ "minamifurano.hokkaido.jp": 1,
+ "minamiise.mie.jp": 1,
+ "minamiizu.shizuoka.jp": 1,
+ "minamimaki.nagano.jp": 1,
+ "minamiminowa.nagano.jp": 1,
+ "minamioguni.kumamoto.jp": 1,
+ "minamisanriku.miyagi.jp": 1,
+ "minamitane.kagoshima.jp": 1,
+ "minamiuonuma.niigata.jp": 1,
+ "minamiyamashiro.kyoto.jp": 1,
+ "minano.saitama.jp": 1,
+ "minato.osaka.jp": 1,
+ "minato.tokyo.jp": 1,
+ "mincom.tn": 1,
+ "mine.nu": 1,
+ "miners.museum": 1,
+ "mining.museum": 1,
+ "miniserver.com": 1,
+ "minnesota.museum": 1,
+ "mino.gifu.jp": 1,
+ "minobu.yamanashi.jp": 1,
+ "minoh.osaka.jp": 1,
+ "minokamo.gifu.jp": 1,
+ "minowa.nagano.jp": 1,
+ "mintere.site": 1,
+ "mircloud.host": 1,
+ "misaki.okayama.jp": 1,
+ "misaki.osaka.jp": 1,
+ "misasa.tottori.jp": 1,
+ "misato.akita.jp": 1,
+ "misato.miyagi.jp": 1,
+ "misato.saitama.jp": 1,
+ "misato.shimane.jp": 1,
+ "misato.wakayama.jp": 1,
+ "misawa.aomori.jp": 1,
+ "misconfused.org": 1,
+ "mishima.fukushima.jp": 1,
+ "mishima.shizuoka.jp": 1,
+ "missile.museum": 1,
+ "missoula.museum": 1,
+ "misugi.mie.jp": 1,
+ "mitaka.tokyo.jp": 1,
+ "mitake.gifu.jp": 1,
+ "mitane.akita.jp": 1,
+ "mito.ibaraki.jp": 1,
+ "mitou.yamaguchi.jp": 1,
+ "mitoyo.kagawa.jp": 1,
+ "mitsue.nara.jp": 1,
+ "mitsuke.niigata.jp": 1,
+ "miura.kanagawa.jp": 1,
+ "miyada.nagano.jp": 1,
+ "miyagi.jp": 1,
+ "miyake.nara.jp": 1,
+ "miyako.fukuoka.jp": 1,
+ "miyako.iwate.jp": 1,
+ "miyakonojo.miyazaki.jp": 1,
+ "miyama.fukuoka.jp": 1,
+ "miyama.mie.jp": 1,
+ "miyashiro.saitama.jp": 1,
+ "miyawaka.fukuoka.jp": 1,
+ "miyazaki.jp": 1,
+ "miyazaki.miyazaki.jp": 1,
+ "miyazu.kyoto.jp": 1,
+ "miyoshi.aichi.jp": 1,
+ "miyoshi.hiroshima.jp": 1,
+ "miyoshi.saitama.jp": 1,
+ "miyoshi.tokushima.jp": 1,
+ "miyota.nagano.jp": 1,
+ "mizuho.tokyo.jp": 1,
+ "mizumaki.fukuoka.jp": 1,
+ "mizunami.gifu.jp": 1,
+ "mizusawa.iwate.jp": 1,
+ "mjondalen.no": 1,
+ "mj\u00f8ndalen.no": 1,
+ "mk.eu.org": 1,
+ "mk.ua": 1,
+ "mlbfan.org": 1,
+ "mm": 2,
+ "mmafan.biz": 1,
+ "mn.it": 1,
+ "mn.us": 1,
+ "mo-i-rana.no": 1,
+ "mo-siemens.io": 1,
+ "mo.cn": 1,
+ "mo.it": 1,
+ "mo.us": 1,
+ "moareke.no": 1,
+ "mobara.chiba.jp": 1,
+ "mobi.gp": 1,
+ "mobi.ke": 1,
+ "mobi.na": 1,
+ "mobi.ng": 1,
+ "mobi.tt": 1,
+ "mobi.tz": 1,
+ "mochizuki.nagano.jp": 1,
+ "mod.gi": 1,
+ "modalen.no": 1,
+ "modelling.aero": 1,
+ "modena.it": 1,
+ "modern.museum": 1,
+ "modum.no": 1,
+ "moka.tochigi.jp": 1,
+ "mol.it": 1,
+ "molde.no": 1,
+ "molise.it": 1,
+ "moma.museum": 1,
+ "mombetsu.hokkaido.jp": 1,
+ "money.museum": 1,
+ "monmouth.museum": 1,
+ "monticello.museum": 1,
+ "montreal.museum": 1,
+ "monza-brianza.it": 1,
+ "monza-e-della-brianza.it": 1,
+ "monza.it": 1,
+ "monzabrianza.it": 1,
+ "monzaebrianza.it": 1,
+ "monzaedellabrianza.it": 1,
+ "moonscale.io": 2,
+ "moonscale.net": 1,
+ "mordovia.ru": 1,
+ "mordovia.su": 1,
+ "morena.br": 1,
+ "moriguchi.osaka.jp": 1,
+ "morimachi.shizuoka.jp": 1,
+ "morioka.iwate.jp": 1,
+ "moriya.ibaraki.jp": 1,
+ "moriyama.shiga.jp": 1,
+ "moriyoshi.akita.jp": 1,
+ "morotsuka.miyazaki.jp": 1,
+ "moroyama.saitama.jp": 1,
+ "moscow.museum": 1,
+ "moseushi.hokkaido.jp": 1,
+ "mosjoen.no": 1,
+ "mosj\u00f8en.no": 1,
+ "moskenes.no": 1,
+ "moss.no": 1,
+ "mosvik.no": 1,
+ "motegi.tochigi.jp": 1,
+ "motobu.okinawa.jp": 1,
+ "motorcycle.museum": 1,
+ "motosu.gifu.jp": 1,
+ "motoyama.kochi.jp": 1,
+ "movimiento.bo": 1,
+ "mozilla-iot.org": 1,
+ "mo\u00e5reke.no": 1,
+ "mp.br": 1,
+ "mr.no": 1,
+ "mragowo.pl": 1,
+ "ms.gov.br": 1,
+ "ms.it": 1,
+ "ms.kr": 1,
+ "ms.leg.br": 1,
+ "ms.us": 1,
+ "msk.ru": 1,
+ "msk.su": 1,
+ "mt.eu.org": 1,
+ "mt.gov.br": 1,
+ "mt.it": 1,
+ "mt.leg.br": 1,
+ "mt.us": 1,
+ "muenchen.museum": 1,
+ "muenster.museum": 1,
+ "mugi.tokushima.jp": 1,
+ "muika.niigata.jp": 1,
+ "mukawa.hokkaido.jp": 1,
+ "muko.kyoto.jp": 1,
+ "mulhouse.museum": 1,
+ "munakata.fukuoka.jp": 1,
+ "muncie.museum": 1,
+ "muni.il": 1,
+ "muosat.no": 1,
+ "muos\u00e1t.no": 1,
+ "mup.gov.pl": 1,
+ "murakami.niigata.jp": 1,
+ "murata.miyagi.jp": 1,
+ "murayama.yamagata.jp": 1,
+ "murmansk.su": 1,
+ "muroran.hokkaido.jp": 1,
+ "muroto.kochi.jp": 1,
+ "mus.br": 1,
+ "mus.mi.us": 1,
+ "musashimurayama.tokyo.jp": 1,
+ "musashino.tokyo.jp": 1,
+ "museet.museum": 1,
+ "museum.mv": 1,
+ "museum.mw": 1,
+ "museum.no": 1,
+ "museum.om": 1,
+ "museum.tt": 1,
+ "museumcenter.museum": 1,
+ "museumvereniging.museum": 1,
+ "music.museum": 1,
+ "musica.ar": 1,
+ "musica.bo": 1,
+ "mutsu.aomori.jp": 1,
+ "mutsuzawa.chiba.jp": 1,
+ "mw.gov.pl": 1,
+ "mx.na": 1,
+ "my-firewall.org": 1,
+ "my-gateway.de": 1,
+ "my-router.de": 1,
+ "my-vigor.de": 1,
+ "my-wan.de": 1,
+ "my.eu.org": 1,
+ "my.id": 1,
+ "myactivedirectory.com": 1,
+ "myasustor.com": 1,
+ "mycd.eu": 1,
+ "mydatto.com": 1,
+ "mydatto.net": 1,
+ "myddns.rocks": 1,
+ "mydissent.net": 1,
+ "mydobiss.com": 1,
+ "mydrobo.com": 1,
+ "myds.me": 1,
+ "myeffect.net": 1,
+ "myfast.host": 1,
+ "myfast.space": 1,
+ "myfirewall.org": 1,
+ "myforum.community": 1,
+ "myfritz.net": 1,
+ "myftp.biz": 1,
+ "myftp.org": 1,
+ "myhome-server.de": 1,
+ "myiphost.com": 1,
+ "myjino.ru": 1,
+ "mykolaiv.ua": 1,
+ "mymailer.com.tw": 1,
+ "mymediapc.net": 1,
+ "myoko.niigata.jp": 1,
+ "mypep.link": 1,
+ "mypets.ws": 1,
+ "myphotos.cc": 1,
+ "mypi.co": 1,
+ "mypsx.net": 1,
+ "myqnapcloud.com": 1,
+ "myravendb.com": 1,
+ "mysecuritycamera.com": 1,
+ "mysecuritycamera.net": 1,
+ "mysecuritycamera.org": 1,
+ "myshopblocks.com": 1,
+ "mytis.ru": 1,
+ "mytuleap.com": 1,
+ "myvnc.com": 1,
+ "mywire.org": 1,
+ "m\u00e1latvuopmi.no": 1,
+ "m\u00e1tta-v\u00e1rjjat.no": 1,
+ "m\u00e5lselv.no": 1,
+ "m\u00e5s\u00f8y.no": 1,
+ "m\u0101ori.nz": 1,
+ "n.bg": 1,
+ "n.se": 1,
+ "n4t.co": 1,
+ "na.it": 1,
+ "na4u.ru": 1,
+ "naamesjevuemie.no": 1,
+ "nabari.mie.jp": 1,
+ "nachikatsuura.wakayama.jp": 1,
+ "nagahama.shiga.jp": 1,
+ "nagai.yamagata.jp": 1,
+ "nagano.jp": 1,
+ "nagano.nagano.jp": 1,
+ "naganohara.gunma.jp": 1,
+ "nagaoka.niigata.jp": 1,
+ "nagaokakyo.kyoto.jp": 1,
+ "nagara.chiba.jp": 1,
+ "nagareyama.chiba.jp": 1,
+ "nagasaki.jp": 1,
+ "nagasaki.nagasaki.jp": 1,
+ "nagasu.kumamoto.jp": 1,
+ "nagato.yamaguchi.jp": 1,
+ "nagatoro.saitama.jp": 1,
+ "nagawa.nagano.jp": 1,
+ "nagi.okayama.jp": 1,
+ "nagiso.nagano.jp": 1,
+ "nago.okinawa.jp": 1,
+ "nagoya.jp": 2,
+ "naha.okinawa.jp": 1,
+ "nahari.kochi.jp": 1,
+ "naie.hokkaido.jp": 1,
+ "naka.hiroshima.jp": 1,
+ "naka.ibaraki.jp": 1,
+ "nakadomari.aomori.jp": 1,
+ "nakagawa.fukuoka.jp": 1,
+ "nakagawa.hokkaido.jp": 1,
+ "nakagawa.nagano.jp": 1,
+ "nakagawa.tokushima.jp": 1,
+ "nakagusuku.okinawa.jp": 1,
+ "nakagyo.kyoto.jp": 1,
+ "nakai.kanagawa.jp": 1,
+ "nakama.fukuoka.jp": 1,
+ "nakamichi.yamanashi.jp": 1,
+ "nakamura.kochi.jp": 1,
+ "nakaniikawa.toyama.jp": 1,
+ "nakano.nagano.jp": 1,
+ "nakano.tokyo.jp": 1,
+ "nakanojo.gunma.jp": 1,
+ "nakanoto.ishikawa.jp": 1,
+ "nakasatsunai.hokkaido.jp": 1,
+ "nakatane.kagoshima.jp": 1,
+ "nakatombetsu.hokkaido.jp": 1,
+ "nakatsugawa.gifu.jp": 1,
+ "nakayama.yamagata.jp": 1,
+ "nakijin.okinawa.jp": 1,
+ "naklo.pl": 1,
+ "nalchik.ru": 1,
+ "nalchik.su": 1,
+ "namdalseid.no": 1,
+ "name.az": 1,
+ "name.cy": 1,
+ "name.eg": 1,
+ "name.et": 1,
+ "name.fj": 1,
+ "name.hr": 1,
+ "name.jo": 1,
+ "name.mk": 1,
+ "name.mv": 1,
+ "name.my": 1,
+ "name.na": 1,
+ "name.ng": 1,
+ "name.pr": 1,
+ "name.qa": 1,
+ "name.tj": 1,
+ "name.tr": 1,
+ "name.tt": 1,
+ "name.vn": 1,
+ "namegata.ibaraki.jp": 1,
+ "namegawa.saitama.jp": 1,
+ "namerikawa.toyama.jp": 1,
+ "namie.fukushima.jp": 1,
+ "namikata.ehime.jp": 1,
+ "namsos.no": 1,
+ "namsskogan.no": 1,
+ "nanae.hokkaido.jp": 1,
+ "nanao.ishikawa.jp": 1,
+ "nanbu.tottori.jp": 1,
+ "nanbu.yamanashi.jp": 1,
+ "nango.fukushima.jp": 1,
+ "nanjo.okinawa.jp": 1,
+ "nankoku.kochi.jp": 1,
+ "nanmoku.gunma.jp": 1,
+ "nannestad.no": 1,
+ "nanporo.hokkaido.jp": 1,
+ "nantan.kyoto.jp": 1,
+ "nanto.toyama.jp": 1,
+ "nanyo.yamagata.jp": 1,
+ "naoshima.kagawa.jp": 1,
+ "naples.it": 1,
+ "napoli.it": 1,
+ "nara.jp": 1,
+ "nara.nara.jp": 1,
+ "narashino.chiba.jp": 1,
+ "narita.chiba.jp": 1,
+ "naroy.no": 1,
+ "narusawa.yamanashi.jp": 1,
+ "naruto.tokushima.jp": 1,
+ "narviika.no": 1,
+ "narvik.no": 1,
+ "nasu.tochigi.jp": 1,
+ "nasushiobara.tochigi.jp": 1,
+ "nat.tn": 1,
+ "natal.br": 1,
+ "national.museum": 1,
+ "nationalfirearms.museum": 1,
+ "nationalheritage.museum": 1,
+ "nativeamerican.museum": 1,
+ "natori.miyagi.jp": 1,
+ "natural.bo": 1,
+ "naturalhistory.museum": 1,
+ "naturalhistorymuseum.museum": 1,
+ "naturalsciences.museum": 1,
+ "naturbruksgymn.se": 1,
+ "nature.museum": 1,
+ "naturhistorisches.museum": 1,
+ "natuurwetenschappen.museum": 1,
+ "naumburg.museum": 1,
+ "naustdal.no": 1,
+ "naval.museum": 1,
+ "navigation.aero": 1,
+ "navoi.su": 1,
+ "navuotna.no": 1,
+ "nayoro.hokkaido.jp": 1,
+ "nb.ca": 1,
+ "nc.tr": 1,
+ "nc.us": 1,
+ "nctu.me": 1,
+ "nd.us": 1,
+ "ne.jp": 1,
+ "ne.ke": 1,
+ "ne.kr": 1,
+ "ne.pw": 1,
+ "ne.tz": 1,
+ "ne.ug": 1,
+ "ne.us": 1,
+ "neat-url.com": 1,
+ "nebraska.museum": 1,
+ "nedre-eiker.no": 1,
+ "neko.am": 1,
+ "nemuro.hokkaido.jp": 1,
+ "nerdpol.ovh": 1,
+ "nerima.tokyo.jp": 1,
+ "nes.akershus.no": 1,
+ "nes.buskerud.no": 1,
+ "nesna.no": 1,
+ "nesodden.no": 1,
+ "nesoddtangen.no": 1,
+ "nesseby.no": 1,
+ "nesset.no": 1,
+ "net-freaks.com": 1,
+ "net.ac": 1,
+ "net.ae": 1,
+ "net.af": 1,
+ "net.ag": 1,
+ "net.ai": 1,
+ "net.al": 1,
+ "net.am": 1,
+ "net.ar": 1,
+ "net.au": 1,
+ "net.az": 1,
+ "net.ba": 1,
+ "net.bb": 1,
+ "net.bh": 1,
+ "net.bm": 1,
+ "net.bn": 1,
+ "net.bo": 1,
+ "net.br": 1,
+ "net.bs": 1,
+ "net.bt": 1,
+ "net.bz": 1,
+ "net.ci": 1,
+ "net.cm": 1,
+ "net.cn": 1,
+ "net.co": 1,
+ "net.cu": 1,
+ "net.cw": 1,
+ "net.cy": 1,
+ "net.dm": 1,
+ "net.do": 1,
+ "net.dz": 1,
+ "net.ec": 1,
+ "net.eg": 1,
+ "net.et": 1,
+ "net.eu.org": 1,
+ "net.fj": 1,
+ "net.fm": 1,
+ "net.ge": 1,
+ "net.gg": 1,
+ "net.gl": 1,
+ "net.gn": 1,
+ "net.gp": 1,
+ "net.gr": 1,
+ "net.gt": 1,
+ "net.gu": 1,
+ "net.gy": 1,
+ "net.hk": 1,
+ "net.hn": 1,
+ "net.ht": 1,
+ "net.id": 1,
+ "net.il": 1,
+ "net.im": 1,
+ "net.in": 1,
+ "net.iq": 1,
+ "net.ir": 1,
+ "net.is": 1,
+ "net.je": 1,
+ "net.jo": 1,
+ "net.kg": 1,
+ "net.ki": 1,
+ "net.kn": 1,
+ "net.kw": 1,
+ "net.ky": 1,
+ "net.kz": 1,
+ "net.la": 1,
+ "net.lb": 1,
+ "net.lc": 1,
+ "net.lk": 1,
+ "net.lr": 1,
+ "net.ls": 1,
+ "net.lv": 1,
+ "net.ly": 1,
+ "net.ma": 1,
+ "net.me": 1,
+ "net.mk": 1,
+ "net.ml": 1,
+ "net.mo": 1,
+ "net.ms": 1,
+ "net.mt": 1,
+ "net.mu": 1,
+ "net.mv": 1,
+ "net.mw": 1,
+ "net.mx": 1,
+ "net.my": 1,
+ "net.mz": 1,
+ "net.nf": 1,
+ "net.ng": 1,
+ "net.ni": 1,
+ "net.nr": 1,
+ "net.nz": 1,
+ "net.om": 1,
+ "net.pa": 1,
+ "net.pe": 1,
+ "net.ph": 1,
+ "net.pk": 1,
+ "net.pl": 1,
+ "net.pn": 1,
+ "net.pr": 1,
+ "net.ps": 1,
+ "net.pt": 1,
+ "net.py": 1,
+ "net.qa": 1,
+ "net.ru": 1,
+ "net.rw": 1,
+ "net.sa": 1,
+ "net.sb": 1,
+ "net.sc": 1,
+ "net.sd": 1,
+ "net.sg": 1,
+ "net.sh": 1,
+ "net.sl": 1,
+ "net.so": 1,
+ "net.ss": 1,
+ "net.st": 1,
+ "net.sy": 1,
+ "net.th": 1,
+ "net.tj": 1,
+ "net.tm": 1,
+ "net.tn": 1,
+ "net.to": 1,
+ "net.tr": 1,
+ "net.tt": 1,
+ "net.tw": 1,
+ "net.ua": 1,
+ "net.uk": 1,
+ "net.uy": 1,
+ "net.uz": 1,
+ "net.vc": 1,
+ "net.ve": 1,
+ "net.vi": 1,
+ "net.vn": 1,
+ "net.vu": 1,
+ "net.ws": 1,
+ "net.za": 1,
+ "net.zm": 1,
+ "netlify.app": 1,
+ "neues.museum": 1,
+ "newhampshire.museum": 1,
+ "newjersey.museum": 1,
+ "newmexico.museum": 1,
+ "newport.museum": 1,
+ "news.hu": 1,
+ "newspaper.museum": 1,
+ "newyork.museum": 1,
+ "neyagawa.osaka.jp": 1,
+ "nf.ca": 1,
+ "nflfan.org": 1,
+ "nfshost.com": 1,
+ "ng.city": 1,
+ "ng.eu.org": 1,
+ "ng.ink": 1,
+ "ng.school": 1,
+ "ngo.lk": 1,
+ "ngo.ng": 1,
+ "ngo.ph": 1,
+ "ngo.za": 1,
+ "ngrok.io": 1,
+ "nh-serv.co.uk": 1,
+ "nh.us": 1,
+ "nhlfan.net": 1,
+ "nhs.uk": 1,
+ "nic.in": 1,
+ "nic.tj": 1,
+ "nic.za": 1,
+ "nichinan.miyazaki.jp": 1,
+ "nichinan.tottori.jp": 1,
+ "nid.io": 1,
+ "niepce.museum": 1,
+ "nieruchomosci.pl": 1,
+ "niigata.jp": 1,
+ "niigata.niigata.jp": 1,
+ "niihama.ehime.jp": 1,
+ "niikappu.hokkaido.jp": 1,
+ "niimi.okayama.jp": 1,
+ "niiza.saitama.jp": 1,
+ "nikaho.akita.jp": 1,
+ "niki.hokkaido.jp": 1,
+ "nikko.tochigi.jp": 1,
+ "nikolaev.ua": 1,
+ "ninohe.iwate.jp": 1,
+ "ninomiya.kanagawa.jp": 1,
+ "nirasaki.yamanashi.jp": 1,
+ "nis.za": 1,
+ "nishi.fukuoka.jp": 1,
+ "nishi.osaka.jp": 1,
+ "nishiaizu.fukushima.jp": 1,
+ "nishiarita.saga.jp": 1,
+ "nishiawakura.okayama.jp": 1,
+ "nishiazai.shiga.jp": 1,
+ "nishigo.fukushima.jp": 1,
+ "nishihara.kumamoto.jp": 1,
+ "nishihara.okinawa.jp": 1,
+ "nishiizu.shizuoka.jp": 1,
+ "nishikata.tochigi.jp": 1,
+ "nishikatsura.yamanashi.jp": 1,
+ "nishikawa.yamagata.jp": 1,
+ "nishimera.miyazaki.jp": 1,
+ "nishinomiya.hyogo.jp": 1,
+ "nishinoomote.kagoshima.jp": 1,
+ "nishinoshima.shimane.jp": 1,
+ "nishio.aichi.jp": 1,
+ "nishiokoppe.hokkaido.jp": 1,
+ "nishitosa.kochi.jp": 1,
+ "nishiwaki.hyogo.jp": 1,
+ "nissedal.no": 1,
+ "nisshin.aichi.jp": 1,
+ "niteroi.br": 1,
+ "nittedal.no": 1,
+ "niyodogawa.kochi.jp": 1,
+ "nj.us": 1,
+ "nl.ca": 1,
+ "nl.ci": 1,
+ "nl.eu.org": 1,
+ "nl.no": 1,
+ "nm.cn": 1,
+ "nm.us": 1,
+ "no-ip.biz": 1,
+ "no-ip.ca": 1,
+ "no-ip.co.uk": 1,
+ "no-ip.info": 1,
+ "no-ip.net": 1,
+ "no-ip.org": 1,
+ "no.com": 1,
+ "no.eu.org": 1,
+ "no.it": 1,
+ "nobeoka.miyazaki.jp": 1,
+ "noboribetsu.hokkaido.jp": 1,
+ "noda.chiba.jp": 1,
+ "noda.iwate.jp": 1,
+ "nodebalancer.linode.com": 2,
+ "nodum.co": 1,
+ "nodum.io": 1,
+ "nogata.fukuoka.jp": 1,
+ "nogi.tochigi.jp": 1,
+ "noheji.aomori.jp": 1,
+ "noho.st": 1,
+ "nohost.me": 1,
+ "noip.me": 1,
+ "noip.us": 1,
+ "nom.ad": 1,
+ "nom.ae": 1,
+ "nom.af": 1,
+ "nom.ag": 1,
+ "nom.ai": 1,
+ "nom.al": 1,
+ "nom.br": 2,
+ "nom.bz": 1,
+ "nom.cl": 1,
+ "nom.co": 1,
+ "nom.es": 1,
+ "nom.fr": 1,
+ "nom.gd": 1,
+ "nom.ge": 1,
+ "nom.gl": 1,
+ "nom.gt": 1,
+ "nom.hn": 1,
+ "nom.im": 1,
+ "nom.ke": 1,
+ "nom.km": 1,
+ "nom.li": 1,
+ "nom.lv": 1,
+ "nom.mg": 1,
+ "nom.mk": 1,
+ "nom.nc": 1,
+ "nom.ni": 1,
+ "nom.nu": 1,
+ "nom.pa": 1,
+ "nom.pe": 1,
+ "nom.pl": 1,
+ "nom.pw": 1,
+ "nom.qa": 1,
+ "nom.re": 1,
+ "nom.ro": 1,
+ "nom.rs": 1,
+ "nom.si": 1,
+ "nom.st": 1,
+ "nom.tj": 1,
+ "nom.tm": 1,
+ "nom.ug": 1,
+ "nom.uy": 1,
+ "nom.vc": 1,
+ "nom.vg": 1,
+ "nom.za": 1,
+ "nombre.bo": 1,
+ "nome.pt": 1,
+ "nomi.ishikawa.jp": 1,
+ "nonoichi.ishikawa.jp": 1,
+ "nord-aurdal.no": 1,
+ "nord-fron.no": 1,
+ "nord-odal.no": 1,
+ "norddal.no": 1,
+ "nordkapp.no": 1,
+ "nordre-land.no": 1,
+ "nordreisa.no": 1,
+ "nore-og-uvdal.no": 1,
+ "norfolk.museum": 1,
+ "north-kazakhstan.su": 1,
+ "north.museum": 1,
+ "nose.osaka.jp": 1,
+ "nosegawa.nara.jp": 1,
+ "noshiro.akita.jp": 1,
+ "not.br": 1,
+ "notaires.fr": 1,
+ "notaires.km": 1,
+ "noticias.bo": 1,
+ "noto.ishikawa.jp": 1,
+ "notodden.no": 1,
+ "notogawa.shiga.jp": 1,
+ "notteroy.no": 1,
+ "nov.ru": 1,
+ "nov.su": 1,
+ "novara.it": 1,
+ "now-dns.net": 1,
+ "now-dns.org": 1,
+ "now-dns.top": 1,
+ "now.sh": 1,
+ "nowaruda.pl": 1,
+ "nozawaonsen.nagano.jp": 1,
+ "np": 2,
+ "nrw.museum": 1,
+ "ns.ca": 1,
+ "nsn.us": 1,
+ "nsupdate.info": 1,
+ "nsw.au": 1,
+ "nsw.edu.au": 1,
+ "nt.au": 1,
+ "nt.ca": 1,
+ "nt.edu.au": 1,
+ "nt.no": 1,
+ "nt.ro": 1,
+ "ntdll.top": 1,
+ "ntr.br": 1,
+ "nu.ca": 1,
+ "nu.it": 1,
+ "numata.gunma.jp": 1,
+ "numata.hokkaido.jp": 1,
+ "numazu.shizuoka.jp": 1,
+ "nuoro.it": 1,
+ "nv.us": 1,
+ "nx.cn": 1,
+ "ny.us": 1,
+ "nyaa.am": 1,
+ "nyan.to": 1,
+ "nyc.mn": 1,
+ "nyc.museum": 1,
+ "nym.by": 1,
+ "nym.bz": 1,
+ "nym.ec": 1,
+ "nym.gr": 1,
+ "nym.gy": 1,
+ "nym.hk": 1,
+ "nym.ie": 1,
+ "nym.kz": 1,
+ "nym.la": 1,
+ "nym.lc": 1,
+ "nym.li": 1,
+ "nym.lt": 1,
+ "nym.lu": 1,
+ "nym.me": 1,
+ "nym.mn": 1,
+ "nym.mx": 1,
+ "nym.nz": 1,
+ "nym.pe": 1,
+ "nym.pt": 1,
+ "nym.ro": 1,
+ "nym.sk": 1,
+ "nym.su": 1,
+ "nym.sx": 1,
+ "nym.tw": 1,
+ "nyny.museum": 1,
+ "nysa.pl": 1,
+ "nyuzen.toyama.jp": 1,
+ "nz.basketball": 1,
+ "nz.eu.org": 1,
+ "n\u00e1vuotna.no": 1,
+ "n\u00e5\u00e5mesjevuemie.no": 1,
+ "n\u00e6r\u00f8y.no": 1,
+ "n\u00f8tter\u00f8y.no": 1,
+ "o.bg": 1,
+ "o.se": 1,
+ "oamishirasato.chiba.jp": 1,
+ "oarai.ibaraki.jp": 1,
+ "obama.fukui.jp": 1,
+ "obama.nagasaki.jp": 1,
+ "obanazawa.yamagata.jp": 1,
+ "obihiro.hokkaido.jp": 1,
+ "obira.hokkaido.jp": 1,
+ "obninsk.su": 1,
+ "obu.aichi.jp": 1,
+ "obuse.nagano.jp": 1,
+ "oceanographic.museum": 1,
+ "oceanographique.museum": 1,
+ "ocelot.mythic-beasts.com": 1,
+ "ochi.kochi.jp": 1,
+ "oci.customer-oci.com": 2,
+ "ocp.customer-oci.com": 2,
+ "ocs.customer-oci.com": 2,
+ "od.ua": 1,
+ "odate.akita.jp": 1,
+ "odawara.kanagawa.jp": 1,
+ "odda.no": 1,
+ "odesa.ua": 1,
+ "odessa.ua": 1,
+ "odo.br": 1,
+ "oe.yamagata.jp": 1,
+ "of.by": 1,
+ "of.fashion": 1,
+ "of.football": 1,
+ "of.london": 1,
+ "of.no": 1,
+ "of.work": 1,
+ "off.ai": 1,
+ "office-on-the.net": 1,
+ "official.academy": 1,
+ "ofunato.iwate.jp": 1,
+ "og.ao": 1,
+ "og.it": 1,
+ "oga.akita.jp": 1,
+ "ogaki.gifu.jp": 1,
+ "ogano.saitama.jp": 1,
+ "ogasawara.tokyo.jp": 1,
+ "ogata.akita.jp": 1,
+ "ogawa.ibaraki.jp": 1,
+ "ogawa.nagano.jp": 1,
+ "ogawa.saitama.jp": 1,
+ "ogawara.miyagi.jp": 1,
+ "ogi.saga.jp": 1,
+ "ogimi.okinawa.jp": 1,
+ "ogliastra.it": 1,
+ "ogori.fukuoka.jp": 1,
+ "ogose.saitama.jp": 1,
+ "oguchi.aichi.jp": 1,
+ "oguni.kumamoto.jp": 1,
+ "oguni.yamagata.jp": 1,
+ "oh.us": 1,
+ "oharu.aichi.jp": 1,
+ "ohda.shimane.jp": 1,
+ "ohi.fukui.jp": 1,
+ "ohira.miyagi.jp": 1,
+ "ohira.tochigi.jp": 1,
+ "ohkura.yamagata.jp": 1,
+ "ohtawara.tochigi.jp": 1,
+ "oi.kanagawa.jp": 1,
+ "oirase.aomori.jp": 1,
+ "oirm.gov.pl": 1,
+ "oishida.yamagata.jp": 1,
+ "oiso.kanagawa.jp": 1,
+ "oita.jp": 1,
+ "oita.oita.jp": 1,
+ "oizumi.gunma.jp": 1,
+ "oji.nara.jp": 1,
+ "ojiya.niigata.jp": 1,
+ "ok.us": 1,
+ "okagaki.fukuoka.jp": 1,
+ "okawa.fukuoka.jp": 1,
+ "okawa.kochi.jp": 1,
+ "okaya.nagano.jp": 1,
+ "okayama.jp": 1,
+ "okayama.okayama.jp": 1,
+ "okazaki.aichi.jp": 1,
+ "okegawa.saitama.jp": 1,
+ "oketo.hokkaido.jp": 1,
+ "oki.fukuoka.jp": 1,
+ "okinawa.jp": 1,
+ "okinawa.okinawa.jp": 1,
+ "okinoshima.shimane.jp": 1,
+ "okoppe.hokkaido.jp": 1,
+ "oksnes.no": 1,
+ "okuizumo.shimane.jp": 1,
+ "okuma.fukushima.jp": 1,
+ "okutama.tokyo.jp": 1,
+ "ol.no": 1,
+ "olawa.pl": 1,
+ "olbia-tempio.it": 1,
+ "olbiatempio.it": 1,
+ "olecko.pl": 1,
+ "olkusz.pl": 1,
+ "olsztyn.pl": 1,
+ "omachi.nagano.jp": 1,
+ "omachi.saga.jp": 1,
+ "omaezaki.shizuoka.jp": 1,
+ "omaha.museum": 1,
+ "omasvuotna.no": 1,
+ "ome.tokyo.jp": 1,
+ "omg.lol": 1,
+ "omi.nagano.jp": 1,
+ "omi.niigata.jp": 1,
+ "omigawa.chiba.jp": 1,
+ "omihachiman.shiga.jp": 1,
+ "omitama.ibaraki.jp": 1,
+ "omiya.saitama.jp": 1,
+ "omniwe.site": 1,
+ "omotego.fukushima.jp": 1,
+ "omura.nagasaki.jp": 1,
+ "omuta.fukuoka.jp": 1,
+ "on-aptible.com": 1,
+ "on-k3s.io": 2,
+ "on-rancher.cloud": 2,
+ "on-rio.io": 2,
+ "on-the-web.tv": 1,
+ "on-web.fr": 1,
+ "on.ca": 1,
+ "on.fashion": 1,
+ "onagawa.miyagi.jp": 1,
+ "onfabrica.com": 1,
+ "ong.br": 1,
+ "onga.fukuoka.jp": 1,
+ "onjuku.chiba.jp": 1,
+ "online.museum": 1,
+ "online.th": 1,
+ "onna.okinawa.jp": 1,
+ "ono.fukui.jp": 1,
+ "ono.fukushima.jp": 1,
+ "ono.hyogo.jp": 1,
+ "onojo.fukuoka.jp": 1,
+ "onomichi.hiroshima.jp": 1,
+ "onred.one": 1,
+ "onrender.com": 1,
+ "ontario.museum": 1,
+ "onthewifi.com": 1,
+ "onza.mythic-beasts.com": 1,
+ "ooguy.com": 1,
+ "ookuwa.nagano.jp": 1,
+ "ooshika.nagano.jp": 1,
+ "openair.museum": 1,
+ "opencraft.hosting": 1,
+ "opensocial.site": 1,
+ "operaunite.com": 1,
+ "opoczno.pl": 1,
+ "opole.pl": 1,
+ "oppdal.no": 1,
+ "oppegard.no": 1,
+ "oppeg\u00e5rd.no": 1,
+ "or.at": 1,
+ "or.bi": 1,
+ "or.ci": 1,
+ "or.cr": 1,
+ "or.id": 1,
+ "or.it": 1,
+ "or.jp": 1,
+ "or.ke": 1,
+ "or.kr": 1,
+ "or.mu": 1,
+ "or.na": 1,
+ "or.pw": 1,
+ "or.th": 1,
+ "or.tz": 1,
+ "or.ug": 1,
+ "or.us": 1,
+ "ora.gunma.jp": 1,
+ "oregon.museum": 1,
+ "oregontrail.museum": 1,
+ "org.ac": 1,
+ "org.ae": 1,
+ "org.af": 1,
+ "org.ag": 1,
+ "org.ai": 1,
+ "org.al": 1,
+ "org.am": 1,
+ "org.ar": 1,
+ "org.au": 1,
+ "org.az": 1,
+ "org.ba": 1,
+ "org.bb": 1,
+ "org.bh": 1,
+ "org.bi": 1,
+ "org.bm": 1,
+ "org.bn": 1,
+ "org.bo": 1,
+ "org.br": 1,
+ "org.bs": 1,
+ "org.bt": 1,
+ "org.bw": 1,
+ "org.bz": 1,
+ "org.ci": 1,
+ "org.cn": 1,
+ "org.co": 1,
+ "org.cu": 1,
+ "org.cw": 1,
+ "org.cy": 1,
+ "org.dm": 1,
+ "org.do": 1,
+ "org.dz": 1,
+ "org.ec": 1,
+ "org.ee": 1,
+ "org.eg": 1,
+ "org.es": 1,
+ "org.et": 1,
+ "org.fj": 1,
+ "org.fm": 1,
+ "org.ge": 1,
+ "org.gg": 1,
+ "org.gh": 1,
+ "org.gi": 1,
+ "org.gl": 1,
+ "org.gn": 1,
+ "org.gp": 1,
+ "org.gr": 1,
+ "org.gt": 1,
+ "org.gu": 1,
+ "org.gy": 1,
+ "org.hk": 1,
+ "org.hn": 1,
+ "org.ht": 1,
+ "org.hu": 1,
+ "org.il": 1,
+ "org.im": 1,
+ "org.in": 1,
+ "org.iq": 1,
+ "org.ir": 1,
+ "org.is": 1,
+ "org.je": 1,
+ "org.jo": 1,
+ "org.kg": 1,
+ "org.ki": 1,
+ "org.km": 1,
+ "org.kn": 1,
+ "org.kp": 1,
+ "org.kw": 1,
+ "org.ky": 1,
+ "org.kz": 1,
+ "org.la": 1,
+ "org.lb": 1,
+ "org.lc": 1,
+ "org.lk": 1,
+ "org.lr": 1,
+ "org.ls": 1,
+ "org.lv": 1,
+ "org.ly": 1,
+ "org.ma": 1,
+ "org.me": 1,
+ "org.mg": 1,
+ "org.mk": 1,
+ "org.ml": 1,
+ "org.mn": 1,
+ "org.mo": 1,
+ "org.ms": 1,
+ "org.mt": 1,
+ "org.mu": 1,
+ "org.mv": 1,
+ "org.mw": 1,
+ "org.mx": 1,
+ "org.my": 1,
+ "org.mz": 1,
+ "org.na": 1,
+ "org.ng": 1,
+ "org.ni": 1,
+ "org.nr": 1,
+ "org.nz": 1,
+ "org.om": 1,
+ "org.pa": 1,
+ "org.pe": 1,
+ "org.pf": 1,
+ "org.ph": 1,
+ "org.pk": 1,
+ "org.pl": 1,
+ "org.pn": 1,
+ "org.pr": 1,
+ "org.ps": 1,
+ "org.pt": 1,
+ "org.py": 1,
+ "org.qa": 1,
+ "org.ro": 1,
+ "org.rs": 1,
+ "org.ru": 1,
+ "org.rw": 1,
+ "org.sa": 1,
+ "org.sb": 1,
+ "org.sc": 1,
+ "org.sd": 1,
+ "org.se": 1,
+ "org.sg": 1,
+ "org.sh": 1,
+ "org.sl": 1,
+ "org.sn": 1,
+ "org.so": 1,
+ "org.ss": 1,
+ "org.st": 1,
+ "org.sv": 1,
+ "org.sy": 1,
+ "org.sz": 1,
+ "org.tj": 1,
+ "org.tm": 1,
+ "org.tn": 1,
+ "org.to": 1,
+ "org.tr": 1,
+ "org.tt": 1,
+ "org.tw": 1,
+ "org.ua": 1,
+ "org.ug": 1,
+ "org.uk": 1,
+ "org.uy": 1,
+ "org.uz": 1,
+ "org.vc": 1,
+ "org.ve": 1,
+ "org.vi": 1,
+ "org.vn": 1,
+ "org.vu": 1,
+ "org.ws": 1,
+ "org.za": 1,
+ "org.zm": 1,
+ "org.zw": 1,
+ "oristano.it": 1,
+ "orkanger.no": 1,
+ "orkdal.no": 1,
+ "orland.no": 1,
+ "orskog.no": 1,
+ "orsta.no": 1,
+ "orx.biz": 1,
+ "os.hedmark.no": 1,
+ "os.hordaland.no": 1,
+ "osaka.jp": 1,
+ "osakasayama.osaka.jp": 1,
+ "osaki.miyagi.jp": 1,
+ "osakikamijima.hiroshima.jp": 1,
+ "osasco.br": 1,
+ "osen.no": 1,
+ "oseto.nagasaki.jp": 1,
+ "oshima.tokyo.jp": 1,
+ "oshima.yamaguchi.jp": 1,
+ "oshino.yamanashi.jp": 1,
+ "oshu.iwate.jp": 1,
+ "oslo.no": 1,
+ "osoyro.no": 1,
+ "osteroy.no": 1,
+ "oster\u00f8y.no": 1,
+ "ostre-toten.no": 1,
+ "ostroda.pl": 1,
+ "ostroleka.pl": 1,
+ "ostrowiec.pl": 1,
+ "ostrowwlkp.pl": 1,
+ "os\u00f8yro.no": 1,
+ "ot.it": 1,
+ "ota.gunma.jp": 1,
+ "ota.tokyo.jp": 1,
+ "otago.museum": 1,
+ "otake.hiroshima.jp": 1,
+ "otaki.chiba.jp": 1,
+ "otaki.nagano.jp": 1,
+ "otaki.saitama.jp": 1,
+ "otama.fukushima.jp": 1,
+ "otap.co": 2,
+ "otari.nagano.jp": 1,
+ "otaru.hokkaido.jp": 1,
+ "other.nf": 1,
+ "oto.fukuoka.jp": 1,
+ "otobe.hokkaido.jp": 1,
+ "otofuke.hokkaido.jp": 1,
+ "otoineppu.hokkaido.jp": 1,
+ "otoyo.kochi.jp": 1,
+ "otsu.shiga.jp": 1,
+ "otsuchi.iwate.jp": 1,
+ "otsuki.kochi.jp": 1,
+ "otsuki.yamanashi.jp": 1,
+ "ouchi.saga.jp": 1,
+ "ouda.nara.jp": 1,
+ "oum.gov.pl": 1,
+ "oumu.hokkaido.jp": 1,
+ "outsystemscloud.com": 1,
+ "overhalla.no": 1,
+ "ovre-eiker.no": 1,
+ "owani.aomori.jp": 1,
+ "owariasahi.aichi.jp": 1,
+ "own.pm": 1,
+ "ownip.net": 1,
+ "ownprovider.com": 1,
+ "owo.codes": 2,
+ "ox.rs": 1,
+ "oxford.museum": 1,
+ "oy.lc": 1,
+ "oya.to": 1,
+ "oyabe.toyama.jp": 1,
+ "oyama.tochigi.jp": 1,
+ "oyamazaki.kyoto.jp": 1,
+ "oyer.no": 1,
+ "oygarden.no": 1,
+ "oyodo.nara.jp": 1,
+ "oystre-slidre.no": 1,
+ "oz.au": 1,
+ "ozora.hokkaido.jp": 1,
+ "ozu.ehime.jp": 1,
+ "ozu.kumamoto.jp": 1,
+ "p.bg": 1,
+ "p.se": 1,
+ "pa.gov.br": 1,
+ "pa.gov.pl": 1,
+ "pa.it": 1,
+ "pa.leg.br": 1,
+ "pa.us": 1,
+ "paas.datacenter.fi": 1,
+ "paas.massivegrid.com": 1,
+ "pacific.museum": 1,
+ "paderborn.museum": 1,
+ "padova.it": 1,
+ "padua.it": 1,
+ "pagefrontapp.com": 1,
+ "pages.dev": 1,
+ "pages.wiardweb.com": 1,
+ "pagespeedmobilizer.com": 1,
+ "pagexl.com": 1,
+ "palace.museum": 1,
+ "paleo.museum": 1,
+ "palermo.it": 1,
+ "palmas.br": 1,
+ "palmsprings.museum": 1,
+ "panama.museum": 1,
+ "panel.gg": 1,
+ "pantheonsite.io": 1,
+ "parachuting.aero": 1,
+ "paragliding.aero": 1,
+ "paris.eu.org": 1,
+ "paris.museum": 1,
+ "parliament.cy": 1,
+ "parliament.nz": 1,
+ "parma.it": 1,
+ "paroch.k12.ma.us": 1,
+ "parti.se": 1,
+ "pasadena.museum": 1,
+ "passenger-association.aero": 1,
+ "patria.bo": 1,
+ "pavia.it": 1,
+ "pb.ao": 1,
+ "pb.gov.br": 1,
+ "pb.leg.br": 1,
+ "pc.it": 1,
+ "pc.pl": 1,
+ "pcloud.host": 1,
+ "pd.it": 1,
+ "pdns.page": 1,
+ "pe.ca": 1,
+ "pe.gov.br": 1,
+ "pe.it": 1,
+ "pe.kr": 1,
+ "pe.leg.br": 1,
+ "penza.su": 1,
+ "per.la": 1,
+ "per.nf": 1,
+ "per.sg": 1,
+ "perso.ht": 1,
+ "perso.sn": 1,
+ "perso.tn": 1,
+ "perspecta.cloud": 1,
+ "perugia.it": 1,
+ "pesaro-urbino.it": 1,
+ "pesarourbino.it": 1,
+ "pescara.it": 1,
+ "pg": 2,
+ "pg.it": 1,
+ "pgafan.net": 1,
+ "pgfog.com": 1,
+ "pharmacien.fr": 1,
+ "pharmaciens.km": 1,
+ "pharmacy.museum": 1,
+ "philadelphia.museum": 1,
+ "philadelphiaarea.museum": 1,
+ "philately.museum": 1,
+ "phoenix.museum": 1,
+ "photography.museum": 1,
+ "pi.gov.br": 1,
+ "pi.it": 1,
+ "pi.leg.br": 1,
+ "piacenza.it": 1,
+ "piedmont.it": 1,
+ "piemonte.it": 1,
+ "pila.pl": 1,
+ "pilot.aero": 1,
+ "pilots.museum": 1,
+ "pimienta.org": 1,
+ "pinb.gov.pl": 1,
+ "pippu.hokkaido.jp": 1,
+ "pisa.it": 1,
+ "pistoia.it": 1,
+ "pisz.pl": 1,
+ "pittsburgh.museum": 1,
+ "piw.gov.pl": 1,
+ "pixolino.com": 1,
+ "pl.eu.org": 1,
+ "pl.ua": 1,
+ "planetarium.museum": 1,
+ "plantation.museum": 1,
+ "plants.museum": 1,
+ "platform0.app": 1,
+ "platformsh.site": 2,
+ "platter-app.com": 1,
+ "platter-app.dev": 1,
+ "platterp.us": 1,
+ "playstation-cloud.com": 1,
+ "plaza.museum": 1,
+ "plc.co.im": 1,
+ "plc.ly": 1,
+ "plc.uk": 1,
+ "plesk.page": 1,
+ "pleskns.com": 1,
+ "plo.ps": 1,
+ "plurinacional.bo": 1,
+ "pmn.it": 1,
+ "pn.it": 1,
+ "po.gov.pl": 1,
+ "po.it": 1,
+ "poa.br": 1,
+ "podhale.pl": 1,
+ "podlasie.pl": 1,
+ "podzone.net": 1,
+ "podzone.org": 1,
+ "point2this.com": 1,
+ "pointto.us": 1,
+ "poivron.org": 1,
+ "pokrovsk.su": 1,
+ "pol.dz": 1,
+ "pol.ht": 1,
+ "pol.tr": 1,
+ "police.uk": 1,
+ "politica.bo": 1,
+ "polkowice.pl": 1,
+ "poltava.ua": 1,
+ "pomorskie.pl": 1,
+ "pomorze.pl": 1,
+ "poniatowa.pl": 1,
+ "ponpes.id": 1,
+ "pony.club": 1,
+ "pordenone.it": 1,
+ "porsanger.no": 1,
+ "porsangu.no": 1,
+ "porsgrunn.no": 1,
+ "pors\u00e1\u014bgu.no": 1,
+ "port.fr": 1,
+ "portal.museum": 1,
+ "portland.museum": 1,
+ "portlligat.museum": 1,
+ "posts-and-telecommunications.museum": 1,
+ "potager.org": 1,
+ "potenza.it": 1,
+ "powiat.pl": 1,
+ "poznan.pl": 1,
+ "pp.az": 1,
+ "pp.ru": 1,
+ "pp.se": 1,
+ "pp.ua": 1,
+ "ppg.br": 1,
+ "pr.gov.br": 1,
+ "pr.it": 1,
+ "pr.leg.br": 1,
+ "pr.us": 1,
+ "prato.it": 1,
+ "prd.fr": 1,
+ "prd.km": 1,
+ "prd.mg": 1,
+ "preservation.museum": 1,
+ "presidio.museum": 1,
+ "press.aero": 1,
+ "press.cy": 1,
+ "press.ma": 1,
+ "press.museum": 1,
+ "press.se": 1,
+ "presse.ci": 1,
+ "presse.km": 1,
+ "presse.ml": 1,
+ "pri.ee": 1,
+ "principe.st": 1,
+ "priv.at": 1,
+ "priv.hu": 1,
+ "priv.me": 1,
+ "priv.no": 1,
+ "priv.pl": 1,
+ "privatizehealthinsurance.net": 1,
+ "pro.az": 1,
+ "pro.br": 1,
+ "pro.cy": 1,
+ "pro.ec": 1,
+ "pro.fj": 1,
+ "pro.ht": 1,
+ "pro.mv": 1,
+ "pro.na": 1,
+ "pro.om": 1,
+ "pro.pr": 1,
+ "pro.tt": 1,
+ "pro.vn": 1,
+ "prochowice.pl": 1,
+ "production.aero": 1,
+ "prof.pr": 1,
+ "profesional.bo": 1,
+ "project.museum": 1,
+ "protonet.io": 1,
+ "pruszkow.pl": 1,
+ "prvcy.page": 1,
+ "przeworsk.pl": 1,
+ "psc.br": 1,
+ "psi.br": 1,
+ "psp.gov.pl": 1,
+ "psse.gov.pl": 1,
+ "pt.eu.org": 1,
+ "pt.it": 1,
+ "ptplus.fit": 1,
+ "pu.it": 1,
+ "pub.sa": 1,
+ "publ.pt": 1,
+ "public.museum": 1,
+ "publishproxy.com": 1,
+ "pubol.museum": 1,
+ "pubtls.org": 1,
+ "pueblo.bo": 1,
+ "pug.it": 1,
+ "puglia.it": 1,
+ "pulawy.pl": 1,
+ "pup.gov.pl": 1,
+ "pv.it": 1,
+ "pvh.br": 1,
+ "pvt.ge": 1,
+ "pvt.k12.ma.us": 1,
+ "pyatigorsk.ru": 1,
+ "pymnt.uk": 1,
+ "pz.it": 1,
+ "q-a.eu.org": 1,
+ "q.bg": 1,
+ "qa2.com": 1,
+ "qbuser.com": 1,
+ "qc.ca": 1,
+ "qc.com": 1,
+ "qcx.io": 1,
+ "qh.cn": 1,
+ "qld.au": 1,
+ "qld.edu.au": 1,
+ "qld.gov.au": 1,
+ "qsl.br": 1,
+ "qualifioapp.com": 1,
+ "quebec.museum": 1,
+ "quicksytes.com": 1,
+ "quipelements.com": 2,
+ "r.appspot.com": 2,
+ "r.bg": 1,
+ "r.cdn77.net": 1,
+ "r.se": 1,
+ "ra.it": 1,
+ "rackmaze.com": 1,
+ "rackmaze.net": 1,
+ "rade.no": 1,
+ "radio.am": 1,
+ "radio.br": 1,
+ "radio.fm": 1,
+ "radom.pl": 1,
+ "radoy.no": 1,
+ "rad\u00f8y.no": 1,
+ "ragusa.it": 1,
+ "rahkkeravju.no": 1,
+ "raholt.no": 1,
+ "railroad.museum": 1,
+ "railway.museum": 1,
+ "raisa.no": 1,
+ "rakkestad.no": 1,
+ "ralingen.no": 1,
+ "rana.no": 1,
+ "randaberg.no": 1,
+ "rankoshi.hokkaido.jp": 1,
+ "ranzan.saitama.jp": 1,
+ "ras.ru": 1,
+ "rauma.no": 1,
+ "ravendb.community": 1,
+ "ravendb.me": 1,
+ "ravendb.run": 1,
+ "ravenna.it": 1,
+ "rawa-maz.pl": 1,
+ "rc.it": 1,
+ "rdv.to": 1,
+ "re.it": 1,
+ "re.kr": 1,
+ "read-books.org": 1,
+ "readmyblog.org": 1,
+ "readthedocs.io": 1,
+ "realestate.pl": 1,
+ "realm.cz": 1,
+ "rebun.hokkaido.jp": 1,
+ "rec.br": 1,
+ "rec.co": 1,
+ "rec.nf": 1,
+ "rec.ro": 1,
+ "rec.ve": 1,
+ "recht.pro": 1,
+ "recife.br": 1,
+ "recreation.aero": 1,
+ "red.sv": 1,
+ "redirectme.net": 1,
+ "reg.dk": 1,
+ "reggio-calabria.it": 1,
+ "reggio-emilia.it": 1,
+ "reggiocalabria.it": 1,
+ "reggioemilia.it": 1,
+ "reklam.hu": 1,
+ "rel.ht": 1,
+ "rel.pl": 1,
+ "remotewd.com": 1,
+ "rendalen.no": 1,
+ "rennebu.no": 1,
+ "rennesoy.no": 1,
+ "rennes\u00f8y.no": 1,
+ "rep.br": 1,
+ "rep.kp": 1,
+ "repbody.aero": 1,
+ "repl.co": 1,
+ "repl.run": 1,
+ "res.aero": 1,
+ "res.in": 1,
+ "research.aero": 1,
+ "research.museum": 1,
+ "resindevice.io": 1,
+ "resistance.museum": 1,
+ "revista.bo": 1,
+ "rg.it": 1,
+ "rhcloud.com": 1,
+ "ri.it": 1,
+ "ri.us": 1,
+ "ribeirao.br": 1,
+ "rieti.it": 1,
+ "rifu.miyagi.jp": 1,
+ "riik.ee": 1,
+ "rikubetsu.hokkaido.jp": 1,
+ "rikuzentakata.iwate.jp": 1,
+ "rimini.it": 1,
+ "rindal.no": 1,
+ "ringebu.no": 1,
+ "ringerike.no": 1,
+ "ringsaker.no": 1,
+ "rio.br": 1,
+ "riobranco.br": 1,
+ "riodejaneiro.museum": 1,
+ "riopreto.br": 1,
+ "rishiri.hokkaido.jp": 1,
+ "rishirifuji.hokkaido.jp": 1,
+ "risor.no": 1,
+ "rissa.no": 1,
+ "ris\u00f8r.no": 1,
+ "ritto.shiga.jp": 1,
+ "rivne.ua": 1,
+ "rj.gov.br": 1,
+ "rj.leg.br": 1,
+ "rl.no": 1,
+ "rm.it": 1,
+ "rn.gov.br": 1,
+ "rn.it": 1,
+ "rn.leg.br": 1,
+ "rnrt.tn": 1,
+ "rns.tn": 1,
+ "rnu.tn": 1,
+ "ro.eu.org": 1,
+ "ro.gov.br": 1,
+ "ro.im": 1,
+ "ro.it": 1,
+ "ro.leg.br": 1,
+ "roan.no": 1,
+ "rochester.museum": 1,
+ "rockart.museum": 1,
+ "rodoy.no": 1,
+ "rokunohe.aomori.jp": 1,
+ "rollag.no": 1,
+ "roma.it": 1,
+ "roma.museum": 1,
+ "rome.it": 1,
+ "romsa.no": 1,
+ "romskog.no": 1,
+ "roros.no": 1,
+ "rost.no": 1,
+ "rotorcraft.aero": 1,
+ "router.management": 1,
+ "rovigo.it": 1,
+ "rovno.ua": 1,
+ "royken.no": 1,
+ "royrvik.no": 1,
+ "rr.gov.br": 1,
+ "rr.leg.br": 1,
+ "rs.gov.br": 1,
+ "rs.leg.br": 1,
+ "rsc.cdn77.org": 1,
+ "ru.com": 1,
+ "ru.eu.org": 1,
+ "ru.net": 1,
+ "run.app": 1,
+ "ruovat.no": 1,
+ "russia.museum": 1,
+ "rv.ua": 1,
+ "rybnik.pl": 1,
+ "rygge.no": 1,
+ "ryokami.saitama.jp": 1,
+ "ryugasaki.ibaraki.jp": 1,
+ "ryuoh.shiga.jp": 1,
+ "rzeszow.pl": 1,
+ "rzgw.gov.pl": 1,
+ "r\u00e1hkker\u00e1vju.no": 1,
+ "r\u00e1isa.no": 1,
+ "r\u00e5de.no": 1,
+ "r\u00e5holt.no": 1,
+ "r\u00e6lingen.no": 1,
+ "r\u00f8d\u00f8y.no": 1,
+ "r\u00f8mskog.no": 1,
+ "r\u00f8ros.no": 1,
+ "r\u00f8st.no": 1,
+ "r\u00f8yken.no": 1,
+ "r\u00f8yrvik.no": 1,
+ "s.bg": 1,
+ "s.se": 1,
+ "s3-ap-northeast-1.amazonaws.com": 1,
+ "s3-ap-northeast-2.amazonaws.com": 1,
+ "s3-ap-south-1.amazonaws.com": 1,
+ "s3-ap-southeast-1.amazonaws.com": 1,
+ "s3-ap-southeast-2.amazonaws.com": 1,
+ "s3-ca-central-1.amazonaws.com": 1,
+ "s3-eu-central-1.amazonaws.com": 1,
+ "s3-eu-west-1.amazonaws.com": 1,
+ "s3-eu-west-2.amazonaws.com": 1,
+ "s3-eu-west-3.amazonaws.com": 1,
+ "s3-external-1.amazonaws.com": 1,
+ "s3-fips-us-gov-west-1.amazonaws.com": 1,
+ "s3-sa-east-1.amazonaws.com": 1,
+ "s3-us-east-2.amazonaws.com": 1,
+ "s3-us-gov-west-1.amazonaws.com": 1,
+ "s3-us-west-1.amazonaws.com": 1,
+ "s3-us-west-2.amazonaws.com": 1,
+ "s3-website-ap-northeast-1.amazonaws.com": 1,
+ "s3-website-ap-southeast-1.amazonaws.com": 1,
+ "s3-website-ap-southeast-2.amazonaws.com": 1,
+ "s3-website-eu-west-1.amazonaws.com": 1,
+ "s3-website-sa-east-1.amazonaws.com": 1,
+ "s3-website-us-east-1.amazonaws.com": 1,
+ "s3-website-us-west-1.amazonaws.com": 1,
+ "s3-website-us-west-2.amazonaws.com": 1,
+ "s3-website.ap-northeast-2.amazonaws.com": 1,
+ "s3-website.ap-south-1.amazonaws.com": 1,
+ "s3-website.ca-central-1.amazonaws.com": 1,
+ "s3-website.eu-central-1.amazonaws.com": 1,
+ "s3-website.eu-west-2.amazonaws.com": 1,
+ "s3-website.eu-west-3.amazonaws.com": 1,
+ "s3-website.us-east-2.amazonaws.com": 1,
+ "s3.amazonaws.com": 1,
+ "s3.ap-northeast-2.amazonaws.com": 1,
+ "s3.ap-south-1.amazonaws.com": 1,
+ "s3.ca-central-1.amazonaws.com": 1,
+ "s3.cn-north-1.amazonaws.com.cn": 1,
+ "s3.dualstack.ap-northeast-1.amazonaws.com": 1,
+ "s3.dualstack.ap-northeast-2.amazonaws.com": 1,
+ "s3.dualstack.ap-south-1.amazonaws.com": 1,
+ "s3.dualstack.ap-southeast-1.amazonaws.com": 1,
+ "s3.dualstack.ap-southeast-2.amazonaws.com": 1,
+ "s3.dualstack.ca-central-1.amazonaws.com": 1,
+ "s3.dualstack.eu-central-1.amazonaws.com": 1,
+ "s3.dualstack.eu-west-1.amazonaws.com": 1,
+ "s3.dualstack.eu-west-2.amazonaws.com": 1,
+ "s3.dualstack.eu-west-3.amazonaws.com": 1,
+ "s3.dualstack.sa-east-1.amazonaws.com": 1,
+ "s3.dualstack.us-east-1.amazonaws.com": 1,
+ "s3.dualstack.us-east-2.amazonaws.com": 1,
+ "s3.eu-central-1.amazonaws.com": 1,
+ "s3.eu-west-2.amazonaws.com": 1,
+ "s3.eu-west-3.amazonaws.com": 1,
+ "s3.us-east-2.amazonaws.com": 1,
+ "s5y.io": 2,
+ "sa-east-1.elasticbeanstalk.com": 1,
+ "sa.au": 1,
+ "sa.com": 1,
+ "sa.cr": 1,
+ "sa.edu.au": 1,
+ "sa.gov.au": 1,
+ "sa.gov.pl": 1,
+ "sa.it": 1,
+ "sabae.fukui.jp": 1,
+ "sado.niigata.jp": 1,
+ "safety.aero": 1,
+ "saga.jp": 1,
+ "saga.saga.jp": 1,
+ "sagae.yamagata.jp": 1,
+ "sagamihara.kanagawa.jp": 1,
+ "saigawa.fukuoka.jp": 1,
+ "saijo.ehime.jp": 1,
+ "saikai.nagasaki.jp": 1,
+ "saiki.oita.jp": 1,
+ "saintlouis.museum": 1,
+ "saitama.jp": 1,
+ "saitama.saitama.jp": 1,
+ "saito.miyazaki.jp": 1,
+ "saka.hiroshima.jp": 1,
+ "sakado.saitama.jp": 1,
+ "sakae.chiba.jp": 1,
+ "sakae.nagano.jp": 1,
+ "sakahogi.gifu.jp": 1,
+ "sakai.fukui.jp": 1,
+ "sakai.ibaraki.jp": 1,
+ "sakai.osaka.jp": 1,
+ "sakaiminato.tottori.jp": 1,
+ "sakaki.nagano.jp": 1,
+ "sakata.yamagata.jp": 1,
+ "sakawa.kochi.jp": 1,
+ "sakegawa.yamagata.jp": 1,
+ "saku.nagano.jp": 1,
+ "sakuho.nagano.jp": 1,
+ "sakura.chiba.jp": 1,
+ "sakura.tochigi.jp": 1,
+ "sakuragawa.ibaraki.jp": 1,
+ "sakurai.nara.jp": 1,
+ "sakyo.kyoto.jp": 1,
+ "salangen.no": 1,
+ "salat.no": 1,
+ "salem.museum": 1,
+ "salerno.it": 1,
+ "saltdal.no": 1,
+ "salud.bo": 1,
+ "salvador.br": 1,
+ "salvadordali.museum": 1,
+ "salzburg.museum": 1,
+ "samegawa.fukushima.jp": 1,
+ "samnanger.no": 1,
+ "sampa.br": 1,
+ "samukawa.kanagawa.jp": 1,
+ "sanagochi.tokushima.jp": 1,
+ "sanda.hyogo.jp": 1,
+ "sandcats.io": 1,
+ "sande.more-og-romsdal.no": 1,
+ "sande.m\u00f8re-og-romsdal.no": 1,
+ "sande.vestfold.no": 1,
+ "sandefjord.no": 1,
+ "sandiego.museum": 1,
+ "sandnes.no": 1,
+ "sandnessjoen.no": 1,
+ "sandnessj\u00f8en.no": 1,
+ "sandoy.no": 1,
+ "sand\u00f8y.no": 1,
+ "sanfrancisco.museum": 1,
+ "sango.nara.jp": 1,
+ "sanjo.niigata.jp": 1,
+ "sannan.hyogo.jp": 1,
+ "sannohe.aomori.jp": 1,
+ "sano.tochigi.jp": 1,
+ "sanok.pl": 1,
+ "santabarbara.museum": 1,
+ "santacruz.museum": 1,
+ "santafe.museum": 1,
+ "santamaria.br": 1,
+ "santoandre.br": 1,
+ "sanuki.kagawa.jp": 1,
+ "saobernardo.br": 1,
+ "saogonca.br": 1,
+ "saotome.st": 1,
+ "sapporo.jp": 2,
+ "sar.it": 1,
+ "sardegna.it": 1,
+ "sardinia.it": 1,
+ "saroma.hokkaido.jp": 1,
+ "sarpsborg.no": 1,
+ "sarufutsu.hokkaido.jp": 1,
+ "sasaguri.fukuoka.jp": 1,
+ "sasayama.hyogo.jp": 1,
+ "sasebo.nagasaki.jp": 1,
+ "saskatchewan.museum": 1,
+ "sassari.it": 1,
+ "satosho.okayama.jp": 1,
+ "satsumasendai.kagoshima.jp": 1,
+ "satte.saitama.jp": 1,
+ "satx.museum": 1,
+ "sauda.no": 1,
+ "sauherad.no": 1,
+ "savannahga.museum": 1,
+ "saves-the-whales.com": 1,
+ "savona.it": 1,
+ "sayama.osaka.jp": 1,
+ "sayama.saitama.jp": 1,
+ "sayo.hyogo.jp": 1,
+ "sb.ua": 1,
+ "sc.cn": 1,
+ "sc.gov.br": 1,
+ "sc.ke": 1,
+ "sc.kr": 1,
+ "sc.leg.br": 1,
+ "sc.ls": 1,
+ "sc.tz": 1,
+ "sc.ug": 1,
+ "sc.us": 1,
+ "scapp.io": 1,
+ "sch.ae": 1,
+ "sch.id": 1,
+ "sch.ir": 1,
+ "sch.jo": 1,
+ "sch.lk": 1,
+ "sch.ly": 1,
+ "sch.ng": 1,
+ "sch.qa": 1,
+ "sch.sa": 1,
+ "sch.so": 1,
+ "sch.uk": 2,
+ "sch.zm": 1,
+ "schlesisches.museum": 1,
+ "schoenbrunn.museum": 1,
+ "schokokeks.net": 1,
+ "schokoladen.museum": 1,
+ "school.museum": 1,
+ "school.na": 1,
+ "school.nz": 1,
+ "school.za": 1,
+ "schools.nsw.edu.au": 1,
+ "schulserver.de": 1,
+ "schweiz.museum": 1,
+ "sci.eg": 1,
+ "science-fiction.museum": 1,
+ "science.museum": 1,
+ "scienceandhistory.museum": 1,
+ "scienceandindustry.museum": 1,
+ "sciencecenter.museum": 1,
+ "sciencecenters.museum": 1,
+ "sciencehistory.museum": 1,
+ "sciences.museum": 1,
+ "sciencesnaturelles.museum": 1,
+ "scientist.aero": 1,
+ "scotland.museum": 1,
+ "scrapper-site.net": 1,
+ "scrapping.cc": 1,
+ "scrysec.com": 1,
+ "sd.cn": 1,
+ "sd.us": 1,
+ "sdn.gov.pl": 1,
+ "se.eu.org": 1,
+ "se.gov.br": 1,
+ "se.leg.br": 1,
+ "se.net": 1,
+ "seaport.museum": 1,
+ "sebastopol.ua": 1,
+ "sec.ps": 1,
+ "securitytactics.com": 1,
+ "seg.br": 1,
+ "seidat.net": 1,
+ "seihi.nagasaki.jp": 1,
+ "seika.kyoto.jp": 1,
+ "seiro.niigata.jp": 1,
+ "seirou.niigata.jp": 1,
+ "seiyo.ehime.jp": 1,
+ "sejny.pl": 1,
+ "seki.gifu.jp": 1,
+ "sekigahara.gifu.jp": 1,
+ "sekikawa.niigata.jp": 1,
+ "sel.no": 1,
+ "selbu.no": 1,
+ "selfip.biz": 1,
+ "selfip.com": 1,
+ "selfip.info": 1,
+ "selfip.net": 1,
+ "selfip.org": 1,
+ "selje.no": 1,
+ "seljord.no": 1,
+ "sells-for-less.com": 1,
+ "sells-for-u.com": 1,
+ "sells-it.net": 1,
+ "sellsyourhome.org": 1,
+ "semboku.akita.jp": 1,
+ "semine.miyagi.jp": 1,
+ "sendai.jp": 2,
+ "sennan.osaka.jp": 1,
+ "senseering.net": 1,
+ "sensiosite.cloud": 2,
+ "seoul.kr": 1,
+ "sera.hiroshima.jp": 1,
+ "seranishi.hiroshima.jp": 1,
+ "servebbs.com": 1,
+ "servebbs.net": 1,
+ "servebbs.org": 1,
+ "servebeer.com": 1,
+ "serveblog.net": 1,
+ "servecounterstrike.com": 1,
+ "serveexchange.com": 1,
+ "serveftp.com": 1,
+ "serveftp.net": 1,
+ "serveftp.org": 1,
+ "servegame.com": 1,
+ "servegame.org": 1,
+ "servehalflife.com": 1,
+ "servehttp.com": 1,
+ "servehumour.com": 1,
+ "serveirc.com": 1,
+ "serveminecraft.net": 1,
+ "servemp3.com": 1,
+ "servep2p.com": 1,
+ "servepics.com": 1,
+ "servequake.com": 1,
+ "servesarcasm.com": 1,
+ "service.gov.uk": 1,
+ "services.aero": 1,
+ "setagaya.tokyo.jp": 1,
+ "seto.aichi.jp": 1,
+ "setouchi.okayama.jp": 1,
+ "settlement.museum": 1,
+ "settlers.museum": 1,
+ "settsu.osaka.jp": 1,
+ "sevastopol.ua": 1,
+ "sex.hu": 1,
+ "sex.pl": 1,
+ "sf.no": 1,
+ "sh.cn": 1,
+ "shacknet.nu": 1,
+ "shakotan.hokkaido.jp": 1,
+ "shari.hokkaido.jp": 1,
+ "shell.museum": 1,
+ "sherbrooke.museum": 1,
+ "shibata.miyagi.jp": 1,
+ "shibata.niigata.jp": 1,
+ "shibecha.hokkaido.jp": 1,
+ "shibetsu.hokkaido.jp": 1,
+ "shibukawa.gunma.jp": 1,
+ "shibuya.tokyo.jp": 1,
+ "shichikashuku.miyagi.jp": 1,
+ "shichinohe.aomori.jp": 1,
+ "shiftedit.io": 1,
+ "shiga.jp": 1,
+ "shiiba.miyazaki.jp": 1,
+ "shijonawate.osaka.jp": 1,
+ "shika.ishikawa.jp": 1,
+ "shikabe.hokkaido.jp": 1,
+ "shikama.miyagi.jp": 1,
+ "shikaoi.hokkaido.jp": 1,
+ "shikatsu.aichi.jp": 1,
+ "shiki.saitama.jp": 1,
+ "shikokuchuo.ehime.jp": 1,
+ "shima.mie.jp": 1,
+ "shimabara.nagasaki.jp": 1,
+ "shimada.shizuoka.jp": 1,
+ "shimamaki.hokkaido.jp": 1,
+ "shimamoto.osaka.jp": 1,
+ "shimane.jp": 1,
+ "shimane.shimane.jp": 1,
+ "shimizu.hokkaido.jp": 1,
+ "shimizu.shizuoka.jp": 1,
+ "shimoda.shizuoka.jp": 1,
+ "shimodate.ibaraki.jp": 1,
+ "shimofusa.chiba.jp": 1,
+ "shimogo.fukushima.jp": 1,
+ "shimoichi.nara.jp": 1,
+ "shimoji.okinawa.jp": 1,
+ "shimokawa.hokkaido.jp": 1,
+ "shimokitayama.nara.jp": 1,
+ "shimonita.gunma.jp": 1,
+ "shimonoseki.yamaguchi.jp": 1,
+ "shimosuwa.nagano.jp": 1,
+ "shimotsuke.tochigi.jp": 1,
+ "shimotsuma.ibaraki.jp": 1,
+ "shinagawa.tokyo.jp": 1,
+ "shinanomachi.nagano.jp": 1,
+ "shingo.aomori.jp": 1,
+ "shingu.fukuoka.jp": 1,
+ "shingu.hyogo.jp": 1,
+ "shingu.wakayama.jp": 1,
+ "shinichi.hiroshima.jp": 1,
+ "shinjo.nara.jp": 1,
+ "shinjo.okayama.jp": 1,
+ "shinjo.yamagata.jp": 1,
+ "shinjuku.tokyo.jp": 1,
+ "shinkamigoto.nagasaki.jp": 1,
+ "shinonsen.hyogo.jp": 1,
+ "shinshinotsu.hokkaido.jp": 1,
+ "shinshiro.aichi.jp": 1,
+ "shinto.gunma.jp": 1,
+ "shintoku.hokkaido.jp": 1,
+ "shintomi.miyazaki.jp": 1,
+ "shinyoshitomi.fukuoka.jp": 1,
+ "shiogama.miyagi.jp": 1,
+ "shiojiri.nagano.jp": 1,
+ "shioya.tochigi.jp": 1,
+ "shirahama.wakayama.jp": 1,
+ "shirakawa.fukushima.jp": 1,
+ "shirakawa.gifu.jp": 1,
+ "shirako.chiba.jp": 1,
+ "shiranuka.hokkaido.jp": 1,
+ "shiraoi.hokkaido.jp": 1,
+ "shiraoka.saitama.jp": 1,
+ "shirataka.yamagata.jp": 1,
+ "shiriuchi.hokkaido.jp": 1,
+ "shiroi.chiba.jp": 1,
+ "shiroishi.miyagi.jp": 1,
+ "shiroishi.saga.jp": 1,
+ "shirosato.ibaraki.jp": 1,
+ "shishikui.tokushima.jp": 1,
+ "shiso.hyogo.jp": 1,
+ "shisui.chiba.jp": 1,
+ "shitara.aichi.jp": 1,
+ "shiwa.iwate.jp": 1,
+ "shizukuishi.iwate.jp": 1,
+ "shizuoka.jp": 1,
+ "shizuoka.shizuoka.jp": 1,
+ "shobara.hiroshima.jp": 1,
+ "shonai.fukuoka.jp": 1,
+ "shonai.yamagata.jp": 1,
+ "shoo.okayama.jp": 1,
+ "shop.ht": 1,
+ "shop.hu": 1,
+ "shop.pl": 1,
+ "shop.ro": 1,
+ "shop.th": 1,
+ "shopitsite.com": 1,
+ "shopware.store": 1,
+ "show.aero": 1,
+ "showa.fukushima.jp": 1,
+ "showa.gunma.jp": 1,
+ "showa.yamanashi.jp": 1,
+ "shunan.yamaguchi.jp": 1,
+ "shw.io": 1,
+ "si.eu.org": 1,
+ "si.it": 1,
+ "sibenik.museum": 1,
+ "sic.it": 1,
+ "sicilia.it": 1,
+ "sicily.it": 1,
+ "siellak.no": 1,
+ "siena.it": 1,
+ "sigdal.no": 1,
+ "siljan.no": 1,
+ "silk.museum": 1,
+ "simple-url.com": 1,
+ "sinaapp.com": 1,
+ "siracusa.it": 1,
+ "sirdal.no": 1,
+ "siteleaf.net": 1,
+ "sites.static.land": 1,
+ "sjc.br": 1,
+ "sk.ca": 1,
+ "sk.eu.org": 1,
+ "skanit.no": 1,
+ "skanland.no": 1,
+ "skaun.no": 1,
+ "skedsmo.no": 1,
+ "skedsmokorset.no": 1,
+ "ski.museum": 1,
+ "ski.no": 1,
+ "skien.no": 1,
+ "skierva.no": 1,
+ "skierv\u00e1.no": 1,
+ "skiptvet.no": 1,
+ "skjak.no": 1,
+ "skjervoy.no": 1,
+ "skjerv\u00f8y.no": 1,
+ "skj\u00e5k.no": 1,
+ "sklep.pl": 1,
+ "sko.gov.pl": 1,
+ "skoczow.pl": 1,
+ "skodje.no": 1,
+ "skole.museum": 1,
+ "skydiving.aero": 1,
+ "skygearapp.com": 1,
+ "sk\u00e1nit.no": 1,
+ "sk\u00e5nland.no": 1,
+ "slask.pl": 1,
+ "slattum.no": 1,
+ "sld.do": 1,
+ "sld.pa": 1,
+ "slg.br": 1,
+ "slupsk.pl": 1,
+ "slz.br": 1,
+ "sm.ua": 1,
+ "small-web.org": 1,
+ "smola.no": 1,
+ "sm\u00f8la.no": 1,
+ "sn.cn": 1,
+ "snaase.no": 1,
+ "snasa.no": 1,
+ "snillfjord.no": 1,
+ "snoasa.no": 1,
+ "sn\u00e5ase.no": 1,
+ "sn\u00e5sa.no": 1,
+ "so.gov.pl": 1,
+ "so.it": 1,
+ "sobetsu.hokkaido.jp": 1,
+ "soc.dz": 1,
+ "soc.lk": 1,
+ "soc.srcf.net": 1,
+ "sochi.su": 1,
+ "society.museum": 1,
+ "sodegaura.chiba.jp": 1,
+ "soeda.fukuoka.jp": 1,
+ "software.aero": 1,
+ "sogndal.no": 1,
+ "sogne.no": 1,
+ "soja.okayama.jp": 1,
+ "soka.saitama.jp": 1,
+ "sokndal.no": 1,
+ "sola.no": 1,
+ "sologne.museum": 1,
+ "solund.no": 1,
+ "soma.fukushima.jp": 1,
+ "somna.no": 1,
+ "sondre-land.no": 1,
+ "sondrio.it": 1,
+ "songdalen.no": 1,
+ "soni.nara.jp": 1,
+ "soo.kagoshima.jp": 1,
+ "sopot.pl": 1,
+ "sor-aurdal.no": 1,
+ "sor-fron.no": 1,
+ "sor-odal.no": 1,
+ "sor-varanger.no": 1,
+ "sorfold.no": 1,
+ "sorocaba.br": 1,
+ "sorreisa.no": 1,
+ "sortland.no": 1,
+ "sorum.no": 1,
+ "sos.pl": 1,
+ "sosa.chiba.jp": 1,
+ "sosnowiec.pl": 1,
+ "soundandvision.museum": 1,
+ "soundcast.me": 1,
+ "southcarolina.museum": 1,
+ "southwest.museum": 1,
+ "sowa.ibaraki.jp": 1,
+ "sp.gov.br": 1,
+ "sp.it": 1,
+ "sp.leg.br": 1,
+ "space-to-rent.com": 1,
+ "space.museum": 1,
+ "spacekit.io": 1,
+ "spb.ru": 1,
+ "spb.su": 1,
+ "spdns.de": 1,
+ "spdns.eu": 1,
+ "spdns.org": 1,
+ "spectrum.myjino.ru": 2,
+ "sphinx.mythic-beasts.com": 1,
+ "spjelkavik.no": 1,
+ "sport.hu": 1,
+ "spy.museum": 1,
+ "spydeberg.no": 1,
+ "square.museum": 1,
+ "square7.ch": 1,
+ "square7.de": 1,
+ "square7.net": 1,
+ "sr.gov.pl": 1,
+ "sr.it": 1,
+ "srv.br": 1,
+ "ss.it": 1,
+ "ssl.origin.cdn77-secure.org": 1,
+ "st.no": 1,
+ "stackhero-network.com": 1,
+ "stadt.museum": 1,
+ "stage.nodeart.io": 1,
+ "staging.onred.one": 1,
+ "stalbans.museum": 1,
+ "stalowa-wola.pl": 1,
+ "stange.no": 1,
+ "starachowice.pl": 1,
+ "stargard.pl": 1,
+ "starnberg.museum": 1,
+ "starostwo.gov.pl": 1,
+ "stat.no": 1,
+ "state.museum": 1,
+ "stateofdelaware.museum": 1,
+ "stathelle.no": 1,
+ "static-access.net": 1,
+ "static.land": 1,
+ "static.observableusercontent.com": 1,
+ "statics.cloud": 2,
+ "station.museum": 1,
+ "stavanger.no": 1,
+ "stavern.no": 1,
+ "steam.museum": 1,
+ "steiermark.museum": 1,
+ "steigen.no": 1,
+ "steinkjer.no": 1,
+ "stg.dev": 2,
+ "sth.ac.at": 1,
+ "stjohn.museum": 1,
+ "stjordal.no": 1,
+ "stjordalshalsen.no": 1,
+ "stj\u00f8rdal.no": 1,
+ "stj\u00f8rdalshalsen.no": 1,
+ "stockholm.museum": 1,
+ "stokke.no": 1,
+ "stolos.io": 2,
+ "stor-elvdal.no": 1,
+ "storage.yandexcloud.net": 1,
+ "stord.no": 1,
+ "stordal.no": 1,
+ "store.bb": 1,
+ "store.dk": 1,
+ "store.nf": 1,
+ "store.ro": 1,
+ "store.st": 1,
+ "store.ve": 1,
+ "storfjord.no": 1,
+ "storj.farm": 1,
+ "stpetersburg.museum": 1,
+ "strand.no": 1,
+ "stranda.no": 1,
+ "stryn.no": 1,
+ "student.aero": 1,
+ "stuff-4-sale.org": 1,
+ "stuff-4-sale.us": 1,
+ "stufftoread.com": 1,
+ "stuttgart.museum": 1,
+ "sue.fukuoka.jp": 1,
+ "suedtirol.it": 1,
+ "suginami.tokyo.jp": 1,
+ "sugito.saitama.jp": 1,
+ "suifu.ibaraki.jp": 1,
+ "suisse.museum": 1,
+ "suita.osaka.jp": 1,
+ "sukagawa.fukushima.jp": 1,
+ "sukumo.kochi.jp": 1,
+ "sula.no": 1,
+ "suldal.no": 1,
+ "suli.hu": 1,
+ "sumida.tokyo.jp": 1,
+ "sumita.iwate.jp": 1,
+ "sumoto.hyogo.jp": 1,
+ "sumoto.kumamoto.jp": 1,
+ "sumy.ua": 1,
+ "sunagawa.hokkaido.jp": 1,
+ "sund.no": 1,
+ "sunndal.no": 1,
+ "surgeonshall.museum": 1,
+ "surnadal.no": 1,
+ "surrey.museum": 1,
+ "susaki.kochi.jp": 1,
+ "susono.shizuoka.jp": 1,
+ "suwa.nagano.jp": 1,
+ "suwalki.pl": 1,
+ "suzaka.nagano.jp": 1,
+ "suzu.ishikawa.jp": 1,
+ "suzuka.mie.jp": 1,
+ "sv.it": 1,
+ "svalbard.no": 1,
+ "svc.firenet.ch": 2,
+ "sveio.no": 1,
+ "svelvik.no": 1,
+ "svizzera.museum": 1,
+ "svn-repos.de": 1,
+ "sweden.museum": 1,
+ "sweetpepper.org": 1,
+ "swidnica.pl": 1,
+ "swidnik.pl": 1,
+ "swiebodzin.pl": 1,
+ "swinoujscie.pl": 1,
+ "sx.cn": 1,
+ "sydney.museum": 1,
+ "sykkylven.no": 1,
+ "syncloud.it": 1,
+ "syno-ds.de": 1,
+ "synology-diskstation.de": 1,
+ "synology-ds.de": 1,
+ "synology.me": 1,
+ "sys.qcx.io": 2,
+ "sytes.net": 1,
+ "szczecin.pl": 1,
+ "szczytno.pl": 1,
+ "szex.hu": 1,
+ "szkola.pl": 1,
+ "s\u00e1lat.no": 1,
+ "s\u00e1l\u00e1t.no": 1,
+ "s\u00f8gne.no": 1,
+ "s\u00f8mna.no": 1,
+ "s\u00f8ndre-land.no": 1,
+ "s\u00f8r-aurdal.no": 1,
+ "s\u00f8r-fron.no": 1,
+ "s\u00f8r-odal.no": 1,
+ "s\u00f8r-varanger.no": 1,
+ "s\u00f8rfold.no": 1,
+ "s\u00f8rreisa.no": 1,
+ "s\u00f8rum.no": 1,
+ "s\u00fcdtirol.it": 1,
+ "t.bg": 1,
+ "t.se": 1,
+ "t3l3p0rt.net": 1,
+ "ta.it": 1,
+ "taa.it": 1,
+ "tabayama.yamanashi.jp": 1,
+ "tabuse.yamaguchi.jp": 1,
+ "tachiarai.fukuoka.jp": 1,
+ "tachikawa.tokyo.jp": 1,
+ "tadaoka.osaka.jp": 1,
+ "tado.mie.jp": 1,
+ "tadotsu.kagawa.jp": 1,
+ "tagajo.miyagi.jp": 1,
+ "tagami.niigata.jp": 1,
+ "tagawa.fukuoka.jp": 1,
+ "tahara.aichi.jp": 1,
+ "taifun-dns.de": 1,
+ "taiji.wakayama.jp": 1,
+ "taiki.hokkaido.jp": 1,
+ "taiki.mie.jp": 1,
+ "tainai.niigata.jp": 1,
+ "taira.toyama.jp": 1,
+ "taishi.hyogo.jp": 1,
+ "taishi.osaka.jp": 1,
+ "taishin.fukushima.jp": 1,
+ "taito.tokyo.jp": 1,
+ "taiwa.miyagi.jp": 1,
+ "tajimi.gifu.jp": 1,
+ "tajiri.osaka.jp": 1,
+ "taka.hyogo.jp": 1,
+ "takagi.nagano.jp": 1,
+ "takahagi.ibaraki.jp": 1,
+ "takahama.aichi.jp": 1,
+ "takahama.fukui.jp": 1,
+ "takaharu.miyazaki.jp": 1,
+ "takahashi.okayama.jp": 1,
+ "takahata.yamagata.jp": 1,
+ "takaishi.osaka.jp": 1,
+ "takamatsu.kagawa.jp": 1,
+ "takamori.kumamoto.jp": 1,
+ "takamori.nagano.jp": 1,
+ "takanabe.miyazaki.jp": 1,
+ "takanezawa.tochigi.jp": 1,
+ "takaoka.toyama.jp": 1,
+ "takarazuka.hyogo.jp": 1,
+ "takasago.hyogo.jp": 1,
+ "takasaki.gunma.jp": 1,
+ "takashima.shiga.jp": 1,
+ "takasu.hokkaido.jp": 1,
+ "takata.fukuoka.jp": 1,
+ "takatori.nara.jp": 1,
+ "takatsuki.osaka.jp": 1,
+ "takatsuki.shiga.jp": 1,
+ "takayama.gifu.jp": 1,
+ "takayama.gunma.jp": 1,
+ "takayama.nagano.jp": 1,
+ "takazaki.miyazaki.jp": 1,
+ "takehara.hiroshima.jp": 1,
+ "taketa.oita.jp": 1,
+ "taketomi.okinawa.jp": 1,
+ "taki.mie.jp": 1,
+ "takikawa.hokkaido.jp": 1,
+ "takino.hyogo.jp": 1,
+ "takinoue.hokkaido.jp": 1,
+ "takko.aomori.jp": 1,
+ "tako.chiba.jp": 1,
+ "taku.saga.jp": 1,
+ "tama.tokyo.jp": 1,
+ "tamakawa.fukushima.jp": 1,
+ "tamaki.mie.jp": 1,
+ "tamamura.gunma.jp": 1,
+ "tamano.okayama.jp": 1,
+ "tamatsukuri.ibaraki.jp": 1,
+ "tamayu.shimane.jp": 1,
+ "tamba.hyogo.jp": 1,
+ "tana.no": 1,
+ "tanabe.kyoto.jp": 1,
+ "tanabe.wakayama.jp": 1,
+ "tanagura.fukushima.jp": 1,
+ "tananger.no": 1,
+ "tank.museum": 1,
+ "tanohata.iwate.jp": 1,
+ "tara.saga.jp": 1,
+ "tarama.okinawa.jp": 1,
+ "taranto.it": 1,
+ "targi.pl": 1,
+ "tarnobrzeg.pl": 1,
+ "tarui.gifu.jp": 1,
+ "tarumizu.kagoshima.jp": 1,
+ "tas.au": 1,
+ "tas.edu.au": 1,
+ "tas.gov.au": 1,
+ "tashkent.su": 1,
+ "tatebayashi.gunma.jp": 1,
+ "tateshina.nagano.jp": 1,
+ "tateyama.chiba.jp": 1,
+ "tateyama.toyama.jp": 1,
+ "tatsuno.hyogo.jp": 1,
+ "tatsuno.nagano.jp": 1,
+ "tawaramoto.nara.jp": 1,
+ "taxi.br": 1,
+ "tc.br": 1,
+ "tcm.museum": 1,
+ "tcp4.me": 1,
+ "te.it": 1,
+ "te.ua": 1,
+ "teaches-yoga.com": 1,
+ "teams.algorithmia.com": 0,
+ "tec.br": 1,
+ "tec.mi.us": 1,
+ "tec.ve": 1,
+ "technology.museum": 1,
+ "tecnologia.bo": 1,
+ "tel.tr": 1,
+ "tele.amune.org": 1,
+ "telebit.app": 1,
+ "telebit.io": 1,
+ "telebit.xyz": 2,
+ "telekommunikation.museum": 1,
+ "television.museum": 1,
+ "temp-dns.com": 1,
+ "tempio-olbia.it": 1,
+ "tempioolbia.it": 1,
+ "tendo.yamagata.jp": 1,
+ "tenei.fukushima.jp": 1,
+ "tenkawa.nara.jp": 1,
+ "tenri.nara.jp": 1,
+ "teo.br": 1,
+ "teramo.it": 1,
+ "termez.su": 1,
+ "terni.it": 1,
+ "ternopil.ua": 1,
+ "teshikaga.hokkaido.jp": 1,
+ "test-iserv.de": 1,
+ "test.algorithmia.com": 0,
+ "test.ru": 1,
+ "test.tj": 1,
+ "texas.museum": 1,
+ "textile.museum": 1,
+ "tgory.pl": 1,
+ "the.br": 1,
+ "theater.museum": 1,
+ "theworkpc.com": 1,
+ "thingdustdata.com": 1,
+ "thruhere.net": 1,
+ "time.museum": 1,
+ "time.no": 1,
+ "timekeeping.museum": 1,
+ "tingvoll.no": 1,
+ "tinn.no": 1,
+ "tj.cn": 1,
+ "tjeldsund.no": 1,
+ "tjome.no": 1,
+ "tj\u00f8me.no": 1,
+ "tksat.bo": 1,
+ "tm.cy": 1,
+ "tm.dz": 1,
+ "tm.fr": 1,
+ "tm.hu": 1,
+ "tm.km": 1,
+ "tm.mc": 1,
+ "tm.mg": 1,
+ "tm.no": 1,
+ "tm.pl": 1,
+ "tm.ro": 1,
+ "tm.se": 1,
+ "tm.za": 1,
+ "tmp.br": 1,
+ "tn.it": 1,
+ "tn.us": 1,
+ "to.gov.br": 1,
+ "to.gt": 1,
+ "to.it": 1,
+ "to.leg.br": 1,
+ "to.md": 1,
+ "to.work": 1,
+ "toba.mie.jp": 1,
+ "tobe.ehime.jp": 1,
+ "tobetsu.hokkaido.jp": 1,
+ "tobishima.aichi.jp": 1,
+ "tochigi.jp": 1,
+ "tochigi.tochigi.jp": 1,
+ "tochio.niigata.jp": 1,
+ "toda.saitama.jp": 1,
+ "toei.aichi.jp": 1,
+ "toga.toyama.jp": 1,
+ "togakushi.nagano.jp": 1,
+ "togane.chiba.jp": 1,
+ "togitsu.nagasaki.jp": 1,
+ "togliatti.su": 1,
+ "togo.aichi.jp": 1,
+ "togura.nagano.jp": 1,
+ "tohma.hokkaido.jp": 1,
+ "tohnosho.chiba.jp": 1,
+ "toho.fukuoka.jp": 1,
+ "tokai.aichi.jp": 1,
+ "tokai.ibaraki.jp": 1,
+ "tokamachi.niigata.jp": 1,
+ "tokashiki.okinawa.jp": 1,
+ "toki.gifu.jp": 1,
+ "tokigawa.saitama.jp": 1,
+ "tokke.no": 1,
+ "tokoname.aichi.jp": 1,
+ "tokorozawa.saitama.jp": 1,
+ "tokushima.jp": 1,
+ "tokushima.tokushima.jp": 1,
+ "tokuyama.yamaguchi.jp": 1,
+ "tokyo.jp": 1,
+ "tolga.no": 1,
+ "tomakomai.hokkaido.jp": 1,
+ "tomari.hokkaido.jp": 1,
+ "tome.miyagi.jp": 1,
+ "tomi.nagano.jp": 1,
+ "tomigusuku.okinawa.jp": 1,
+ "tomika.gifu.jp": 1,
+ "tomioka.gunma.jp": 1,
+ "tomisato.chiba.jp": 1,
+ "tomiya.miyagi.jp": 1,
+ "tomobe.ibaraki.jp": 1,
+ "tonaki.okinawa.jp": 1,
+ "tonami.toyama.jp": 1,
+ "tondabayashi.osaka.jp": 1,
+ "tone.ibaraki.jp": 1,
+ "tono.iwate.jp": 1,
+ "tonosho.kagawa.jp": 1,
+ "tonsberg.no": 1,
+ "toolforge.org": 1,
+ "toon.ehime.jp": 1,
+ "topology.museum": 1,
+ "torahime.shiga.jp": 1,
+ "toride.ibaraki.jp": 1,
+ "torino.it": 1,
+ "torino.museum": 1,
+ "torsken.no": 1,
+ "tos.it": 1,
+ "tosa.kochi.jp": 1,
+ "tosashimizu.kochi.jp": 1,
+ "toscana.it": 1,
+ "toshima.tokyo.jp": 1,
+ "tosu.saga.jp": 1,
+ "tottori.jp": 1,
+ "tottori.tottori.jp": 1,
+ "touch.museum": 1,
+ "tourism.pl": 1,
+ "tourism.tn": 1,
+ "towada.aomori.jp": 1,
+ "town.museum": 1,
+ "townnews-staging.com": 1,
+ "toya.hokkaido.jp": 1,
+ "toyako.hokkaido.jp": 1,
+ "toyama.jp": 1,
+ "toyama.toyama.jp": 1,
+ "toyo.kochi.jp": 1,
+ "toyoake.aichi.jp": 1,
+ "toyohashi.aichi.jp": 1,
+ "toyokawa.aichi.jp": 1,
+ "toyonaka.osaka.jp": 1,
+ "toyone.aichi.jp": 1,
+ "toyono.osaka.jp": 1,
+ "toyooka.hyogo.jp": 1,
+ "toyosato.shiga.jp": 1,
+ "toyota.aichi.jp": 1,
+ "toyota.yamaguchi.jp": 1,
+ "toyotomi.hokkaido.jp": 1,
+ "toyotsu.fukuoka.jp": 1,
+ "toyoura.hokkaido.jp": 1,
+ "tozawa.yamagata.jp": 1,
+ "tozsde.hu": 1,
+ "tp.it": 1,
+ "tr.eu.org": 1,
+ "tr.it": 1,
+ "tr.no": 1,
+ "tra.kp": 1,
+ "trader.aero": 1,
+ "trading.aero": 1,
+ "traeumtgerade.de": 1,
+ "trafficplex.cloud": 1,
+ "trainer.aero": 1,
+ "trana.no": 1,
+ "tranby.no": 1,
+ "trani-andria-barletta.it": 1,
+ "trani-barletta-andria.it": 1,
+ "traniandriabarletta.it": 1,
+ "tranibarlettaandria.it": 1,
+ "tranoy.no": 1,
+ "translate.goog": 1,
+ "transport.museum": 1,
+ "transporte.bo": 1,
+ "transurl.be": 2,
+ "transurl.eu": 2,
+ "transurl.nl": 2,
+ "tran\u00f8y.no": 1,
+ "trapani.it": 1,
+ "travel.pl": 1,
+ "travel.tt": 1,
+ "trd.br": 1,
+ "tree.museum": 1,
+ "trentin-sud-tirol.it": 1,
+ "trentin-sudtirol.it": 1,
+ "trentin-sued-tirol.it": 1,
+ "trentin-suedtirol.it": 1,
+ "trentin-s\u00fcd-tirol.it": 1,
+ "trentin-s\u00fcdtirol.it": 1,
+ "trentino-a-adige.it": 1,
+ "trentino-aadige.it": 1,
+ "trentino-alto-adige.it": 1,
+ "trentino-altoadige.it": 1,
+ "trentino-s-tirol.it": 1,
+ "trentino-stirol.it": 1,
+ "trentino-sud-tirol.it": 1,
+ "trentino-sudtirol.it": 1,
+ "trentino-sued-tirol.it": 1,
+ "trentino-suedtirol.it": 1,
+ "trentino-s\u00fcd-tirol.it": 1,
+ "trentino-s\u00fcdtirol.it": 1,
+ "trentino.it": 1,
+ "trentinoa-adige.it": 1,
+ "trentinoaadige.it": 1,
+ "trentinoalto-adige.it": 1,
+ "trentinoaltoadige.it": 1,
+ "trentinos-tirol.it": 1,
+ "trentinostirol.it": 1,
+ "trentinosud-tirol.it": 1,
+ "trentinosudtirol.it": 1,
+ "trentinosued-tirol.it": 1,
+ "trentinosuedtirol.it": 1,
+ "trentinos\u00fcd-tirol.it": 1,
+ "trentinos\u00fcdtirol.it": 1,
+ "trentinsud-tirol.it": 1,
+ "trentinsudtirol.it": 1,
+ "trentinsued-tirol.it": 1,
+ "trentinsuedtirol.it": 1,
+ "trentins\u00fcd-tirol.it": 1,
+ "trentins\u00fcdtirol.it": 1,
+ "trento.it": 1,
+ "treviso.it": 1,
+ "trieste.it": 1,
+ "triton.zone": 2,
+ "troandin.no": 1,
+ "trogstad.no": 1,
+ "troitsk.su": 1,
+ "trolley.museum": 1,
+ "tromsa.no": 1,
+ "tromso.no": 1,
+ "troms\u00f8.no": 1,
+ "trondheim.no": 1,
+ "trust.museum": 1,
+ "trustee.museum": 1,
+ "trycloudflare.com": 1,
+ "trysil.no": 1,
+ "tr\u00e6na.no": 1,
+ "tr\u00f8gstad.no": 1,
+ "ts.it": 1,
+ "tselinograd.su": 1,
+ "tsk.tr": 1,
+ "tsu.mie.jp": 1,
+ "tsubame.niigata.jp": 1,
+ "tsubata.ishikawa.jp": 1,
+ "tsubetsu.hokkaido.jp": 1,
+ "tsuchiura.ibaraki.jp": 1,
+ "tsuga.tochigi.jp": 1,
+ "tsugaru.aomori.jp": 1,
+ "tsuiki.fukuoka.jp": 1,
+ "tsukigata.hokkaido.jp": 1,
+ "tsukiyono.gunma.jp": 1,
+ "tsukuba.ibaraki.jp": 1,
+ "tsukui.kanagawa.jp": 1,
+ "tsukumi.oita.jp": 1,
+ "tsumagoi.gunma.jp": 1,
+ "tsunan.niigata.jp": 1,
+ "tsuno.kochi.jp": 1,
+ "tsuno.miyazaki.jp": 1,
+ "tsuru.yamanashi.jp": 1,
+ "tsuruga.fukui.jp": 1,
+ "tsurugashima.saitama.jp": 1,
+ "tsurugi.ishikawa.jp": 1,
+ "tsuruoka.yamagata.jp": 1,
+ "tsuruta.aomori.jp": 1,
+ "tsushima.aichi.jp": 1,
+ "tsushima.nagasaki.jp": 1,
+ "tsuwano.shimane.jp": 1,
+ "tsuyama.okayama.jp": 1,
+ "tt.im": 1,
+ "tula.su": 1,
+ "tunk.org": 1,
+ "tur.ar": 1,
+ "tur.br": 1,
+ "turek.pl": 1,
+ "turen.tn": 1,
+ "turin.it": 1,
+ "turystyka.pl": 1,
+ "tuscany.it": 1,
+ "tuva.su": 1,
+ "tuxfamily.org": 1,
+ "tv.bb": 1,
+ "tv.bo": 1,
+ "tv.br": 1,
+ "tv.im": 1,
+ "tv.it": 1,
+ "tv.kg": 1,
+ "tv.na": 1,
+ "tv.sd": 1,
+ "tv.tr": 1,
+ "tv.tz": 1,
+ "tvedestrand.no": 1,
+ "tw.cn": 1,
+ "twmail.cc": 1,
+ "twmail.net": 1,
+ "twmail.org": 1,
+ "tx.us": 1,
+ "tychy.pl": 1,
+ "tydal.no": 1,
+ "tynset.no": 1,
+ "tysfjord.no": 1,
+ "tysnes.no": 1,
+ "tysvar.no": 1,
+ "tysv\u00e6r.no": 1,
+ "t\u00f8nsberg.no": 1,
+ "u.bg": 1,
+ "u.channelsdvr.net": 1,
+ "u.se": 1,
+ "u2-local.xnbay.com": 1,
+ "u2.xnbay.com": 1,
+ "ua.rs": 1,
+ "ube.yamaguchi.jp": 1,
+ "uber.space": 1,
+ "uberspace.de": 2,
+ "uchihara.ibaraki.jp": 1,
+ "uchiko.ehime.jp": 1,
+ "uchinada.ishikawa.jp": 1,
+ "uchinomi.kagawa.jp": 1,
+ "ud.it": 1,
+ "uda.nara.jp": 1,
+ "udi.br": 1,
+ "udine.it": 1,
+ "udono.mie.jp": 1,
+ "ueda.nagano.jp": 1,
+ "ueno.gunma.jp": 1,
+ "uenohara.yamanashi.jp": 1,
+ "ufcfan.org": 1,
+ "ug.gov.pl": 1,
+ "ugim.gov.pl": 1,
+ "uhren.museum": 1,
+ "ui.nabu.casa": 1,
+ "uji.kyoto.jp": 1,
+ "ujiie.tochigi.jp": 1,
+ "ujitawara.kyoto.jp": 1,
+ "uk.com": 1,
+ "uk.eu.org": 1,
+ "uk.kg": 1,
+ "uk.net": 1,
+ "uk0.bigv.io": 1,
+ "ukco.me": 1,
+ "uki.kumamoto.jp": 1,
+ "ukiha.fukuoka.jp": 1,
+ "uklugs.org": 1,
+ "ullensaker.no": 1,
+ "ullensvang.no": 1,
+ "ulm.museum": 1,
+ "ulsan.kr": 1,
+ "ulvik.no": 1,
+ "um.gov.pl": 1,
+ "umaji.kochi.jp": 1,
+ "umb.it": 1,
+ "umbria.it": 1,
+ "umi.fukuoka.jp": 1,
+ "umig.gov.pl": 1,
+ "unazuki.toyama.jp": 1,
+ "undersea.museum": 1,
+ "uni5.net": 1,
+ "union.aero": 1,
+ "univ.sn": 1,
+ "university.museum": 1,
+ "unjarga.no": 1,
+ "unj\u00e1rga.no": 1,
+ "unnan.shimane.jp": 1,
+ "unusualperson.com": 1,
+ "unzen.nagasaki.jp": 1,
+ "uonuma.niigata.jp": 1,
+ "uozu.toyama.jp": 1,
+ "upow.gov.pl": 1,
+ "uppo.gov.pl": 1,
+ "urakawa.hokkaido.jp": 1,
+ "urasoe.okinawa.jp": 1,
+ "urausu.hokkaido.jp": 1,
+ "urawa.saitama.jp": 1,
+ "urayasu.chiba.jp": 1,
+ "urbino-pesaro.it": 1,
+ "urbinopesaro.it": 1,
+ "ureshino.mie.jp": 1,
+ "uri.arpa": 1,
+ "url.tw": 1,
+ "urn.arpa": 1,
+ "urown.cloud": 1,
+ "uruma.okinawa.jp": 1,
+ "uryu.hokkaido.jp": 1,
+ "us-1.evennode.com": 1,
+ "us-2.evennode.com": 1,
+ "us-3.evennode.com": 1,
+ "us-4.evennode.com": 1,
+ "us-east-1.amazonaws.com": 1,
+ "us-east-1.elasticbeanstalk.com": 1,
+ "us-east-2.elasticbeanstalk.com": 1,
+ "us-gov-west-1.elasticbeanstalk.com": 1,
+ "us-west-1.elasticbeanstalk.com": 1,
+ "us-west-2.elasticbeanstalk.com": 1,
+ "us.ax": 1,
+ "us.com": 1,
+ "us.eu.org": 1,
+ "us.gov.pl": 1,
+ "us.kg": 1,
+ "us.na": 1,
+ "us.org": 1,
+ "us.platform.sh": 1,
+ "usa.museum": 1,
+ "usa.oita.jp": 1,
+ "usantiques.museum": 1,
+ "usarts.museum": 1,
+ "uscountryestate.museum": 1,
+ "usculture.museum": 1,
+ "usdecorativearts.museum": 1,
+ "user.aseinet.ne.jp": 1,
+ "user.party.eus": 1,
+ "user.srcf.net": 1,
+ "usercontent.jp": 1,
+ "usgarden.museum": 1,
+ "ushiku.ibaraki.jp": 1,
+ "ushistory.museum": 1,
+ "ushuaia.museum": 1,
+ "uslivinghistory.museum": 1,
+ "usr.cloud.muni.cz": 1,
+ "ustka.pl": 1,
+ "usui.fukuoka.jp": 1,
+ "usuki.oita.jp": 1,
+ "ut.us": 1,
+ "utah.museum": 1,
+ "utashinai.hokkaido.jp": 1,
+ "utazas.hu": 1,
+ "utazu.kagawa.jp": 1,
+ "uto.kumamoto.jp": 1,
+ "utsira.no": 1,
+ "utsunomiya.tochigi.jp": 1,
+ "utwente.io": 1,
+ "uvic.museum": 1,
+ "uw.gov.pl": 1,
+ "uwajima.ehime.jp": 1,
+ "uwu.ai": 1,
+ "uwu.nu": 1,
+ "uy.com": 1,
+ "uz.ua": 1,
+ "uzhgorod.ua": 1,
+ "uzs.gov.pl": 1,
+ "v-info.info": 1,
+ "v.bg": 1,
+ "v.ua": 1,
+ "va.it": 1,
+ "va.no": 1,
+ "va.us": 1,
+ "vaapste.no": 1,
+ "vadso.no": 1,
+ "vads\u00f8.no": 1,
+ "vaga.no": 1,
+ "vagan.no": 1,
+ "vagsoy.no": 1,
+ "vaksdal.no": 1,
+ "val-d-aosta.it": 1,
+ "val-daosta.it": 1,
+ "vald-aosta.it": 1,
+ "valdaosta.it": 1,
+ "valer.hedmark.no": 1,
+ "valer.ostfold.no": 1,
+ "valle-aosta.it": 1,
+ "valle-d-aosta.it": 1,
+ "valle-daosta.it": 1,
+ "valle.no": 1,
+ "valleaosta.it": 1,
+ "valled-aosta.it": 1,
+ "valledaosta.it": 1,
+ "vallee-aoste.it": 1,
+ "vallee-d-aoste.it": 1,
+ "valleeaoste.it": 1,
+ "valleedaoste.it": 1,
+ "valley.museum": 1,
+ "vall\u00e9e-aoste.it": 1,
+ "vall\u00e9e-d-aoste.it": 1,
+ "vall\u00e9eaoste.it": 1,
+ "vall\u00e9edaoste.it": 1,
+ "vang.no": 1,
+ "vantaa.museum": 1,
+ "vanylven.no": 1,
+ "vao.it": 1,
+ "vapor.cloud": 1,
+ "vaporcloud.io": 1,
+ "vardo.no": 1,
+ "vard\u00f8.no": 1,
+ "varese.it": 1,
+ "varggat.no": 1,
+ "varoy.no": 1,
+ "vb.it": 1,
+ "vc.it": 1,
+ "vda.it": 1,
+ "ve.it": 1,
+ "vefsn.no": 1,
+ "vega.no": 1,
+ "vegarshei.no": 1,
+ "veg\u00e5rshei.no": 1,
+ "ven.it": 1,
+ "veneto.it": 1,
+ "venezia.it": 1,
+ "venice.it": 1,
+ "vennesla.no": 1,
+ "verbania.it": 1,
+ "vercel.app": 1,
+ "vercel.dev": 1,
+ "vercelli.it": 1,
+ "verdal.no": 1,
+ "verona.it": 1,
+ "verran.no": 1,
+ "versailles.museum": 1,
+ "vestby.no": 1,
+ "vestnes.no": 1,
+ "vestre-slidre.no": 1,
+ "vestre-toten.no": 1,
+ "vestvagoy.no": 1,
+ "vestv\u00e5g\u00f8y.no": 1,
+ "vet.br": 1,
+ "veterinaire.fr": 1,
+ "veterinaire.km": 1,
+ "vevelstad.no": 1,
+ "vf.no": 1,
+ "vgs.no": 1,
+ "vi.it": 1,
+ "vi.us": 1,
+ "vibo-valentia.it": 1,
+ "vibovalentia.it": 1,
+ "vic.au": 1,
+ "vic.edu.au": 1,
+ "vic.gov.au": 1,
+ "vicenza.it": 1,
+ "video.hu": 1,
+ "vik.no": 1,
+ "viking.museum": 1,
+ "vikna.no": 1,
+ "village.museum": 1,
+ "vindafjord.no": 1,
+ "vinnica.ua": 1,
+ "vinnytsia.ua": 1,
+ "vip.jelastic.cloud": 1,
+ "vipsinaapp.com": 1,
+ "virginia.museum": 1,
+ "virtual-user.de": 1,
+ "virtual.museum": 1,
+ "virtualserver.io": 1,
+ "virtualuser.de": 1,
+ "virtueeldomein.nl": 1,
+ "virtuel.museum": 1,
+ "viterbo.it": 1,
+ "vix.br": 1,
+ "vlaanderen.museum": 1,
+ "vladikavkaz.ru": 1,
+ "vladikavkaz.su": 1,
+ "vladimir.ru": 1,
+ "vladimir.su": 1,
+ "vlog.br": 1,
+ "vm.bytemark.co.uk": 1,
+ "vn.ua": 1,
+ "voagat.no": 1,
+ "volda.no": 1,
+ "volkenkunde.museum": 1,
+ "vologda.su": 1,
+ "volyn.ua": 1,
+ "voorloper.cloud": 1,
+ "voss.no": 1,
+ "vossevangen.no": 1,
+ "vpndns.net": 1,
+ "vpnplus.to": 1,
+ "vps.mcdir.ru": 1,
+ "vps.myjino.ru": 2,
+ "vr.it": 1,
+ "vs.it": 1,
+ "vs.mythic-beasts.com": 1,
+ "vt.it": 1,
+ "vt.us": 1,
+ "vv.it": 1,
+ "vxl.sh": 1,
+ "v\u00e1rgg\u00e1t.no": 1,
+ "v\u00e5gan.no": 1,
+ "v\u00e5gs\u00f8y.no": 1,
+ "v\u00e5g\u00e5.no": 1,
+ "v\u00e5ler.hedmark.no": 1,
+ "v\u00e5ler.\u00f8stfold.no": 1,
+ "v\u00e6r\u00f8y.no": 1,
+ "w.bg": 1,
+ "w.se": 1,
+ "wa.au": 1,
+ "wa.edu.au": 1,
+ "wa.gov.au": 1,
+ "wa.us": 1,
+ "wada.nagano.jp": 1,
+ "wafflecell.com": 1,
+ "wajiki.tokushima.jp": 1,
+ "wajima.ishikawa.jp": 1,
+ "wakasa.fukui.jp": 1,
+ "wakasa.tottori.jp": 1,
+ "wakayama.jp": 1,
+ "wakayama.wakayama.jp": 1,
+ "wake.okayama.jp": 1,
+ "wakkanai.hokkaido.jp": 1,
+ "wakuya.miyagi.jp": 1,
+ "walbrzych.pl": 1,
+ "wales.museum": 1,
+ "wallonie.museum": 1,
+ "wanouchi.gifu.jp": 1,
+ "war.museum": 1,
+ "warabi.saitama.jp": 1,
+ "warmia.pl": 1,
+ "warszawa.pl": 1,
+ "washingtondc.museum": 1,
+ "washtenaw.mi.us": 1,
+ "wassamu.hokkaido.jp": 1,
+ "watarai.mie.jp": 1,
+ "watari.miyagi.jp": 1,
+ "watch-and-clock.museum": 1,
+ "watchandclock.museum": 1,
+ "waw.pl": 1,
+ "wazuka.kyoto.jp": 1,
+ "we.bs": 1,
+ "we.tc": 1,
+ "web.app": 1,
+ "web.bo": 1,
+ "web.co": 1,
+ "web.do": 1,
+ "web.gu": 1,
+ "web.id": 1,
+ "web.in": 1,
+ "web.lk": 1,
+ "web.nf": 1,
+ "web.ni": 1,
+ "web.pk": 1,
+ "web.tj": 1,
+ "web.tr": 1,
+ "web.ve": 1,
+ "web.za": 1,
+ "webhare.dev": 2,
+ "webhop.biz": 1,
+ "webhop.info": 1,
+ "webhop.me": 1,
+ "webhop.net": 1,
+ "webhop.org": 1,
+ "webhosting.be": 1,
+ "webredirect.org": 1,
+ "website.yandexcloud.net": 1,
+ "webspace.rocks": 1,
+ "wedeploy.io": 1,
+ "wedeploy.me": 1,
+ "wedeploy.sh": 1,
+ "wegrow.pl": 1,
+ "wellbeingzone.co.uk": 1,
+ "wellbeingzone.eu": 1,
+ "western.museum": 1,
+ "westfalen.museum": 1,
+ "whaling.museum": 1,
+ "wi.us": 1,
+ "wielun.pl": 1,
+ "wien.funkfeuer.at": 1,
+ "wif.gov.pl": 1,
+ "wiih.gov.pl": 1,
+ "wiki.bo": 1,
+ "wiki.br": 1,
+ "wildlife.museum": 1,
+ "williamsburg.museum": 1,
+ "winb.gov.pl": 1,
+ "windmill.museum": 1,
+ "wios.gov.pl": 1,
+ "witd.gov.pl": 1,
+ "withgoogle.com": 1,
+ "withyoutube.com": 1,
+ "wiw.gov.pl": 1,
+ "wlocl.pl": 1,
+ "wloclawek.pl": 1,
+ "wmcloud.org": 1,
+ "wmflabs.org": 1,
+ "wnext.app": 1,
+ "wodzislaw.pl": 1,
+ "wolomin.pl": 1,
+ "workers.dev": 1,
+ "workinggroup.aero": 1,
+ "workisboring.com": 1,
+ "works.aero": 1,
+ "workshop.museum": 1,
+ "worse-than.tv": 1,
+ "wpdevcloud.com": 1,
+ "wpenginepowered.com": 1,
+ "writesthisblog.com": 1,
+ "wroc.pl": 1,
+ "wroclaw.pl": 1,
+ "ws.na": 1,
+ "wsa.gov.pl": 1,
+ "wskr.gov.pl": 1,
+ "wuoz.gov.pl": 1,
+ "wv.us": 1,
+ "www.ck": 0,
+ "www.ro": 1,
+ "wy.us": 1,
+ "wzmiuw.gov.pl": 1,
+ "x.bg": 1,
+ "x.mythic-beasts.com": 1,
+ "x.se": 1,
+ "x443.pw": 1,
+ "xen.prgmr.com": 1,
+ "xenapponazure.com": 1,
+ "xj.cn": 1,
+ "xnbay.com": 1,
+ "xs4all.space": 1,
+ "xx.gl": 1,
+ "xy.ax": 1,
+ "xz.cn": 1,
+ "y.bg": 1,
+ "y.se": 1,
+ "yabu.hyogo.jp": 1,
+ "yabuki.fukushima.jp": 1,
+ "yachimata.chiba.jp": 1,
+ "yachiyo.chiba.jp": 1,
+ "yachiyo.ibaraki.jp": 1,
+ "yaese.okinawa.jp": 1,
+ "yahaba.iwate.jp": 1,
+ "yahiko.niigata.jp": 1,
+ "yaita.tochigi.jp": 1,
+ "yaizu.shizuoka.jp": 1,
+ "yakage.okayama.jp": 1,
+ "yakumo.hokkaido.jp": 1,
+ "yakumo.shimane.jp": 1,
+ "yali.mythic-beasts.com": 1,
+ "yalta.ua": 1,
+ "yamada.fukuoka.jp": 1,
+ "yamada.iwate.jp": 1,
+ "yamada.toyama.jp": 1,
+ "yamaga.kumamoto.jp": 1,
+ "yamagata.gifu.jp": 1,
+ "yamagata.ibaraki.jp": 1,
+ "yamagata.jp": 1,
+ "yamagata.nagano.jp": 1,
+ "yamagata.yamagata.jp": 1,
+ "yamaguchi.jp": 1,
+ "yamakita.kanagawa.jp": 1,
+ "yamamoto.miyagi.jp": 1,
+ "yamanakako.yamanashi.jp": 1,
+ "yamanashi.jp": 1,
+ "yamanashi.yamanashi.jp": 1,
+ "yamanobe.yamagata.jp": 1,
+ "yamanouchi.nagano.jp": 1,
+ "yamashina.kyoto.jp": 1,
+ "yamato.fukushima.jp": 1,
+ "yamato.kanagawa.jp": 1,
+ "yamato.kumamoto.jp": 1,
+ "yamatokoriyama.nara.jp": 1,
+ "yamatotakada.nara.jp": 1,
+ "yamatsuri.fukushima.jp": 1,
+ "yamazoe.nara.jp": 1,
+ "yame.fukuoka.jp": 1,
+ "yanagawa.fukuoka.jp": 1,
+ "yanaizu.fukushima.jp": 1,
+ "yandexcloud.net": 1,
+ "yao.osaka.jp": 1,
+ "yaotsu.gifu.jp": 1,
+ "yasaka.nagano.jp": 1,
+ "yashio.saitama.jp": 1,
+ "yashiro.hyogo.jp": 1,
+ "yasu.shiga.jp": 1,
+ "yasuda.kochi.jp": 1,
+ "yasugi.shimane.jp": 1,
+ "yasuoka.nagano.jp": 1,
+ "yatomi.aichi.jp": 1,
+ "yatsuka.shimane.jp": 1,
+ "yatsushiro.kumamoto.jp": 1,
+ "yawara.ibaraki.jp": 1,
+ "yawata.kyoto.jp": 1,
+ "yawatahama.ehime.jp": 1,
+ "yazu.tottori.jp": 1,
+ "ybo.faith": 1,
+ "ybo.party": 1,
+ "ybo.review": 1,
+ "ybo.science": 1,
+ "ybo.trade": 1,
+ "ye": 2,
+ "yk.ca": 1,
+ "yn.cn": 1,
+ "yoichi.hokkaido.jp": 1,
+ "yoita.niigata.jp": 1,
+ "yoka.hyogo.jp": 1,
+ "yokaichiba.chiba.jp": 1,
+ "yokawa.hyogo.jp": 1,
+ "yokkaichi.mie.jp": 1,
+ "yokohama.jp": 2,
+ "yokoshibahikari.chiba.jp": 1,
+ "yokosuka.kanagawa.jp": 1,
+ "yokote.akita.jp": 1,
+ "yokoze.saitama.jp": 1,
+ "yolasite.com": 1,
+ "yombo.me": 1,
+ "yomitan.okinawa.jp": 1,
+ "yonabaru.okinawa.jp": 1,
+ "yonago.tottori.jp": 1,
+ "yonaguni.okinawa.jp": 1,
+ "yonezawa.yamagata.jp": 1,
+ "yono.saitama.jp": 1,
+ "yorii.saitama.jp": 1,
+ "york.museum": 1,
+ "yorkshire.museum": 1,
+ "yoro.gifu.jp": 1,
+ "yosemite.museum": 1,
+ "yoshida.saitama.jp": 1,
+ "yoshida.shizuoka.jp": 1,
+ "yoshikawa.saitama.jp": 1,
+ "yoshimi.saitama.jp": 1,
+ "yoshino.nara.jp": 1,
+ "yoshinogari.saga.jp": 1,
+ "yoshioka.gunma.jp": 1,
+ "yotsukaido.chiba.jp": 1,
+ "youth.museum": 1,
+ "yuasa.wakayama.jp": 1,
+ "yufu.oita.jp": 1,
+ "yugawa.fukushima.jp": 1,
+ "yugawara.kanagawa.jp": 1,
+ "yuki.ibaraki.jp": 1,
+ "yukuhashi.fukuoka.jp": 1,
+ "yura.wakayama.jp": 1,
+ "yurihonjo.akita.jp": 1,
+ "yusuhara.kochi.jp": 1,
+ "yusui.kagoshima.jp": 1,
+ "yuu.yamaguchi.jp": 1,
+ "yuza.yamagata.jp": 1,
+ "yuzawa.niigata.jp": 1,
+ "z.bg": 1,
+ "z.se": 1,
+ "za.bz": 1,
+ "za.com": 1,
+ "za.net": 1,
+ "za.org": 1,
+ "zachpomor.pl": 1,
+ "zagan.pl": 1,
+ "zakopane.pl": 1,
+ "zama.kanagawa.jp": 1,
+ "zamami.okinawa.jp": 1,
+ "zao.miyagi.jp": 1,
+ "zaporizhzhe.ua": 1,
+ "zaporizhzhia.ua": 1,
+ "zapto.org": 1,
+ "zapto.xyz": 1,
+ "zarow.pl": 1,
+ "zentsuji.kagawa.jp": 1,
+ "zgora.pl": 1,
+ "zgorzelec.pl": 1,
+ "zhitomir.ua": 1,
+ "zhytomyr.ua": 1,
+ "zj.cn": 1,
+ "zlg.br": 1,
+ "zoological.museum": 1,
+ "zoology.museum": 1,
+ "zp.gov.pl": 1,
+ "zp.ua": 1,
+ "zt.ua": 1,
+ "zushi.kanagawa.jp": 1,
+ "\u00e1k\u014boluokta.no": 1,
+ "\u00e1laheadju.no": 1,
+ "\u00e1lt\u00e1.no": 1,
+ "\u00e5fjord.no": 1,
+ "\u00e5krehamn.no": 1,
+ "\u00e5l.no": 1,
+ "\u00e5lesund.no": 1,
+ "\u00e5lg\u00e5rd.no": 1,
+ "\u00e5mli.no": 1,
+ "\u00e5mot.no": 1,
+ "\u00e5rdal.no": 1,
+ "\u00e5s.no": 1,
+ "\u00e5seral.no": 1,
+ "\u00e5snes.no": 1,
+ "\u00f8ksnes.no": 1,
+ "\u00f8rland.no": 1,
+ "\u00f8rskog.no": 1,
+ "\u00f8rsta.no": 1,
+ "\u00f8stre-toten.no": 1,
+ "\u00f8vre-eiker.no": 1,
+ "\u00f8yer.no": 1,
+ "\u00f8ygarden.no": 1,
+ "\u00f8ystre-slidre.no": 1,
+ "\u010d\u00e1hcesuolo.no": 1,
+ "\u0430\u043a.\u0441\u0440\u0431": 1,
+ "\u0438\u043a\u043e\u043c.museum": 1,
+ "\u043e\u0431\u0440.\u0441\u0440\u0431": 1,
+ "\u043e\u0434.\u0441\u0440\u0431": 1,
+ "\u043e\u0440\u0433.\u0441\u0440\u0431": 1,
+ "\u043f\u0440.\u0441\u0440\u0431": 1,
+ "\u0443\u043f\u0440.\u0441\u0440\u0431": 1,
+ "\u05d9\u05e8\u05d5\u05e9\u05dc\u05d9\u05dd.museum": 1,
+ "\u0627\u064a\u0631\u0627\u0646.ir": 1,
+ "\u0627\u06cc\u0631\u0627\u0646.ir": 1,
+ "\u0e17\u0e2b\u0e32\u0e23.\u0e44\u0e17\u0e22": 1,
+ "\u0e18\u0e38\u0e23\u0e01\u0e34\u0e08.\u0e44\u0e17\u0e22": 1,
+ "\u0e23\u0e31\u0e10\u0e1a\u0e32\u0e25.\u0e44\u0e17\u0e22": 1,
+ "\u0e28\u0e36\u0e01\u0e29\u0e32.\u0e44\u0e17\u0e22": 1,
+ "\u0e2d\u0e07\u0e04\u0e4c\u0e01\u0e23.\u0e44\u0e17\u0e22": 1,
+ "\u0e40\u0e19\u0e47\u0e15.\u0e44\u0e17\u0e22": 1,
+ "\u4e09\u91cd.jp": 1,
+ "\u4e2a\u4eba.hk": 1,
+ "\u4eac\u90fd.jp": 1,
+ "\u4f50\u8cc0.jp": 1,
+ "\u500b\u4eba.hk": 1,
+ "\u500b\u4eba.\u9999\u6e2f": 1,
+ "\u516c\u53f8.cn": 1,
+ "\u516c\u53f8.hk": 1,
+ "\u516c\u53f8.\u9999\u6e2f": 1,
+ "\u5175\u5eab.jp": 1,
+ "\u5317\u6d77\u9053.jp": 1,
+ "\u5343\u8449.jp": 1,
+ "\u548c\u6b4c\u5c71.jp": 1,
+ "\u5546\u696d.tw": 1,
+ "\u57fc\u7389.jp": 1,
+ "\u5927\u5206.jp": 1,
+ "\u5927\u962a.jp": 1,
+ "\u5948\u826f.jp": 1,
+ "\u5bae\u57ce.jp": 1,
+ "\u5bae\u5d0e.jp": 1,
+ "\u5bcc\u5c71.jp": 1,
+ "\u5c71\u53e3.jp": 1,
+ "\u5c71\u5f62.jp": 1,
+ "\u5c71\u68a8.jp": 1,
+ "\u5c90\u961c.jp": 1,
+ "\u5ca1\u5c71.jp": 1,
+ "\u5ca9\u624b.jp": 1,
+ "\u5cf6\u6839.jp": 1,
+ "\u5e83\u5cf6.jp": 1,
+ "\u5fb3\u5cf6.jp": 1,
+ "\u611b\u5a9b.jp": 1,
+ "\u611b\u77e5.jp": 1,
+ "\u653f\u5e9c.hk": 1,
+ "\u653f\u5e9c.\u9999\u6e2f": 1,
+ "\u654e\u80b2.hk": 1,
+ "\u6559\u80b2.hk": 1,
+ "\u6559\u80b2.\u9999\u6e2f": 1,
+ "\u65b0\u6f5f.jp": 1,
+ "\u6771\u4eac.jp": 1,
+ "\u6803\u6728.jp": 1,
+ "\u6c96\u7e04.jp": 1,
+ "\u6ecb\u8cc0.jp": 1,
+ "\u718a\u672c.jp": 1,
+ "\u77f3\u5ddd.jp": 1,
+ "\u795e\u5948\u5ddd.jp": 1,
+ "\u798f\u4e95.jp": 1,
+ "\u798f\u5ca1.jp": 1,
+ "\u798f\u5cf6.jp": 1,
+ "\u79cb\u7530.jp": 1,
+ "\u7b87\u4eba.hk": 1,
+ "\u7d44\u7e54.hk": 1,
+ "\u7d44\u7e54.tw": 1,
+ "\u7d44\u7e54.\u9999\u6e2f": 1,
+ "\u7d44\u7ec7.hk": 1,
+ "\u7db2\u7d61.cn": 1,
+ "\u7db2\u7d61.hk": 1,
+ "\u7db2\u7d61.\u9999\u6e2f": 1,
+ "\u7db2\u7edc.hk": 1,
+ "\u7db2\u8def.tw": 1,
+ "\u7ec4\u7e54.hk": 1,
+ "\u7ec4\u7ec7.hk": 1,
+ "\u7f51\u7d61.hk": 1,
+ "\u7f51\u7edc.cn": 1,
+ "\u7f51\u7edc.hk": 1,
+ "\u7fa4\u99ac.jp": 1,
+ "\u8328\u57ce.jp": 1,
+ "\u9577\u5d0e.jp": 1,
+ "\u9577\u91ce.jp": 1,
+ "\u9752\u68ee.jp": 1,
+ "\u9759\u5ca1.jp": 1,
+ "\u9999\u5ddd.jp": 1,
+ "\u9ad8\u77e5.jp": 1,
+ "\u9ce5\u53d6.jp": 1,
+ "\u9e7f\u5150\u5cf6.jp": 1
+};
diff --git a/src/lib/vendor/jquery-3.5.1.js b/src/lib/vendor/jquery-3.5.1.js
new file mode 100644
index 0000000..5093733
--- /dev/null
+++ b/src/lib/vendor/jquery-3.5.1.js
@@ -0,0 +1,10872 @@
+/*!
+ * jQuery JavaScript Library v3.5.1
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2020-05-04T22:49Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+ return arr.flat.call( array );
+} : function( array ) {
+ return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML <object> elements
+ // (i.e., `typeof document.createElement( "object" ) === "function"`).
+ // We don't want to classify *any* DOM node as a function.
+ return typeof obj === "function" && typeof obj.nodeType !== "number";
+ };
+
+
+var isWindow = function isWindow( obj ) {
+ return obj != null && obj === obj.window;
+ };
+
+
+var document = window.document;
+
+
+
+ var preservedScriptAttributes = {
+ type: true,
+ src: true,
+ nonce: true,
+ noModule: true
+ };
+
+ function DOMEval( code, node, doc ) {
+ doc = doc || document;
+
+ var i, val,
+ script = doc.createElement( "script" );
+
+ script.text = code;
+ if ( node ) {
+ for ( i in preservedScriptAttributes ) {
+
+ // Support: Firefox 64+, Edge 18+
+ // Some browsers don't support the "nonce" property on scripts.
+ // On the other hand, just using `getAttribute` is not enough as
+ // the `nonce` attribute is reset to an empty string whenever it
+ // becomes browsing-context connected.
+ // See https://github.com/whatwg/html/issues/2369
+ // See https://html.spec.whatwg.org/#nonce-attributes
+ // The `node.getAttribute` check was added for the sake of
+ // `jQuery.globalEval` so that it can fake a nonce-containing node
+ // via an object.
+ val = node[ i ] || node.getAttribute && node.getAttribute( i );
+ if ( val ) {
+ script.setAttribute( i, val );
+ }
+ }
+ }
+ doc.head.appendChild( script ).parentNode.removeChild( script );
+ }
+
+
+function toType( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+
+ // Support: Android <=2.3 only (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+}
+/* global Symbol */
+// Defining this global in .eslintrc.json would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
+
+
+
+var
+ version = "3.5.1",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ };
+
+jQuery.fn = jQuery.prototype = {
+
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+
+ // Return all the elements in a clean array
+ if ( num == null ) {
+ return slice.call( this );
+ }
+
+ // Return just the one element from the set
+ return num < 0 ? this[ num + this.length ] : this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ each: function( callback ) {
+ return jQuery.each( this, callback );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ } ) );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ even: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return ( i + 1 ) % 2;
+ } ) );
+ },
+
+ odd: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return i % 2;
+ } ) );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor();
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: arr.sort,
+ splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[ 0 ] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !isFunction( target ) ) {
+ target = {};
+ }
+
+ // Extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+
+ // Only deal with non-null/undefined values
+ if ( ( options = arguments[ i ] ) != null ) {
+
+ // Extend the base object
+ for ( name in options ) {
+ copy = options[ name ];
+
+ // Prevent Object.prototype pollution
+ // Prevent never-ending loop
+ if ( name === "__proto__" || target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = Array.isArray( copy ) ) ) ) {
+ src = target[ name ];
+
+ // Ensure proper type for the source value
+ if ( copyIsArray && !Array.isArray( src ) ) {
+ clone = [];
+ } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
+ clone = {};
+ } else {
+ clone = src;
+ }
+ copyIsArray = false;
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend( {
+
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ isPlainObject: function( obj ) {
+ var proto, Ctor;
+
+ // Detect obvious negatives
+ // Use toString instead of jQuery.type to catch host objects
+ if ( !obj || toString.call( obj ) !== "[object Object]" ) {
+ return false;
+ }
+
+ proto = getProto( obj );
+
+ // Objects with no prototype (e.g., `Object.create( null )`) are plain
+ if ( !proto ) {
+ return true;
+ }
+
+ // Objects with prototype are plain iff they were constructed by a global Object function
+ Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+ return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ // Evaluates a script in a provided context; falls back to the global one
+ // if not specified.
+ globalEval: function( code, options, doc ) {
+ DOMEval( code, { nonce: options && options.nonce }, doc );
+ },
+
+ each: function( obj, callback ) {
+ var length, i = 0;
+
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArrayLike( Object( arr ) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
+ },
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var length, value,
+ i = 0,
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return flat( ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+} );
+
+if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
+
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( _i, name ) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+} );
+
+function isArrayLike( obj ) {
+
+ // Support: real iOS 8.2 only (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
+ type = toType( obj );
+
+ if ( isFunction( obj ) || isWindow( obj ) ) {
+ return false;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.3.5
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://js.foundation/
+ *
+ * Date: 2020-03-14
+ */
+( function( window ) {
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ nonnativeSelectorCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // Instance methods
+ hasOwn = ( {} ).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ pushNative = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+
+ // Use a stripped-down indexOf as it's faster than native
+ // https://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[ i ] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
+ "ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
+ identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
+ "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+
+ // "Attribute values must be CSS identifiers [capture 5]
+ // or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
+ whitespace + "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
+ whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
+ "*" ),
+ rdescend = new RegExp( whitespace + "|>" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+ whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+ whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace +
+ "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rhtml = /HTML$/i,
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+
+ // CSS escapes
+ // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+ funescape = function( escape, nonHex ) {
+ var high = "0x" + escape.slice( 1 ) - 0x10000;
+
+ return nonHex ?
+
+ // Strip the backslash prefix from a non-hex escape sequence
+ nonHex :
+
+ // Replace a hexadecimal escape sequence with the encoded Unicode code point
+ // Support: IE <=11+
+ // For values outside the Basic Multilingual Plane (BMP), manually construct a
+ // surrogate pair
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // CSS string/identifier serialization
+ // https://drafts.csswg.org/cssom/#common-serializing-idioms
+ rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
+ fcssescape = function( ch, asCodePoint ) {
+ if ( asCodePoint ) {
+
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+ if ( ch === "\0" ) {
+ return "\uFFFD";
+ }
+
+ // Control characters and (dependent upon position) numbers get escaped as code points
+ return ch.slice( 0, -1 ) + "\\" +
+ ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ }
+
+ // Other potentially-special ASCII characters get backslash-escaped
+ return "\\" + ch;
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ },
+
+ inDisabledFieldset = addCombinator(
+ function( elem ) {
+ return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
+ },
+ { dir: "parentNode", next: "legend" }
+ );
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ ( arr = slice.call( preferredDoc.childNodes ) ),
+ preferredDoc.childNodes
+ );
+
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ // eslint-disable-next-line no-unused-expressions
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ pushNative.apply( target, slice.call( els ) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+
+ // Can't trust NodeList.length
+ while ( ( target[ j++ ] = els[ i++ ] ) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var m, i, elem, nid, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
+
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
+
+ results = results || [];
+
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
+ setDocument( context );
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
+
+ // ID selector
+ if ( ( m = match[ 1 ] ) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( ( elem = context.getElementById( m ) ) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+
+ // Element context
+ } else {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && ( elem = newContext.getElementById( m ) ) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Type selector
+ } else if ( match[ 2 ] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Class selector
+ } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !nonnativeSelectorCache[ selector + " " ] &&
+ ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
+
+ // Support: IE 8 only
+ // Exclude object elements
+ ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
+
+ newSelector = selector;
+ newContext = context;
+
+ // qSA considers elements outside a scoping root when evaluating child or
+ // descendant combinators, which is not what we want.
+ // In such cases, we work around the behavior by prefixing every selector in the
+ // list with an ID selector referencing the scope context.
+ // The technique has to be used as well when a leading combinator is used
+ // as such selectors are not recognized by querySelectorAll.
+ // Thanks to Andrew Dupont for this technique.
+ if ( nodeType === 1 &&
+ ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+
+ // We can use :scope instead of the ID hack if the browser
+ // supports it & if we're not changing the context.
+ if ( newContext !== context || !support.scope ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( ( nid = context.getAttribute( "id" ) ) ) {
+ nid = nid.replace( rcssescape, fcssescape );
+ } else {
+ context.setAttribute( "id", ( nid = expando ) );
+ }
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ while ( i-- ) {
+ groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+ toSelector( groups[ i ] );
+ }
+ newSelector = groups.join( "," );
+ }
+
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ nonnativeSelectorCache( selector, true );
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return ( cache[ key + " " ] = value );
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created element and returns a boolean result
+ */
+function assert( fn ) {
+ var el = document.createElement( "fieldset" );
+
+ try {
+ return !!fn( el );
+ } catch ( e ) {
+ return false;
+ } finally {
+
+ // Remove from its parent by default
+ if ( el.parentNode ) {
+ el.parentNode.removeChild( el );
+ }
+
+ // release memory in IE
+ el = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split( "|" ),
+ i = arr.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[ i ] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ a.sourceIndex - b.sourceIndex;
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( ( cur = cur.nextSibling ) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return ( name === "input" || name === "button" ) && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+
+ // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+ return function( elem ) {
+
+ // Only certain elements can match :enabled or :disabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
+ if ( "form" in elem ) {
+
+ // Check for inherited disabledness on relevant non-disabled elements:
+ // * listed form-associated elements in a disabled fieldset
+ // https://html.spec.whatwg.org/multipage/forms.html#category-listed
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
+ // * option elements in a disabled optgroup
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
+ // All such elements have a "form" property.
+ if ( elem.parentNode && elem.disabled === false ) {
+
+ // Option elements defer to a parent optgroup if present
+ if ( "label" in elem ) {
+ if ( "label" in elem.parentNode ) {
+ return elem.parentNode.disabled === disabled;
+ } else {
+ return elem.disabled === disabled;
+ }
+ }
+
+ // Support: IE 6 - 11
+ // Use the isDisabled shortcut property to check for disabled fieldset ancestors
+ return elem.isDisabled === disabled ||
+
+ // Where there is no isDisabled, check manually
+ /* jshint -W018 */
+ elem.isDisabled !== !disabled &&
+ inDisabledFieldset( elem ) === disabled;
+ }
+
+ return elem.disabled === disabled;
+
+ // Try to winnow out elements that can't be disabled before trusting the disabled property.
+ // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
+ // even exist on them, let alone have a boolean value.
+ } else if ( "label" in elem ) {
+ return elem.disabled === disabled;
+ }
+
+ // Remaining elements are neither :enabled nor :disabled
+ return false;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction( function( argument ) {
+ argument = +argument;
+ return markFunction( function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
+ seed[ j ] = !( matches[ j ] = seed[ j ] );
+ }
+ }
+ } );
+ } );
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ var namespace = elem.namespaceURI,
+ docElem = ( elem.ownerDocument || elem ).documentElement;
+
+ // Support: IE <=8
+ // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
+ // https://bugs.jquery.com/ticket/4833
+ return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, subWindow,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // Return early if doc is invalid or already selected
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Update global variables
+ document = doc;
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9 - 11+, Edge 12 - 18+
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( preferredDoc != document &&
+ ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
+
+ // Support: IE 11, Edge
+ if ( subWindow.addEventListener ) {
+ subWindow.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( subWindow.attachEvent ) {
+ subWindow.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
+ // Safari 4 - 5 only, Opera <=11.6 - 12.x only
+ // IE/Edge & older browsers don't support the :scope pseudo-class.
+ // Support: Safari 6.0 only
+ // Safari 6.0 supports :scope but it's an alias of :root there.
+ support.scope = assert( function( el ) {
+ docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
+ return typeof el.querySelectorAll !== "undefined" &&
+ !el.querySelectorAll( ":scope fieldset div" ).length;
+ } );
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert( function( el ) {
+ el.className = "i";
+ return !el.getAttribute( "className" );
+ } );
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert( function( el ) {
+ el.appendChild( document.createComment( "" ) );
+ return !el.getElementsByTagName( "*" ).length;
+ } );
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programmatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert( function( el ) {
+ docElem.appendChild( el ).id = expando;
+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
+ } );
+
+ // ID filter and find
+ if ( support.getById ) {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute( "id" ) === attrId;
+ };
+ };
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var elem = context.getElementById( id );
+ return elem ? [ elem ] : [];
+ }
+ };
+ } else {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" &&
+ elem.getAttributeNode( "id" );
+ return node && node.value === attrId;
+ };
+ };
+
+ // Support: IE 6 - 7 only
+ // getElementById is not reliable as a find shortcut
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var node, i, elems,
+ elem = context.getElementById( id );
+
+ if ( elem ) {
+
+ // Verify the id attribute
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+
+ // Fall back on getElementsByName
+ elems = context.getElementsByName( id );
+ i = 0;
+ while ( ( elem = elems[ i++ ] ) ) {
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+ }
+ }
+
+ return [];
+ }
+ };
+ }
+
+ // Tag
+ Expr.find[ "TAG" ] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See https://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert( function( el ) {
+
+ var input;
+
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // https://bugs.jquery.com/ticket/12359
+ docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+ "<option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !el.querySelectorAll( "[selected]" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push( "~=" );
+ }
+
+ // Support: IE 11+, Edge 15 - 18+
+ // IE 11/Edge don't find elements on a `[name='']` query in some cases.
+ // Adding a temporary attribute to the document before the selection works
+ // around the issue.
+ // Interestingly, IE 10 & older don't seem to have the issue.
+ input = document.createElement( "input" );
+ input.setAttribute( "name", "" );
+ el.appendChild( input );
+ if ( !el.querySelectorAll( "[name='']" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+ whitespace + "*(?:''|\"\")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !el.querySelectorAll( ":checked" ).length ) {
+ rbuggyQSA.push( ":checked" );
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibling-combinator selector` fails
+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push( ".#.+[+~]" );
+ }
+
+ // Support: Firefox <=3.6 - 5 only
+ // Old Firefox doesn't throw on a badly-escaped identifier.
+ el.querySelectorAll( "\\\f" );
+ rbuggyQSA.push( "[\\r\\n\\f]" );
+ } );
+
+ assert( function( el ) {
+ el.innerHTML = "<a href='' disabled='disabled'></a>" +
+ "<select disabled='disabled'><option/></select>";
+
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = document.createElement( "input" );
+ input.setAttribute( "type", "hidden" );
+ el.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( el.querySelectorAll( "[name=d]" ).length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: IE9-11+
+ // IE's :disabled selector does not pick up the children of disabled fieldsets
+ docElem.appendChild( el ).disabled = true;
+ if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: Opera 10 - 11 only
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ el.querySelectorAll( "*,:x" );
+ rbuggyQSA.push( ",.*:" );
+ } );
+ }
+
+ if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector ) ) ) ) {
+
+ assert( function( el ) {
+
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( el, "*" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( el, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ } );
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully self-exclusive
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ) );
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( ( b = b.parentNode ) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
+
+ // Choose the first element that is related to our preferred document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( a == document || a.ownerDocument == preferredDoc &&
+ contains( preferredDoc, a ) ) {
+ return -1;
+ }
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( b == document || b.ownerDocument == preferredDoc &&
+ contains( preferredDoc, b ) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ return a == document ? -1 :
+ b == document ? 1 :
+ /* eslint-enable eqeqeq */
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( ( cur = cur.parentNode ) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( ( cur = cur.parentNode ) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[ i ] === bp[ i ] ) {
+ i++;
+ }
+
+ return i ?
+
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[ i ], bp[ i ] ) :
+
+ // Otherwise nodes in our document sort first
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ ap[ i ] == preferredDoc ? -1 :
+ bp[ i ] == preferredDoc ? 1 :
+ /* eslint-enable eqeqeq */
+ 0;
+ };
+
+ return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ setDocument( elem );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ !nonnativeSelectorCache[ expr + " " ] &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch ( e ) {
+ nonnativeSelectorCache( expr, true );
+ }
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( context.ownerDocument || context ) != document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( elem.ownerDocument || elem ) != document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.escape = function( sel ) {
+ return ( sel + "" ).replace( rcssescape, fcssescape );
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+
+ // If no nodeType, this is expected to be an array
+ while ( ( node = elem[ i++ ] ) ) {
+
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[ 1 ] = match[ 1 ].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
+ match[ 5 ] || "" ).replace( runescape, funescape );
+
+ if ( match[ 2 ] === "~=" ) {
+ match[ 3 ] = " " + match[ 3 ] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[ 1 ] = match[ 1 ].toLowerCase();
+
+ if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
+
+ // nth-* requires argument
+ if ( !match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[ 4 ] = +( match[ 4 ] ?
+ match[ 5 ] + ( match[ 6 ] || 1 ) :
+ 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+ match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[ 6 ] && match[ 2 ];
+
+ if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[ 3 ] ) {
+ match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+
+ // Get excess from tokenize (recursively)
+ ( excess = tokenize( unquoted, true ) ) &&
+
+ // advance to the next closing parenthesis
+ ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
+
+ // excess is a negative index
+ match[ 0 ] = match[ 0 ].slice( 0, excess );
+ match[ 2 ] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() {
+ return true;
+ } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ ( pattern = new RegExp( "(^|" + whitespace +
+ ")" + className + "(" + whitespace + "|$)" ) ) && classCache(
+ className, function( elem ) {
+ return pattern.test(
+ typeof elem.className === "string" && elem.className ||
+ typeof elem.getAttribute !== "undefined" &&
+ elem.getAttribute( "class" ) ||
+ ""
+ );
+ } );
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ /* eslint-disable max-len */
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ /* eslint-enable max-len */
+
+ };
+ },
+
+ "CHILD": function( type, what, _argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, _context, xml ) {
+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType,
+ diff = false;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( ( node = node[ dir ] ) ) {
+ if ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) {
+
+ return false;
+ }
+ }
+
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+
+ // Seek `elem` from a previously-cached index
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && cache[ 2 ];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ } else {
+
+ // Use previously-cached element index if available
+ if ( useCache ) {
+
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+
+ // Use the same loop as above to seek `elem` from the start
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ if ( ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) &&
+ ++diff ) {
+
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ outerCache = node[ expando ] ||
+ ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ uniqueCache[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction( function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[ i ] );
+ seed[ idx ] = !( matches[ idx ] = matched[ i ] );
+ }
+ } ) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+
+ // Potentially complex pseudos
+ "not": markFunction( function( selector ) {
+
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction( function( seed, matches, _context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ seed[ i ] = !( matches[ i ] = elem );
+ }
+ }
+ } ) :
+ function( elem, _context, xml ) {
+ input[ 0 ] = elem;
+ matcher( input, null, xml, results );
+
+ // Don't keep the element (issue #299)
+ input[ 0 ] = null;
+ return !results.pop();
+ };
+ } ),
+
+ "has": markFunction( function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ } ),
+
+ "contains": markFunction( function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
+ };
+ } ),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+
+ // lang value must be a valid identifier
+ if ( !ridentifier.test( lang || "" ) ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( ( elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
+ return false;
+ };
+ } ),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement &&
+ ( !document.hasFocus || document.hasFocus() ) &&
+ !!( elem.type || elem.href || ~elem.tabIndex );
+ },
+
+ // Boolean properties
+ "enabled": createDisabledPseudo( false ),
+ "disabled": createDisabledPseudo( true ),
+
+ "checked": function( elem ) {
+
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return ( nodeName === "input" && !!elem.checked ) ||
+ ( nodeName === "option" && !!elem.selected );
+ },
+
+ "selected": function( elem ) {
+
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ // eslint-disable-next-line no-unused-expressions
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos[ "empty" ]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( ( attr = elem.getAttribute( "type" ) ) == null ||
+ attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo( function() {
+ return [ 0 ];
+ } ),
+
+ "last": createPositionalPseudo( function( _matchIndexes, length ) {
+ return [ length - 1 ];
+ } ),
+
+ "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ } ),
+
+ "even": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "odd": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ?
+ argument + length :
+ argument > length ?
+ length :
+ argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } )
+ }
+};
+
+Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
+ if ( match ) {
+
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[ 0 ].length ) || soFar;
+ }
+ groups.push( ( tokens = [] ) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( ( match = rcombinators.exec( soFar ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+
+ // Cast descendant combinators to space
+ type: match[ 0 ].replace( rtrim, " " )
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
+ ( match = preFilters[ type ]( match ) ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+ type: type,
+ matches: match
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[ i ].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ skip = combinator.next,
+ key = skip || dir,
+ checkNonElements = base && key === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ return false;
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, uniqueCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
+ if ( xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] ||
+ ( outerCache[ elem.uniqueID ] = {} );
+
+ if ( skip && skip === elem.nodeName.toLowerCase() ) {
+ elem = elem[ dir ] || elem;
+ } else if ( ( oldCache = uniqueCache[ key ] ) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return ( newCache[ 2 ] = oldCache[ 2 ] );
+ } else {
+
+ // Reuse newcache so results back-propagate to previous elements
+ uniqueCache[ key ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[ i ]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[ 0 ];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[ i ], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction( function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts(
+ selector || "*",
+ context.nodeType ? [ context ] : context,
+ []
+ ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( ( elem = temp[ i ] ) ) {
+ matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) ) {
+
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( ( matcherIn[ i ] = elem ) );
+ }
+ }
+ postFinder( null, ( matcherOut = [] ), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) &&
+ ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
+
+ seed[ temp ] = !( results[ temp ] = elem );
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ } );
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[ 0 ].type ],
+ implicitRelative = leadingRelative || Expr.relative[ " " ],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ ( checkContext = context ).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[ j ].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens
+ .slice( 0, i - 1 )
+ .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
+ len = elems.length;
+
+ if ( outermost ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ outermostContext = context == document || context || outermost;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( !context && elem.ownerDocument != document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
+ while ( ( matcher = elementMatchers[ j++ ] ) ) {
+ if ( matcher( elem, context || document, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+
+ // They will have gone through all possible matchers
+ if ( ( elem = !matcher && elem ) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
+ matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( ( matcher = setMatchers[ j++ ] ) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
+ setMatched[ i ] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[ i ] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache(
+ selector,
+ matcherFromGroupMatchers( elementMatchers, setMatchers )
+ );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( ( selector = compiled.selector || selector ) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
+ if ( match.length === 1 ) {
+
+ // Reduce context if the leading compound selector is an ID
+ tokens = match[ 0 ] = match[ 0 ].slice( 0 );
+ if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
+ context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+
+ context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
+ .replace( runescape, funescape ), context ) || [] )[ 0 ];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[ i ];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ ( type = token.type ) ] ) {
+ break;
+ }
+ if ( ( find = Expr.find[ type ] ) ) {
+
+ // Search, expanding context for leading sibling combinators
+ if ( ( seed = find(
+ token.matches[ 0 ].replace( runescape, funescape ),
+ rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
+ context
+ ) ) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert( function( el ) {
+
+ // Should return 1, but returns 4 (following)
+ return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
+} );
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert( function( el ) {
+ el.innerHTML = "<a href='#'></a>";
+ return el.firstChild.getAttribute( "href" ) === "#";
+} ) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ } );
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert( function( el ) {
+ el.innerHTML = "<input/>";
+ el.firstChild.setAttribute( "value", "" );
+ return el.firstChild.getAttribute( "value" ) === "";
+} ) ) {
+ addHandle( "value", function( elem, _name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ } );
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert( function( el ) {
+ return el.getAttribute( "disabled" ) == null;
+} ) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+ }
+ } );
+}
+
+return Sizzle;
+
+} )( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+
+// Deprecated
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+jQuery.escapeSelector = Sizzle.escape;
+
+
+
+
+var dir = function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+};
+
+
+var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+};
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+
+
+function nodeName( elem, name ) {
+
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+
+};
+var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
+
+
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ return !!qualifier.call( elem, i, elem ) !== not;
+ } );
+ }
+
+ // Single element
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ } );
+ }
+
+ // Arraylike of elements (jQuery, arguments, Array)
+ if ( typeof qualifier !== "string" ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
+ } );
+ }
+
+ // Filtered directly for both simple and complex selectors
+ return jQuery.filter( qualifier, elements, not );
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ if ( elems.length === 1 && elem.nodeType === 1 ) {
+ return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
+ }
+
+ return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ } ) );
+};
+
+jQuery.fn.extend( {
+ find: function( selector ) {
+ var i, ret,
+ len = this.length,
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter( function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ } ) );
+ }
+
+ ret = this.pushStack( [] );
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ return len > 1 ? jQuery.uniqueSort( ret ) : ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], false ) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], true ) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+} );
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ // Shortcut simple #id case for speed
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
+
+ init = jQuery.fn.init = function( selector, context, root ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Method init() accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector[ 0 ] === "<" &&
+ selector[ selector.length - 1 ] === ">" &&
+ selector.length >= 3 ) {
+
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && ( match[ 1 ] || !context ) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[ 1 ] ) {
+ context = context instanceof jQuery ? context[ 0 ] : context;
+
+ // Option to run scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[ 1 ],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+
+ // Properties of context are called as methods if possible
+ if ( isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[ 2 ] );
+
+ if ( elem ) {
+
+ // Inject the element directly into the jQuery object
+ this[ 0 ] = elem;
+ this.length = 1;
+ }
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || root ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this[ 0 ] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( isFunction( selector ) ) {
+ return root.ready !== undefined ?
+ root.ready( selector ) :
+
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+ // Methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend( {
+ has: function( target ) {
+ var targets = jQuery( target, this ),
+ l = targets.length;
+
+ return this.filter( function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[ i ] ) ) {
+ return true;
+ }
+ }
+ } );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ targets = typeof selectors !== "string" && jQuery( selectors );
+
+ // Positional selectors never match, since there's no _selection_ context
+ if ( !rneedsContext.test( selectors ) ) {
+ for ( ; i < l; i++ ) {
+ for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
+
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && ( targets ?
+ targets.index( cur ) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+ },
+
+ // Determine the position of an element within the set
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // Index in selector
+ if ( typeof elem === "string" ) {
+ return indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.uniqueSort(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ }
+} );
+
+function sibling( cur, dir ) {
+ while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
+ return cur;
+}
+
+jQuery.each( {
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, _i, until ) {
+ return dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, _i, until ) {
+ return dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, _i, until ) {
+ return dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return siblings( elem.firstChild );
+ },
+ contents: function( elem ) {
+ if ( elem.contentDocument != null &&
+
+ // Support: IE 11+
+ // <object> elements with no `data` attribute has an object
+ // `contentDocument` with a `null` prototype.
+ getProto( elem.contentDocument ) ) {
+
+ return elem.contentDocument;
+ }
+
+ // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
+ // Treat the template element as a regular one in browsers that
+ // don't support it.
+ if ( nodeName( elem, "template" ) ) {
+ elem = elem.content || elem;
+ }
+
+ return jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var matched = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ matched = jQuery.filter( selector, matched );
+ }
+
+ if ( this.length > 1 ) {
+
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ jQuery.uniqueSort( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+} );
+var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
+
+
+
+// Convert String-formatted options into Object-formatted ones
+function createOptions( options ) {
+ var object = {};
+ jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ } );
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ createOptions( options ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+
+ // Last fire value for non-forgettable lists
+ memory,
+
+ // Flag to know if list was already fired
+ fired,
+
+ // Flag to prevent firing
+ locked,
+
+ // Actual callback list
+ list = [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
+ // Fire callbacks
+ fire = function() {
+
+ // Enforce single-firing
+ locked = locked || options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
+ }
+ }
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
+ firing = false;
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
+ list = [];
+
+ // Otherwise, this object is spent
+ } else {
+ list = "";
+ }
+ }
+ },
+
+ // Actual Callbacks object
+ self = {
+
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ if ( isFunction( arg ) ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && toType( arg ) !== "string" ) {
+
+ // Inspect recursively
+ add( arg );
+ }
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Remove a callback from the list
+ remove: function() {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ } );
+ return this;
+ },
+
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ?
+ jQuery.inArray( fn, list ) > -1 :
+ list.length > 0;
+ },
+
+ // Remove all callbacks from the list
+ empty: function() {
+ if ( list ) {
+ list = [];
+ }
+ return this;
+ },
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
+ disable: function() {
+ locked = queue = [];
+ list = memory = "";
+ return this;
+ },
+ disabled: function() {
+ return !list;
+ },
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
+ lock: function() {
+ locked = queue = [];
+ if ( !memory && !firing ) {
+ list = memory = "";
+ }
+ return this;
+ },
+ locked: function() {
+ return !!locked;
+ },
+
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( !locked ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ queue.push( args );
+ if ( !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+function Identity( v ) {
+ return v;
+}
+function Thrower( ex ) {
+ throw ex;
+}
+
+function adoptValue( value, resolve, reject, noValue ) {
+ var method;
+
+ try {
+
+ // Check for promise aspect first to privilege synchronous behavior
+ if ( value && isFunction( ( method = value.promise ) ) ) {
+ method.call( value ).done( resolve ).fail( reject );
+
+ // Other thenables
+ } else if ( value && isFunction( ( method = value.then ) ) ) {
+ method.call( value, resolve, reject );
+
+ // Other non-thenables
+ } else {
+
+ // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
+ // * false: [ value ].slice( 0 ) => resolve( value )
+ // * true: [ value ].slice( 1 ) => resolve()
+ resolve.apply( undefined, [ value ].slice( noValue ) );
+ }
+
+ // For Promises/A+, convert exceptions into rejections
+ // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+ // Deferred#then to conditionally suppress rejection.
+ } catch ( value ) {
+
+ // Support: Android 4.0 only
+ // Strict mode functions invoked without .call/.apply get global-object context
+ reject.apply( undefined, [ value ] );
+ }
+}
+
+jQuery.extend( {
+
+ Deferred: function( func ) {
+ var tuples = [
+
+ // action, add listener, callbacks,
+ // ... .then handlers, argument index, [final state]
+ [ "notify", "progress", jQuery.Callbacks( "memory" ),
+ jQuery.Callbacks( "memory" ), 2 ],
+ [ "resolve", "done", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 0, "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 1, "rejected" ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ "catch": function( fn ) {
+ return promise.then( null, fn );
+ },
+
+ // Keep pipe for back-compat
+ pipe: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+
+ return jQuery.Deferred( function( newDefer ) {
+ jQuery.each( tuples, function( _i, tuple ) {
+
+ // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+ var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+ // deferred.progress(function() { bind to newDefer or newDefer.notify })
+ // deferred.done(function() { bind to newDefer or newDefer.resolve })
+ // deferred.fail(function() { bind to newDefer or newDefer.reject })
+ deferred[ tuple[ 1 ] ]( function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && isFunction( returned.promise ) ) {
+ returned.promise()
+ .progress( newDefer.notify )
+ .done( newDefer.resolve )
+ .fail( newDefer.reject );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ](
+ this,
+ fn ? [ returned ] : arguments
+ );
+ }
+ } );
+ } );
+ fns = null;
+ } ).promise();
+ },
+ then: function( onFulfilled, onRejected, onProgress ) {
+ var maxDepth = 0;
+ function resolve( depth, deferred, handler, special ) {
+ return function() {
+ var that = this,
+ args = arguments,
+ mightThrow = function() {
+ var returned, then;
+
+ // Support: Promises/A+ section 2.3.3.3.3
+ // https://promisesaplus.com/#point-59
+ // Ignore double-resolution attempts
+ if ( depth < maxDepth ) {
+ return;
+ }
+
+ returned = handler.apply( that, args );
+
+ // Support: Promises/A+ section 2.3.1
+ // https://promisesaplus.com/#point-48
+ if ( returned === deferred.promise() ) {
+ throw new TypeError( "Thenable self-resolution" );
+ }
+
+ // Support: Promises/A+ sections 2.3.3.1, 3.5
+ // https://promisesaplus.com/#point-54
+ // https://promisesaplus.com/#point-75
+ // Retrieve `then` only once
+ then = returned &&
+
+ // Support: Promises/A+ section 2.3.4
+ // https://promisesaplus.com/#point-64
+ // Only check objects and functions for thenability
+ ( typeof returned === "object" ||
+ typeof returned === "function" ) &&
+ returned.then;
+
+ // Handle a returned thenable
+ if ( isFunction( then ) ) {
+
+ // Special processors (notify) just wait for resolution
+ if ( special ) {
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special )
+ );
+
+ // Normal processors (resolve) also hook into progress
+ } else {
+
+ // ...and disregard older resolution values
+ maxDepth++;
+
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special ),
+ resolve( maxDepth, deferred, Identity,
+ deferred.notifyWith )
+ );
+ }
+
+ // Handle all other returned values
+ } else {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Identity ) {
+ that = undefined;
+ args = [ returned ];
+ }
+
+ // Process the value(s)
+ // Default process is resolve
+ ( special || deferred.resolveWith )( that, args );
+ }
+ },
+
+ // Only normal processors (resolve) catch and reject exceptions
+ process = special ?
+ mightThrow :
+ function() {
+ try {
+ mightThrow();
+ } catch ( e ) {
+
+ if ( jQuery.Deferred.exceptionHook ) {
+ jQuery.Deferred.exceptionHook( e,
+ process.stackTrace );
+ }
+
+ // Support: Promises/A+ section 2.3.3.3.4.1
+ // https://promisesaplus.com/#point-61
+ // Ignore post-resolution exceptions
+ if ( depth + 1 >= maxDepth ) {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Thrower ) {
+ that = undefined;
+ args = [ e ];
+ }
+
+ deferred.rejectWith( that, args );
+ }
+ }
+ };
+
+ // Support: Promises/A+ section 2.3.3.3.1
+ // https://promisesaplus.com/#point-57
+ // Re-resolve promises immediately to dodge false rejection from
+ // subsequent errors
+ if ( depth ) {
+ process();
+ } else {
+
+ // Call an optional hook to record the stack, in case of exception
+ // since it's otherwise lost when execution goes async
+ if ( jQuery.Deferred.getStackHook ) {
+ process.stackTrace = jQuery.Deferred.getStackHook();
+ }
+ window.setTimeout( process );
+ }
+ };
+ }
+
+ return jQuery.Deferred( function( newDefer ) {
+
+ // progress_handlers.add( ... )
+ tuples[ 0 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onProgress ) ?
+ onProgress :
+ Identity,
+ newDefer.notifyWith
+ )
+ );
+
+ // fulfilled_handlers.add( ... )
+ tuples[ 1 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onFulfilled ) ?
+ onFulfilled :
+ Identity
+ )
+ );
+
+ // rejected_handlers.add( ... )
+ tuples[ 2 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onRejected ) ?
+ onRejected :
+ Thrower
+ )
+ );
+ } ).promise();
+ },
+
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 5 ];
+
+ // promise.progress = list.add
+ // promise.done = list.add
+ // promise.fail = list.add
+ promise[ tuple[ 1 ] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(
+ function() {
+
+ // state = "resolved" (i.e., fulfilled)
+ // state = "rejected"
+ state = stateString;
+ },
+
+ // rejected_callbacks.disable
+ // fulfilled_callbacks.disable
+ tuples[ 3 - i ][ 2 ].disable,
+
+ // rejected_handlers.disable
+ // fulfilled_handlers.disable
+ tuples[ 3 - i ][ 3 ].disable,
+
+ // progress_callbacks.lock
+ tuples[ 0 ][ 2 ].lock,
+
+ // progress_handlers.lock
+ tuples[ 0 ][ 3 ].lock
+ );
+ }
+
+ // progress_handlers.fire
+ // fulfilled_handlers.fire
+ // rejected_handlers.fire
+ list.add( tuple[ 3 ].fire );
+
+ // deferred.notify = function() { deferred.notifyWith(...) }
+ // deferred.resolve = function() { deferred.resolveWith(...) }
+ // deferred.reject = function() { deferred.rejectWith(...) }
+ deferred[ tuple[ 0 ] ] = function() {
+ deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
+ return this;
+ };
+
+ // deferred.notifyWith = list.fireWith
+ // deferred.resolveWith = list.fireWith
+ // deferred.rejectWith = list.fireWith
+ deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+ } );
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( singleValue ) {
+ var
+
+ // count of uncompleted subordinates
+ remaining = arguments.length,
+
+ // count of unprocessed arguments
+ i = remaining,
+
+ // subordinate fulfillment data
+ resolveContexts = Array( i ),
+ resolveValues = slice.call( arguments ),
+
+ // the master Deferred
+ master = jQuery.Deferred(),
+
+ // subordinate callback factory
+ updateFunc = function( i ) {
+ return function( value ) {
+ resolveContexts[ i ] = this;
+ resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( !( --remaining ) ) {
+ master.resolveWith( resolveContexts, resolveValues );
+ }
+ };
+ };
+
+ // Single- and empty arguments are adopted like Promise.resolve
+ if ( remaining <= 1 ) {
+ adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
+ !remaining );
+
+ // Use .then() to unwrap secondary thenables (cf. gh-3000)
+ if ( master.state() === "pending" ||
+ isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+
+ return master.then();
+ }
+ }
+
+ // Multiple arguments are aggregated like Promise.all array elements
+ while ( i-- ) {
+ adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
+ }
+
+ return master.promise();
+ }
+} );
+
+
+// These usually indicate a programmer mistake during development,
+// warn about them ASAP rather than swallowing them by default.
+var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+
+jQuery.Deferred.exceptionHook = function( error, stack ) {
+
+ // Support: IE 8 - 9 only
+ // Console exists when dev tools are open, which can happen at any time
+ if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
+ window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+ }
+};
+
+
+
+
+jQuery.readyException = function( error ) {
+ window.setTimeout( function() {
+ throw error;
+ } );
+};
+
+
+
+
+// The deferred used on DOM ready
+var readyList = jQuery.Deferred();
+
+jQuery.fn.ready = function( fn ) {
+
+ readyList
+ .then( fn )
+
+ // Wrap jQuery.readyException in a function so that the lookup
+ // happens at the time of error handling instead of callback
+ // registration.
+ .catch( function( error ) {
+ jQuery.readyException( error );
+ } );
+
+ return this;
+};
+
+jQuery.extend( {
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+ }
+} );
+
+jQuery.ready.then = readyList.then;
+
+// The ready event handler and self cleanup method
+function completed() {
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+ jQuery.ready();
+}
+
+// Catch cases where $(document).ready() is called
+// after the browser event has already occurred.
+// Support: IE <=9 - 10 only
+// Older IE sometimes signals "interactive" too soon
+if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
+
+} else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+}
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( toType( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ access( elems, fn, i, key[ i ], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, _key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < len; i++ ) {
+ fn(
+ elems[ i ], key, raw ?
+ value :
+ value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
+ }
+ }
+
+ if ( chainable ) {
+ return elems;
+ }
+
+ // Gets
+ if ( bulk ) {
+ return fn.call( elems );
+ }
+
+ return len ? fn( elems[ 0 ], key ) : emptyGet;
+};
+
+
+// Matches dashed string for camelizing
+var rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([a-z])/g;
+
+// Used by camelCase as callback to replace()
+function fcamelCase( _all, letter ) {
+ return letter.toUpperCase();
+}
+
+// Convert dashed to camelCase; used by the css and data modules
+// Support: IE <=9 - 11, Edge 12 - 15
+// Microsoft forgot to hump their vendor prefix (#9572)
+function camelCase( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+}
+var acceptData = function( owner ) {
+
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+
+
+function Data() {
+ this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+
+Data.prototype = {
+
+ cache: function( owner ) {
+
+ // Check if the owner object already has a cache
+ var value = owner[ this.expando ];
+
+ // If not, create one
+ if ( !value ) {
+ value = {};
+
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( acceptData( owner ) ) {
+
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
+
+ // Otherwise secure it in a non-enumerable property
+ // configurable must be true to allow the property to be
+ // deleted when data is removed
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ configurable: true
+ } );
+ }
+ }
+ }
+
+ return value;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ cache = this.cache( owner );
+
+ // Handle: [ owner, key, value ] args
+ // Always use camelCase key (gh-2257)
+ if ( typeof data === "string" ) {
+ cache[ camelCase( data ) ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+
+ // Copy the properties one-by-one to the cache object
+ for ( prop in data ) {
+ cache[ camelCase( prop ) ] = data[ prop ];
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ return key === undefined ?
+ this.cache( owner ) :
+
+ // Always use camelCase key (gh-2257)
+ owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
+ },
+ access: function( owner, key, value ) {
+
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ( ( key && typeof key === "string" ) && value === undefined ) ) {
+
+ return this.get( owner, key );
+ }
+
+ // When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
+
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i,
+ cache = owner[ this.expando ];
+
+ if ( cache === undefined ) {
+ return;
+ }
+
+ if ( key !== undefined ) {
+
+ // Support array or space separated string of keys
+ if ( Array.isArray( key ) ) {
+
+ // If key is an array of keys...
+ // We always set camelCase keys, so remove that.
+ key = key.map( camelCase );
+ } else {
+ key = camelCase( key );
+
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ key = key in cache ?
+ [ key ] :
+ ( key.match( rnothtmlwhite ) || [] );
+ }
+
+ i = key.length;
+
+ while ( i-- ) {
+ delete cache[ key[ i ] ];
+ }
+ }
+
+ // Remove the expando if there's no more data
+ if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
+
+ // Support: Chrome <=35 - 45
+ // Webkit & Blink performance suffers when deleting properties
+ // from DOM nodes, so set to undefined instead
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = undefined;
+ } else {
+ delete owner[ this.expando ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
+ }
+};
+var dataPriv = new Data();
+
+var dataUser = new Data();
+
+
+
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /[A-Z]/g;
+
+function getData( data ) {
+ if ( data === "true" ) {
+ return true;
+ }
+
+ if ( data === "false" ) {
+ return false;
+ }
+
+ if ( data === "null" ) {
+ return null;
+ }
+
+ // Only convert to a number if it doesn't change the string
+ if ( data === +data + "" ) {
+ return +data;
+ }
+
+ if ( rbrace.test( data ) ) {
+ return JSON.parse( data );
+ }
+
+ return data;
+}
+
+function dataAttr( elem, key, data ) {
+ var name;
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = getData( data );
+ } catch ( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ dataUser.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+}
+
+jQuery.extend( {
+ hasData: function( elem ) {
+ return dataUser.hasData( elem ) || dataPriv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return dataUser.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ dataUser.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to dataPriv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return dataPriv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ dataPriv.remove( elem, name );
+ }
+} );
+
+jQuery.fn.extend( {
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = dataUser.get( elem );
+
+ if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE 11 only
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = camelCase( name.slice( 5 ) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ dataPriv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each( function() {
+ dataUser.set( this, key );
+ } );
+ }
+
+ return access( this, function( value ) {
+ var data;
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+
+ // Attempt to get data from the cache
+ // The key will always be camelCased in Data
+ data = dataUser.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
+
+ // Set the data...
+ this.each( function() {
+
+ // We always store the camelCased key
+ dataUser.set( this, key, value );
+ } );
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each( function() {
+ dataUser.remove( this, key );
+ } );
+ }
+} );
+
+
+jQuery.extend( {
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = dataPriv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || Array.isArray( data ) ) {
+ queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // Clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // Not public - generate a queueHooks object, or return the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ dataPriv.remove( elem, [ type + "queue", key ] );
+ } )
+ } );
+ }
+} );
+
+jQuery.fn.extend( {
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[ 0 ], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each( function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // Ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ dequeue: function( type ) {
+ return this.each( function() {
+ jQuery.dequeue( this, type );
+ } );
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+} );
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var documentElement = document.documentElement;
+
+
+
+ var isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem );
+ },
+ composed = { composed: true };
+
+ // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
+ // Check attachment across shadow DOM boundaries when possible (gh-3504)
+ // Support: iOS 10.0-10.2 only
+ // Early iOS 10 versions support `attachShadow` but not `getRootNode`,
+ // leading to errors. We need to check for `getRootNode`.
+ if ( documentElement.getRootNode ) {
+ isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem ) ||
+ elem.getRootNode( composed ) === elem.ownerDocument;
+ };
+ }
+var isHiddenWithinTree = function( elem, el ) {
+
+ // isHiddenWithinTree might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+
+ // Inline style trumps all
+ return elem.style.display === "none" ||
+ elem.style.display === "" &&
+
+ // Otherwise, check computed style
+ // Support: Firefox <=43 - 45
+ // Disconnected elements can have computed display: none, so first confirm that elem is
+ // in the document.
+ isAttached( elem ) &&
+
+ jQuery.css( elem, "display" ) === "none";
+ };
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted, scale,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() {
+ return tween.cur();
+ } :
+ function() {
+ return jQuery.css( elem, prop, "" );
+ },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = elem.nodeType &&
+ ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Support: Firefox <=54
+ // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
+ initial = initial / 2;
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ while ( maxIterations-- ) {
+
+ // Evaluate and update our best guess (doubling guesses that zero out).
+ // Finish if the scale equals or crosses 1 (making the old*new product non-positive).
+ jQuery.style( elem, prop, initialInUnit + unit );
+ if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
+ maxIterations = 0;
+ }
+ initialInUnit = initialInUnit / scale;
+
+ }
+
+ initialInUnit = initialInUnit * 2;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+}
+
+
+var defaultDisplayMap = {};
+
+function getDefaultDisplay( elem ) {
+ var temp,
+ doc = elem.ownerDocument,
+ nodeName = elem.nodeName,
+ display = defaultDisplayMap[ nodeName ];
+
+ if ( display ) {
+ return display;
+ }
+
+ temp = doc.body.appendChild( doc.createElement( nodeName ) );
+ display = jQuery.css( temp, "display" );
+
+ temp.parentNode.removeChild( temp );
+
+ if ( display === "none" ) {
+ display = "block";
+ }
+ defaultDisplayMap[ nodeName ] = display;
+
+ return display;
+}
+
+function showHide( elements, show ) {
+ var display, elem,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ // Determine new display value for elements that need to change
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ display = elem.style.display;
+ if ( show ) {
+
+ // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
+ // check is required in this first loop unless we have a nonempty display value (either
+ // inline or about-to-be-restored)
+ if ( display === "none" ) {
+ values[ index ] = dataPriv.get( elem, "display" ) || null;
+ if ( !values[ index ] ) {
+ elem.style.display = "";
+ }
+ }
+ if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
+ values[ index ] = getDefaultDisplay( elem );
+ }
+ } else {
+ if ( display !== "none" ) {
+ values[ index ] = "none";
+
+ // Remember what we're overwriting
+ dataPriv.set( elem, "display", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop to avoid constant reflow
+ for ( index = 0; index < length; index++ ) {
+ if ( values[ index ] != null ) {
+ elements[ index ].style.display = values[ index ];
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend( {
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each( function() {
+ if ( isHiddenWithinTree( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ } );
+ }
+} );
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
+
+var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
+
+
+
+( function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Android 4.0 - 4.3 only
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Android <=4.1 only
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE <=11 only
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // Support: IE <=9 only
+ // IE <=9 replaces <option> tags with their contents when inserted outside of
+ // the select element.
+ div.innerHTML = "<option></option>";
+ support.option = !!div.lastChild;
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
+
+ // XHTML parsers do not magically insert elements in the
+ // same way that tag soup parsers do. So we cannot shorten
+ // this by omitting <tbody> or other required elements.
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ _default: [ 0, "", "" ]
+};
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: IE <=9 only
+if ( !support.option ) {
+ wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
+}
+
+
+function getAll( context, tag ) {
+
+ // Support: IE <=9 - 11 only
+ // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+ var ret;
+
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ ret = context.getElementsByTagName( tag || "*" );
+
+ } else if ( typeof context.querySelectorAll !== "undefined" ) {
+ ret = context.querySelectorAll( tag || "*" );
+
+ } else {
+ ret = [];
+ }
+
+ if ( tag === undefined || tag && nodeName( context, tag ) ) {
+ return jQuery.merge( [ context ], ret );
+ }
+
+ return ret;
+}
+
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ dataPriv.set(
+ elems[ i ],
+ "globalEval",
+ !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+
+var rhtml = /<|&#?\w+;/;
+
+function buildFragment( elems, context, scripts, selection, ignored ) {
+ var elem, tmp, tag, wrap, attached, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( toType( elem ) === "object" ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
+
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+ continue;
+ }
+
+ attached = isAttached( elem );
+
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( attached ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( ( elem = tmp[ j++ ] ) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ return fragment;
+}
+
+
+var
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+// Support: IE <=9 - 11+
+// focus() and blur() are asynchronous, except when they are no-op.
+// So expect focus to be synchronous when the element is already active,
+// and blur to be synchronous when the element is not already active.
+// (focus and blur are always synchronous in other supported browsers,
+// this just defines when we can count on it).
+function expectSync( elem, type ) {
+ return ( elem === safeActiveElement() ) === ( type === "focus" );
+}
+
+// Support: IE <=9 only
+// Accessing document.activeElement can throw unexpectedly
+// https://bugs.jquery.com/ticket/13393
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+function on( elem, types, selector, data, fn, one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ if ( data == null && fn == null ) {
+
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return elem;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.get( elem );
+
+ // Only attach events to objects that accept data
+ if ( !acceptData( elem ) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Ensure that invalid selectors throw exceptions at attach time
+ // Evaluate against documentElement in case elem is a non-element node (e.g., document)
+ if ( selector ) {
+ jQuery.find.matchesSelector( documentElement, selector );
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !( events = elemData.events ) ) {
+ events = elemData.events = Object.create( null );
+ }
+ if ( !( eventHandle = elemData.handle ) ) {
+ eventHandle = elemData.handle = function( e ) {
+
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+ };
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend( {
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join( "." )
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !( handlers = events[ type ] ) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup ||
+ special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[ 2 ] &&
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector ||
+ selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown ||
+ special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove data and the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ dataPriv.remove( elem, "handle events" );
+ }
+ },
+
+ dispatch: function( nativeEvent ) {
+
+ var i, j, ret, matched, handleObj, handlerQueue,
+ args = new Array( arguments.length ),
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( nativeEvent ),
+
+ handlers = (
+ dataPriv.get( this, "events" ) || Object.create( null )
+ )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[ 0 ] = event;
+
+ for ( i = 1; i < arguments.length; i++ ) {
+ args[ i ] = arguments[ i ];
+ }
+
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( ( handleObj = matched.handlers[ j++ ] ) &&
+ !event.isImmediatePropagationStopped() ) {
+
+ // If the event is namespaced, then each handler is only invoked if it is
+ // specially universal or its namespaces are a superset of the event's.
+ if ( !event.rnamespace || handleObj.namespace === false ||
+ event.rnamespace.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+ handleObj.handler ).apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( ( event.result = ret ) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, handleObj, sel, matchedHandlers, matchedSelectors,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ if ( delegateCount &&
+
+ // Support: IE <=9
+ // Black-hole SVG <use> instance trees (trac-13180)
+ cur.nodeType &&
+
+ // Support: Firefox <=42
+ // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
+ // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
+ // Support: IE 11 only
+ // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
+ !( event.type === "click" && event.button >= 1 ) ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
+ matchedHandlers = [];
+ matchedSelectors = {};
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matchedSelectors[ sel ] === undefined ) {
+ matchedSelectors[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) > -1 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matchedSelectors[ sel ] ) {
+ matchedHandlers.push( handleObj );
+ }
+ }
+ if ( matchedHandlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ cur = this;
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
+ }
+
+ return handlerQueue;
+ },
+
+ addProp: function( name, hook ) {
+ Object.defineProperty( jQuery.Event.prototype, name, {
+ enumerable: true,
+ configurable: true,
+
+ get: isFunction( hook ) ?
+ function() {
+ if ( this.originalEvent ) {
+ return hook( this.originalEvent );
+ }
+ } :
+ function() {
+ if ( this.originalEvent ) {
+ return this.originalEvent[ name ];
+ }
+ },
+
+ set: function( value ) {
+ Object.defineProperty( this, name, {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: value
+ } );
+ }
+ } );
+ },
+
+ fix: function( originalEvent ) {
+ return originalEvent[ jQuery.expando ] ?
+ originalEvent :
+ new jQuery.Event( originalEvent );
+ },
+
+ special: {
+ load: {
+
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ click: {
+
+ // Utilize native event to ensure correct state for checkable inputs
+ setup: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Claim the first handler
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ // dataPriv.set( el, "click", ... )
+ leverageNative( el, "click", returnTrue );
+ }
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Force setup before triggering a click
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ leverageNative( el, "click" );
+ }
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ // For cross-browser consistency, suppress native .click() on links
+ // Also prevent it if we're currently inside a leveraged native-event stack
+ _default: function( event ) {
+ var target = event.target;
+ return rcheckableType.test( target.type ) &&
+ target.click && nodeName( target, "input" ) &&
+ dataPriv.get( target, "click" ) ||
+ nodeName( target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ }
+};
+
+// Ensure the presence of an event listener that handles manually-triggered
+// synthetic events by interrupting progress until reinvoked in response to
+// *native* events that it fires directly, ensuring that state changes have
+// already occurred before other listeners are invoked.
+function leverageNative( el, type, expectSync ) {
+
+ // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
+ if ( !expectSync ) {
+ if ( dataPriv.get( el, type ) === undefined ) {
+ jQuery.event.add( el, type, returnTrue );
+ }
+ return;
+ }
+
+ // Register the controller as a special universal handler for all event namespaces
+ dataPriv.set( el, type, false );
+ jQuery.event.add( el, type, {
+ namespace: false,
+ handler: function( event ) {
+ var notAsync, result,
+ saved = dataPriv.get( this, type );
+
+ if ( ( event.isTrigger & 1 ) && this[ type ] ) {
+
+ // Interrupt processing of the outer synthetic .trigger()ed event
+ // Saved data should be false in such cases, but might be a leftover capture object
+ // from an async native handler (gh-4350)
+ if ( !saved.length ) {
+
+ // Store arguments for use when handling the inner native event
+ // There will always be at least one argument (an event object), so this array
+ // will not be confused with a leftover capture object.
+ saved = slice.call( arguments );
+ dataPriv.set( this, type, saved );
+
+ // Trigger the native event and capture its result
+ // Support: IE <=9 - 11+
+ // focus() and blur() are asynchronous
+ notAsync = expectSync( this, type );
+ this[ type ]();
+ result = dataPriv.get( this, type );
+ if ( saved !== result || notAsync ) {
+ dataPriv.set( this, type, false );
+ } else {
+ result = {};
+ }
+ if ( saved !== result ) {
+
+ // Cancel the outer synthetic event
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ return result.value;
+ }
+
+ // If this is an inner synthetic event for an event with a bubbling surrogate
+ // (focus or blur), assume that the surrogate already propagated from triggering the
+ // native event and prevent that from happening again here.
+ // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
+ // bubbling surrogate propagates *after* the non-bubbling base), but that seems
+ // less bad than duplication.
+ } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
+ event.stopPropagation();
+ }
+
+ // If this is a native event triggered above, everything is now in order
+ // Fire an inner synthetic event with the original arguments
+ } else if ( saved.length ) {
+
+ // ...and capture the result
+ dataPriv.set( this, type, {
+ value: jQuery.event.trigger(
+
+ // Support: IE <=9 - 11+
+ // Extend with the prototype to reset the above stopImmediatePropagation()
+ jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
+ saved.slice( 1 ),
+ this
+ )
+ } );
+
+ // Abort handling of the native event
+ event.stopImmediatePropagation();
+ }
+ }
+ } );
+}
+
+jQuery.removeEvent = function( elem, type, handle ) {
+
+ // This "if" is needed for plain objects
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle );
+ }
+};
+
+jQuery.Event = function( src, props ) {
+
+ // Allow instantiation without the 'new' keyword
+ if ( !( this instanceof jQuery.Event ) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+
+ // Support: Android <=2.3 only
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Create target properties
+ // Support: Safari <=6 - 7 only
+ // Target should not be a text node (#504, #13143)
+ this.target = ( src.target && src.target.nodeType === 3 ) ?
+ src.target.parentNode :
+ src.target;
+
+ this.currentTarget = src.currentTarget;
+ this.relatedTarget = src.relatedTarget;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || Date.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ constructor: jQuery.Event,
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+ isSimulated: false,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Includes all common event props including KeyEvent and MouseEvent specific props
+jQuery.each( {
+ altKey: true,
+ bubbles: true,
+ cancelable: true,
+ changedTouches: true,
+ ctrlKey: true,
+ detail: true,
+ eventPhase: true,
+ metaKey: true,
+ pageX: true,
+ pageY: true,
+ shiftKey: true,
+ view: true,
+ "char": true,
+ code: true,
+ charCode: true,
+ key: true,
+ keyCode: true,
+ button: true,
+ buttons: true,
+ clientX: true,
+ clientY: true,
+ offsetX: true,
+ offsetY: true,
+ pointerId: true,
+ pointerType: true,
+ screenX: true,
+ screenY: true,
+ targetTouches: true,
+ toElement: true,
+ touches: true,
+
+ which: function( event ) {
+ var button = event.button;
+
+ // Add which for key events
+ if ( event.which == null && rkeyEvent.test( event.type ) ) {
+ return event.charCode != null ? event.charCode : event.keyCode;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
+ if ( button & 1 ) {
+ return 1;
+ }
+
+ if ( button & 2 ) {
+ return 3;
+ }
+
+ if ( button & 4 ) {
+ return 2;
+ }
+
+ return 0;
+ }
+
+ return event.which;
+ }
+}, jQuery.event.addProp );
+
+jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
+ jQuery.event.special[ type ] = {
+
+ // Utilize native event if possible so blur/focus sequence is correct
+ setup: function() {
+
+ // Claim the first handler
+ // dataPriv.set( this, "focus", ... )
+ // dataPriv.set( this, "blur", ... )
+ leverageNative( this, type, expectSync );
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function() {
+
+ // Force setup before trigger
+ leverageNative( this, type );
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ delegateType: delegateType
+ };
+} );
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// so that event delegation works in jQuery.
+// Do the same for pointerenter/pointerleave and pointerover/pointerout
+//
+// Support: Safari 7 only
+// Safari sends mouseenter too often; see:
+// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
+// for the description of the bug (it existed in older Chrome versions as well).
+jQuery.each( {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mouseenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+} );
+
+jQuery.fn.extend( {
+
+ on: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn );
+ },
+ one: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ?
+ handleObj.origType + "." + handleObj.namespace :
+ handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each( function() {
+ jQuery.event.remove( this, types, fn, selector );
+ } );
+ }
+} );
+
+
+var
+
+ // Support: IE <=10 - 11, Edge 12 - 13 only
+ // In IE/Edge using regex groups here causes severe slowdowns.
+ // See https://connect.microsoft.com/IE/feedback/details/1736512/
+ rnoInnerhtml = /<script|<style|<link/i,
+
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+
+// Prefer a tbody over its parent table for containing new rows
+function manipulationTarget( elem, content ) {
+ if ( nodeName( elem, "table" ) &&
+ nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
+
+ return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
+ }
+
+ return elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
+ elem.type = elem.type.slice( 5 );
+ } else {
+ elem.removeAttribute( "type" );
+ }
+
+ return elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, udataOld, udataCur, events;
+
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // 1. Copy private data: events, handlers, etc.
+ if ( dataPriv.hasData( src ) ) {
+ pdataOld = dataPriv.get( src );
+ events = pdataOld.events;
+
+ if ( events ) {
+ dataPriv.remove( dest, "handle events" );
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+ }
+
+ // 2. Copy user data
+ if ( dataUser.hasData( src ) ) {
+ udataOld = dataUser.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ dataUser.set( dest, udataCur );
+ }
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
+
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+function domManip( collection, args, callback, ignored ) {
+
+ // Flatten any nested arrays
+ args = flat( args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = collection.length,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ valueIsFunction = isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( valueIsFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return collection.each( function( index ) {
+ var self = collection.eq( index );
+ if ( valueIsFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ domManip( self, args, callback, ignored );
+ } );
+ }
+
+ if ( l ) {
+ fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ // Require either new content or an interest in ignored elements to invoke the callback
+ if ( first || ignored ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item
+ // instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( collection[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !dataPriv.access( node, "globalEval" ) &&
+ jQuery.contains( doc, node ) ) {
+
+ if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
+
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl && !node.noModule ) {
+ jQuery._evalUrl( node.src, {
+ nonce: node.nonce || node.getAttribute( "nonce" )
+ }, doc );
+ }
+ } else {
+ DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return collection;
+}
+
+function remove( elem, selector, keepData ) {
+ var node,
+ nodes = selector ? jQuery.filter( selector, elem ) : elem,
+ i = 0;
+
+ for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+ if ( !keepData && node.nodeType === 1 ) {
+ jQuery.cleanData( getAll( node ) );
+ }
+
+ if ( node.parentNode ) {
+ if ( keepData && isAttached( node ) ) {
+ setGlobalEval( getAll( node, "script" ) );
+ }
+ node.parentNode.removeChild( node );
+ }
+ }
+
+ return elem;
+}
+
+jQuery.extend( {
+ htmlPrefilter: function( html ) {
+ return html;
+ },
+
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = isAttached( elem );
+
+ // Fix IE cloning issues
+ if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+ !jQuery.isXMLDoc( elem ) ) {
+
+ // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ // Return the cloned set
+ return clone;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, type,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+ if ( acceptData( elem ) ) {
+ if ( ( data = elem[ dataPriv.expando ] ) ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataPriv.expando ] = undefined;
+ }
+ if ( elem[ dataUser.expando ] ) {
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataUser.expando ] = undefined;
+ }
+ }
+ }
+ }
+} );
+
+jQuery.fn.extend( {
+ detach: function( selector ) {
+ return remove( this, selector, true );
+ },
+
+ remove: function( selector ) {
+ return remove( this, selector );
+ },
+
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().each( function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ } );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ } );
+ },
+
+ prepend: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ } );
+ },
+
+ before: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ } );
+ },
+
+ after: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ } );
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; ( elem = this[ i ] ) != null; i++ ) {
+ if ( elem.nodeType === 1 ) {
+
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
+
+ // Remove any remaining nodes
+ elem.textContent = "";
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ } );
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+ value = jQuery.htmlPrefilter( value );
+
+ try {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch ( e ) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var ignored = [];
+
+ // Make the changes, replacing each non-ignored context element with the new content
+ return domManip( this, arguments, function( elem ) {
+ var parent = this.parentNode;
+
+ if ( jQuery.inArray( this, ignored ) < 0 ) {
+ jQuery.cleanData( getAll( this ) );
+ if ( parent ) {
+ parent.replaceChild( elem, this );
+ }
+ }
+
+ // Force callback invocation
+ }, ignored );
+ }
+} );
+
+jQuery.each( {
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1,
+ i = 0;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // .get() because push.apply(_, arraylike) throws on ancient WebKit
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+} );
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+
+ // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ var view = elem.ownerDocument.defaultView;
+
+ if ( !view || !view.opener ) {
+ view = window;
+ }
+
+ return view.getComputedStyle( elem );
+ };
+
+var swap = function( elem, options, callback ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
+
+
+
+( function() {
+
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computeStyleTests() {
+
+ // This is a singleton, we need to execute it only once
+ if ( !div ) {
+ return;
+ }
+
+ container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
+ "margin-top:1px;padding:0;border:0";
+ div.style.cssText =
+ "position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
+ "margin:auto;border:1px;padding:1px;" +
+ "width:60%;top:1%";
+ documentElement.appendChild( container ).appendChild( div );
+
+ var divStyle = window.getComputedStyle( div );
+ pixelPositionVal = divStyle.top !== "1%";
+
+ // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
+ reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
+
+ // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
+ // Some styles come back with percentage values, even though they shouldn't
+ div.style.right = "60%";
+ pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
+
+ // Support: IE 9 - 11 only
+ // Detect misreporting of content dimensions for box-sizing:border-box elements
+ boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
+
+ // Support: IE 9 only
+ // Detect overflow:scroll screwiness (gh-3699)
+ // Support: Chrome <=64
+ // Don't get tricked when zoom affects offsetWidth (gh-4029)
+ div.style.position = "absolute";
+ scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
+
+ documentElement.removeChild( container );
+
+ // Nullify the div so it wouldn't be stored in the memory and
+ // it will also be a sign that checks already performed
+ div = null;
+ }
+
+ function roundPixelMeasures( measure ) {
+ return Math.round( parseFloat( measure ) );
+ }
+
+ var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
+ reliableTrDimensionsVal, reliableMarginLeftVal,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
+
+ // Finish early in limited (non-browser) environments
+ if ( !div.style ) {
+ return;
+ }
+
+ // Support: IE <=9 - 11 only
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ jQuery.extend( support, {
+ boxSizingReliable: function() {
+ computeStyleTests();
+ return boxSizingReliableVal;
+ },
+ pixelBoxStyles: function() {
+ computeStyleTests();
+ return pixelBoxStylesVal;
+ },
+ pixelPosition: function() {
+ computeStyleTests();
+ return pixelPositionVal;
+ },
+ reliableMarginLeft: function() {
+ computeStyleTests();
+ return reliableMarginLeftVal;
+ },
+ scrollboxSize: function() {
+ computeStyleTests();
+ return scrollboxSizeVal;
+ },
+
+ // Support: IE 9 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Behavior in IE 9 is more subtle than in newer versions & it passes
+ // some versions of this test; make sure not to make it pass there!
+ reliableTrDimensions: function() {
+ var table, tr, trChild, trStyle;
+ if ( reliableTrDimensionsVal == null ) {
+ table = document.createElement( "table" );
+ tr = document.createElement( "tr" );
+ trChild = document.createElement( "div" );
+
+ table.style.cssText = "position:absolute;left:-11111px";
+ tr.style.height = "1px";
+ trChild.style.height = "9px";
+
+ documentElement
+ .appendChild( table )
+ .appendChild( tr )
+ .appendChild( trChild );
+
+ trStyle = window.getComputedStyle( tr );
+ reliableTrDimensionsVal = parseInt( trStyle.height ) > 3;
+
+ documentElement.removeChild( table );
+ }
+ return reliableTrDimensionsVal;
+ }
+ } );
+} )();
+
+
+function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+
+ // Support: Firefox 51+
+ // Retrieving style before computed somehow
+ // fixes an issue with getting wrong values
+ // on detached elements
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is needed for:
+ // .css('filter') (IE 9 only, #12537)
+ // .css('--customProperty) (#3144)
+ if ( computed ) {
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !isAttached( elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Android Browser returns percentage for some values,
+ // but width seems to be reliably pixels.
+ // This is against the CSSOM draft spec:
+ // https://drafts.csswg.org/cssom/#resolved-values
+ if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret !== undefined ?
+
+ // Support: IE <=9 - 11 only
+ // IE returns zIndex value as an integer.
+ ret + "" :
+ ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ if ( conditionFn() ) {
+
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+ return ( this.get = hookFn ).apply( this, arguments );
+ }
+ };
+}
+
+
+var cssPrefixes = [ "Webkit", "Moz", "ms" ],
+ emptyStyle = document.createElement( "div" ).style,
+ vendorProps = {};
+
+// Return a vendor-prefixed property or undefined
+function vendorPropName( name ) {
+
+ // Check for vendor prefixed names
+ var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ }
+}
+
+// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
+function finalPropName( name ) {
+ var final = jQuery.cssProps[ name ] || vendorProps[ name ];
+
+ if ( final ) {
+ return final;
+ }
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ return vendorProps[ name ] = vendorPropName( name ) || name;
+}
+
+
+var
+
+ // Swappable if display is none or starts with table
+ // except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rcustomProp = /^--/,
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ };
+
+function setPositiveNumber( _elem, value, subtract ) {
+
+ // Any relative (+/-) values have already been
+ // normalized at this point
+ var matches = rcssNum.exec( value );
+ return matches ?
+
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
+ value;
+}
+
+function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
+ var i = dimension === "width" ? 1 : 0,
+ extra = 0,
+ delta = 0;
+
+ // Adjustment may not be necessary
+ if ( box === ( isBorderBox ? "border" : "content" ) ) {
+ return 0;
+ }
+
+ for ( ; i < 4; i += 2 ) {
+
+ // Both box models exclude margin
+ if ( box === "margin" ) {
+ delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
+ }
+
+ // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
+ if ( !isBorderBox ) {
+
+ // Add padding
+ delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // For "border" or "margin", add border
+ if ( box !== "padding" ) {
+ delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+
+ // But still keep track of it otherwise
+ } else {
+ extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+
+ // If we get here with a border-box (content + padding + border), we're seeking "content" or
+ // "padding" or "margin"
+ } else {
+
+ // For "content", subtract padding
+ if ( box === "content" ) {
+ delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // For "content" or "padding", subtract border
+ if ( box !== "margin" ) {
+ delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ // Account for positive content-box scroll gutter when requested by providing computedVal
+ if ( !isBorderBox && computedVal >= 0 ) {
+
+ // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
+ // Assuming integer scroll gutter, subtract the rest and round down
+ delta += Math.max( 0, Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ computedVal -
+ delta -
+ extra -
+ 0.5
+
+ // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
+ // Use an explicit zero to avoid NaN (gh-3964)
+ ) ) || 0;
+ }
+
+ return delta;
+}
+
+function getWidthOrHeight( elem, dimension, extra ) {
+
+ // Start with computed style
+ var styles = getStyles( elem ),
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
+ // Fake content-box until we know it's needed to know the true value.
+ boxSizingNeeded = !support.boxSizingReliable() || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ valueIsBorderBox = isBorderBox,
+
+ val = curCSS( elem, dimension, styles ),
+ offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
+
+ // Support: Firefox <=54
+ // Return a confounding non-pixel value or feign ignorance, as appropriate.
+ if ( rnumnonpx.test( val ) ) {
+ if ( !extra ) {
+ return val;
+ }
+ val = "auto";
+ }
+
+
+ // Support: IE 9 - 11 only
+ // Use offsetWidth/offsetHeight for when box sizing is unreliable.
+ // In those cases, the computed value can be trusted to be border-box.
+ if ( ( !support.boxSizingReliable() && isBorderBox ||
+
+ // Support: IE 10 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Interestingly, in some cases IE 9 doesn't suffer from this issue.
+ !support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
+
+ // Fall back to offsetWidth/offsetHeight when value is "auto"
+ // This happens for inline elements with no explicit setting (gh-3571)
+ val === "auto" ||
+
+ // Support: Android <=4.1 - 4.3 only
+ // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
+ !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
+
+ // Make sure the element is visible & connected
+ elem.getClientRects().length ) {
+
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // Where available, offsetWidth/offsetHeight approximate border box dimensions.
+ // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
+ // retrieved value as a content box dimension.
+ valueIsBorderBox = offsetProp in elem;
+ if ( valueIsBorderBox ) {
+ val = elem[ offsetProp ];
+ }
+ }
+
+ // Normalize "" and auto
+ val = parseFloat( val ) || 0;
+
+ // Adjust for the element's box model
+ return ( val +
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles,
+
+ // Provide the current computed size to request scroll gutter calculation (gh-3589)
+ val
+ )
+ ) + "px";
+}
+
+jQuery.extend( {
+
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "animationIterationCount": true,
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "gridArea": true,
+ "gridColumn": true,
+ "gridColumnEnd": true,
+ "gridColumnStart": true,
+ "gridRow": true,
+ "gridRowEnd": true,
+ "gridRowStart": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {},
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name ),
+ style = elem.style;
+
+ // Make sure that we're working with the right name. We don't
+ // want to query the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Gets hook for the prefixed version, then unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
+
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set (#7116)
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
+ // "px" to a few hardcoded values.
+ if ( type === "number" && !isCustomProp ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
+ }
+
+ // background-* props affect original clone's values
+ if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !( "set" in hooks ) ||
+ ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
+
+ if ( isCustomProp ) {
+ style.setProperty( name, value );
+ } else {
+ style[ name ] = value;
+ }
+ }
+
+ } else {
+
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks &&
+ ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
+
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name );
+
+ // Make sure that we're working with the right name. We don't
+ // want to modify the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Try prefixed name followed by the unprefixed name
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ // Convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Make numeric if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || isFinite( num ) ? num || 0 : val;
+ }
+
+ return val;
+ }
+} );
+
+jQuery.each( [ "height", "width" ], function( _i, dimension ) {
+ jQuery.cssHooks[ dimension ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+
+ // Support: Safari 8+
+ // Table columns in Safari have non-zero offsetWidth & zero
+ // getBoundingClientRect().width unless display is changed.
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a disconnected node
+ // in IE throws an error.
+ ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
+ swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, dimension, extra );
+ } ) :
+ getWidthOrHeight( elem, dimension, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var matches,
+ styles = getStyles( elem ),
+
+ // Only read styles.position if the test has a chance to fail
+ // to avoid forcing a reflow.
+ scrollboxSizeBuggy = !support.scrollboxSize() &&
+ styles.position === "absolute",
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
+ boxSizingNeeded = scrollboxSizeBuggy || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ subtract = extra ?
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra,
+ isBorderBox,
+ styles
+ ) :
+ 0;
+
+ // Account for unreliable border-box dimensions by comparing offset* to computed and
+ // faking a content-box to get border and padding (gh-3699)
+ if ( isBorderBox && scrollboxSizeBuggy ) {
+ subtract -= Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ parseFloat( styles[ dimension ] ) -
+ boxModelAdjustment( elem, dimension, "border", false, styles ) -
+ 0.5
+ );
+ }
+
+ // Convert to pixels if value adjustment is needed
+ if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+ ( matches[ 3 ] || "px" ) !== "px" ) {
+
+ elem.style[ dimension ] = value;
+ value = jQuery.css( elem, dimension );
+ }
+
+ return setPositiveNumber( elem, value, subtract );
+ }
+ };
+} );
+
+jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
+ function( elem, computed ) {
+ if ( computed ) {
+ return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+ elem.getBoundingClientRect().left -
+ swap( elem, { marginLeft: 0 }, function() {
+ return elem.getBoundingClientRect().left;
+ } )
+ ) + "px";
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each( {
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // Assumes a single number if not a string
+ parts = typeof value === "string" ? value.split( " " ) : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( prefix !== "margin" ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+} );
+
+jQuery.fn.extend( {
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( Array.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ }
+} );
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || jQuery.easing._default;
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ // Use a property on the element directly when it is not a DOM element,
+ // or when there is no matching style property that exists.
+ if ( tween.elem.nodeType !== 1 ||
+ tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.nodeType === 1 && (
+ jQuery.cssHooks[ tween.prop ] ||
+ tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9 only
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ },
+ _default: "swing"
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, inProgress,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rrun = /queueHooks$/;
+
+function schedule() {
+ if ( inProgress ) {
+ if ( document.hidden === false && window.requestAnimationFrame ) {
+ window.requestAnimationFrame( schedule );
+ } else {
+ window.setTimeout( schedule, jQuery.fx.interval );
+ }
+
+ jQuery.fx.tick();
+ }
+}
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ window.setTimeout( function() {
+ fxNow = undefined;
+ } );
+ return ( fxNow = Date.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ i = 0,
+ attrs = { height: type };
+
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
+
+ // We're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+ isBox = "width" in props || "height" in props,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHiddenWithinTree( elem ),
+ dataShow = dataPriv.get( elem, "fxshow" );
+
+ // Queue-skipping animations hijack the fx hooks
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always( function() {
+
+ // Ensure the complete handler is called before this completes
+ anim.always( function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ } );
+ } );
+ }
+
+ // Detect show/hide animations
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.test( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // Pretend to be hidden if this is a "show" and
+ // there is still data from a stopped show/hide
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+
+ // Ignore all other no-op show/hide data
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ // Bail out if this is a no-op like .hide().hide()
+ propTween = !jQuery.isEmptyObject( props );
+ if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+ return;
+ }
+
+ // Restrict "overflow" and "display" styles during box animations
+ if ( isBox && elem.nodeType === 1 ) {
+
+ // Support: IE <=9 - 11, Edge 12 - 15
+ // Record all 3 overflow attributes because IE does not infer the shorthand
+ // from identically-valued overflowX and overflowY and Edge just mirrors
+ // the overflowX value there.
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Identify a display type, preferring old show/hide data over the CSS cascade
+ restoreDisplay = dataShow && dataShow.display;
+ if ( restoreDisplay == null ) {
+ restoreDisplay = dataPriv.get( elem, "display" );
+ }
+ display = jQuery.css( elem, "display" );
+ if ( display === "none" ) {
+ if ( restoreDisplay ) {
+ display = restoreDisplay;
+ } else {
+
+ // Get nonempty value(s) by temporarily forcing visibility
+ showHide( [ elem ], true );
+ restoreDisplay = elem.style.display || restoreDisplay;
+ display = jQuery.css( elem, "display" );
+ showHide( [ elem ] );
+ }
+ }
+
+ // Animate inline elements as inline-block
+ if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+ if ( jQuery.css( elem, "float" ) === "none" ) {
+
+ // Restore the original display value at the end of pure show/hide animations
+ if ( !propTween ) {
+ anim.done( function() {
+ style.display = restoreDisplay;
+ } );
+ if ( restoreDisplay == null ) {
+ display = style.display;
+ restoreDisplay = display === "none" ? "" : display;
+ }
+ }
+ style.display = "inline-block";
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always( function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ } );
+ }
+
+ // Implement show/hide animations
+ propTween = false;
+ for ( prop in orig ) {
+
+ // General show/hide setup for this element animation
+ if ( !propTween ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
+ }
+
+ // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+
+ // Show elements before animating them
+ if ( hidden ) {
+ showHide( [ elem ], true );
+ }
+
+ /* eslint-disable no-loop-func */
+
+ anim.done( function() {
+
+ /* eslint-enable no-loop-func */
+
+ // The final step of a "hide" animation is actually hiding the element
+ if ( !hidden ) {
+ showHide( [ elem ] );
+ }
+ dataPriv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ } );
+ }
+
+ // Per-property setup
+ propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = propTween.start;
+ if ( hidden ) {
+ propTween.end = propTween.start;
+ propTween.start = 0;
+ }
+ }
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( Array.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = Animation.prefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+
+ // Don't match elem in the :animated selector
+ delete tick.elem;
+ } ),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+
+ // Support: Android 2.3 only
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ] );
+
+ // If there's more to do, yield
+ if ( percent < 1 && length ) {
+ return remaining;
+ }
+
+ // If this was an empty animation, synthesize a final progress notification
+ if ( !length ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ }
+
+ // Resolve the animation and report its conclusion
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ },
+ animation = deferred.promise( {
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, {
+ specialEasing: {},
+ easing: jQuery.easing._default
+ }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+
+ // If we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // Resolve when we played the last frame; otherwise, reject
+ if ( gotoEnd ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ } ),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length; index++ ) {
+ result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ if ( isFunction( result.stop ) ) {
+ jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+ result.stop.bind( result );
+ }
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ // Attach callbacks from options
+ animation
+ .progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ } )
+ );
+
+ return animation;
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweeners: {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+ return tween;
+ } ]
+ },
+
+ tweener: function( props, callback ) {
+ if ( isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.match( rnothtmlwhite );
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length; index++ ) {
+ prop = props[ index ];
+ Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+ Animation.tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilters: [ defaultPrefilter ],
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ Animation.prefilters.unshift( callback );
+ } else {
+ Animation.prefilters.push( callback );
+ }
+ }
+} );
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !isFunction( easing ) && easing
+ };
+
+ // Go to the end state if fx are off
+ if ( jQuery.fx.off ) {
+ opt.duration = 0;
+
+ } else {
+ if ( typeof opt.duration !== "number" ) {
+ if ( opt.duration in jQuery.fx.speeds ) {
+ opt.duration = jQuery.fx.speeds[ opt.duration ];
+
+ } else {
+ opt.duration = jQuery.fx.speeds._default;
+ }
+ }
+ }
+
+ // Normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend( {
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // Show any hidden elements after setting opacity to 0
+ return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
+
+ // Animate to the value specified
+ .end().animate( { opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || dataPriv.get( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each( function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = dataPriv.get( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this &&
+ ( type == null || timers[ index ].queue === type ) ) {
+
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each( function() {
+ var index,
+ data = dataPriv.get( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // Enable finishing flag on private data
+ data.finish = true;
+
+ // Empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // Look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // Turn off finishing flag
+ delete data.finish;
+ } );
+ }
+} );
+
+jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+} );
+
+// Generate shortcuts for custom animations
+jQuery.each( {
+ slideDown: genFx( "show" ),
+ slideUp: genFx( "hide" ),
+ slideToggle: genFx( "toggle" ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+} );
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ i = 0,
+ timers = jQuery.timers;
+
+ fxNow = Date.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+
+ // Run the timer and safely remove it when done (allowing for external removal)
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ jQuery.fx.start();
+};
+
+jQuery.fx.interval = 13;
+jQuery.fx.start = function() {
+ if ( inProgress ) {
+ return;
+ }
+
+ inProgress = true;
+ schedule();
+};
+
+jQuery.fx.stop = function() {
+ inProgress = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = window.setTimeout( next, time );
+ hooks.stop = function() {
+ window.clearTimeout( timeout );
+ };
+ } );
+};
+
+
+( function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
+
+ input.type = "checkbox";
+
+ // Support: Android <=4.3 only
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
+
+ // Support: IE <=11 only
+ // Must access selectedIndex to make default options select
+ support.optSelected = opt.selected;
+
+ // Support: IE <=11 only
+ // An input loses its value after becoming a radio
+ input = document.createElement( "input" );
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+} )();
+
+
+var boolHook,
+ attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend( {
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each( function() {
+ jQuery.removeAttr( this, name );
+ } );
+ }
+} );
+
+jQuery.extend( {
+ attr: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set attributes on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // Attribute hooks are determined by the lowercase version
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
+ }
+
+ if ( value !== undefined ) {
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+ }
+
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ? undefined : ret;
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" &&
+ nodeName( elem, "input" ) ) {
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name,
+ i = 0,
+
+ // Attribute names can contain non-HTML whitespace characters
+ // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
+ attrNames = value && value.match( rnothtmlwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( ( name = attrNames[ i++ ] ) ) {
+ elem.removeAttribute( name );
+ }
+ }
+ }
+} );
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ elem.setAttribute( name, name );
+ }
+ return name;
+ }
+};
+
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle,
+ lowercaseName = name.toLowerCase();
+
+ if ( !isXML ) {
+
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ lowercaseName ];
+ attrHandle[ lowercaseName ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ lowercaseName :
+ null;
+ attrHandle[ lowercaseName ] = handle;
+ }
+ return ret;
+ };
+} );
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend( {
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each( function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ } );
+ }
+} );
+
+jQuery.extend( {
+ prop: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ return ( elem[ name ] = value );
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ return elem[ name ];
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+
+ // Support: IE <=9 - 11 only
+ // elem.tabIndex doesn't always return the
+ // correct value when it hasn't been explicitly set
+ // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ if ( tabindex ) {
+ return parseInt( tabindex, 10 );
+ }
+
+ if (
+ rfocusable.test( elem.nodeName ) ||
+ rclickable.test( elem.nodeName ) &&
+ elem.href
+ ) {
+ return 0;
+ }
+
+ return -1;
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ }
+} );
+
+// Support: IE <=11 only
+// Accessing the selectedIndex property
+// forces the browser to respect setting selected
+// on the option
+// The getter ensures a default option is selected
+// when in an optgroup
+// eslint rule "no-unused-expressions" is disabled for this code
+// since it considers such accessions noop
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ },
+ set: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+ };
+}
+
+jQuery.each( [
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+} );
+
+
+
+
+ // Strip and collapse whitespace according to HTML spec
+ // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+ function stripAndCollapse( value ) {
+ var tokens = value.match( rnothtmlwhite ) || [];
+ return tokens.join( " " );
+ }
+
+
+function getClass( elem ) {
+ return elem.getAttribute && elem.getAttribute( "class" ) || "";
+}
+
+function classesToArray( value ) {
+ if ( Array.isArray( value ) ) {
+ return value;
+ }
+ if ( typeof value === "string" ) {
+ return value.match( rnothtmlwhite ) || [];
+ }
+ return [];
+}
+
+jQuery.fn.extend( {
+ addClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ if ( !arguments.length ) {
+ return this.attr( "class", "" );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isValidValue = type === "string" || Array.isArray( value );
+
+ if ( typeof stateVal === "boolean" && isValidValue ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( isFunction( value ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).toggleClass(
+ value.call( this, i, getClass( this ), stateVal ),
+ stateVal
+ );
+ } );
+ }
+
+ return this.each( function() {
+ var className, i, self, classNames;
+
+ if ( isValidValue ) {
+
+ // Toggle individual class names
+ i = 0;
+ self = jQuery( this );
+ classNames = classesToArray( value );
+
+ while ( ( className = classNames[ i++ ] ) ) {
+
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( value === undefined || type === "boolean" ) {
+ className = getClass( this );
+ if ( className ) {
+
+ // Store className if set
+ dataPriv.set( this, "__className__", className );
+ }
+
+ // If the element has a class name or if we're passed `false`,
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ if ( this.setAttribute ) {
+ this.setAttribute( "class",
+ className || value === false ?
+ "" :
+ dataPriv.get( this, "__className__" ) || ""
+ );
+ }
+ }
+ } );
+ },
+
+ hasClass: function( selector ) {
+ var className, elem,
+ i = 0;
+
+ className = " " + selector + " ";
+ while ( ( elem = this[ i++ ] ) ) {
+ if ( elem.nodeType === 1 &&
+ ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+} );
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend( {
+ val: function( value ) {
+ var hooks, ret, valueIsFunction,
+ elem = this[ 0 ];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] ||
+ jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks &&
+ "get" in hooks &&
+ ( ret = hooks.get( elem, "value" ) ) !== undefined
+ ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ // Handle most common string cases
+ if ( typeof ret === "string" ) {
+ return ret.replace( rreturn, "" );
+ }
+
+ // Handle cases where value is null/undef or number
+ return ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ valueIsFunction = isFunction( value );
+
+ return this.each( function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( valueIsFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+
+ } else if ( typeof val === "number" ) {
+ val += "";
+
+ } else if ( Array.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ } );
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ } );
+ }
+} );
+
+jQuery.extend( {
+ valHooks: {
+ option: {
+ get: function( elem ) {
+
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+
+ // Support: IE <=10 - 11 only
+ // option.text throws exceptions (#14686, #14858)
+ // Strip and collapse whitespace
+ // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+ stripAndCollapse( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option, i,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one",
+ values = one ? null : [],
+ max = one ? index + 1 : options.length;
+
+ if ( index < 0 ) {
+ i = max;
+
+ } else {
+ i = one ? index : 0;
+ }
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Support: IE <=9 only
+ // IE8-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+
+ // Don't return options that are disabled or in a disabled optgroup
+ !option.disabled &&
+ ( !option.parentNode.disabled ||
+ !nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ /* eslint-disable no-cond-assign */
+
+ if ( option.selected =
+ jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
+ ) {
+ optionSet = true;
+ }
+
+ /* eslint-enable no-cond-assign */
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+} );
+
+// Radios and checkboxes getter/setter
+jQuery.each( [ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( Array.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+ };
+ }
+} );
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+support.focusin = "onfocusin" in window;
+
+
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ stopPropagationCallback = function( e ) {
+ e.stopPropagation();
+ };
+
+jQuery.extend( jQuery.event, {
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+ cur = lastElement = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "." ) > -1 ) {
+
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split( "." );
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join( "." );
+ event.rnamespace = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === ( elem.ownerDocument || document ) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+ lastElement = cur;
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = (
+ dataPriv.get( cur, "events" ) || Object.create( null )
+ )[ event.type ] &&
+ dataPriv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( ( !special._default ||
+ special._default.apply( eventPath.pop(), data ) === false ) &&
+ acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.addEventListener( type, stopPropagationCallback );
+ }
+
+ elem[ type ]();
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.removeEventListener( type, stopPropagationCallback );
+ }
+
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ // Piggyback on a donor event to simulate a different one
+ // Used only for `focus(in | out)` events
+ simulate: function( type, elem, event ) {
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true
+ }
+ );
+
+ jQuery.event.trigger( e, null, elem );
+ }
+
+} );
+
+jQuery.fn.extend( {
+
+ trigger: function( type, data ) {
+ return this.each( function() {
+ jQuery.event.trigger( type, data, this );
+ } );
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[ 0 ];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+} );
+
+
+// Support: Firefox <=44
+// Firefox doesn't have focus(in | out) events
+// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+//
+// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+// focus(in | out) events fire after focus & blur events,
+// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+if ( !support.focusin ) {
+ jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+
+ // Handle: regular nodes (via `this.ownerDocument`), window
+ // (via `this.document`) & document (via `this`).
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ dataPriv.remove( doc, fix );
+
+ } else {
+ dataPriv.access( doc, fix, attaches );
+ }
+ }
+ };
+ } );
+}
+var location = window.location;
+
+var nonce = { guid: Date.now() };
+
+var rquery = ( /\?/ );
+
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE throws on parseFromString with invalid input.
+ try {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {
+ xml = undefined;
+ }
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( Array.isArray( obj ) ) {
+
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams(
+ prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
+ v,
+ traditional,
+ add
+ );
+ }
+ } );
+
+ } else if ( !traditional && toType( obj ) === "object" ) {
+
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, valueOrFunction ) {
+
+ // If value is a function, invoke it and use its return value
+ var value = isFunction( valueOrFunction ) ?
+ valueOrFunction() :
+ valueOrFunction;
+
+ s[ s.length ] = encodeURIComponent( key ) + "=" +
+ encodeURIComponent( value == null ? "" : value );
+ };
+
+ if ( a == null ) {
+ return "";
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ } );
+
+ } else {
+
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" );
+};
+
+jQuery.fn.extend( {
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map( function() {
+
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ } )
+ .filter( function() {
+ var type = this.type;
+
+ // Use .is( ":disabled" ) so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ } )
+ .map( function( _i, elem ) {
+ var val = jQuery( this ).val();
+
+ if ( val == null ) {
+ return null;
+ }
+
+ if ( Array.isArray( val ) ) {
+ return jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } );
+ }
+
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } ).get();
+ }
+} );
+
+
+var
+ r20 = /%20/g,
+ rhash = /#.*$/,
+ rantiCache = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat( "*" ),
+
+ // Anchor tag for parsing the document origin
+ originAnchor = document.createElement( "a" );
+ originAnchor.href = location.href;
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
+
+ if ( isFunction( func ) ) {
+
+ // For each dataType in the dataTypeExpression
+ while ( ( dataType = dataTypes[ i++ ] ) ) {
+
+ // Prepend if requested
+ if ( dataType[ 0 ] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
+
+ // Otherwise append
+ } else {
+ ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" &&
+ !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ } );
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s.throws ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return {
+ state: "parsererror",
+ error: conv ? e : "No conversion from " + prev + " to " + current
+ };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend( {
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: location.href,
+ type: "GET",
+ isLocal: rlocalProtocol.test( location.protocol ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /\bxml\b/,
+ html: /\bhtml/,
+ json: /\bjson\b/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": JSON.parse,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+
+ // URL without anti-cache param
+ cacheURL,
+
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+
+ // timeout handle
+ timeoutTimer,
+
+ // Url cleanup var
+ urlAnchor,
+
+ // Request state (becomes false upon send and true upon completion)
+ completed,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ // Loop variable
+ i,
+
+ // uncached part of the url
+ uncached,
+
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+
+ // Callbacks context
+ callbackContext = s.context || s,
+
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context &&
+ ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+
+ // Default abort message
+ strAbort = "canceled",
+
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( completed ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
+ ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
+ .concat( match[ 2 ] );
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() + " " ];
+ }
+ return match == null ? null : match.join( ", " );
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return completed ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( completed == null ) {
+ name = requestHeadersNames[ name.toLowerCase() ] =
+ requestHeadersNames[ name.toLowerCase() ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( completed == null ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( completed ) {
+
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ } else {
+
+ // Lazy-add the new callbacks in a way that preserves old ones
+ for ( code in map ) {
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+
+ // Add protocol if not provided (prefilters might expect it)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || location.href ) + "" )
+ .replace( rprotocol, location.protocol + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
+
+ // A cross-domain request is in order when the origin doesn't match the current origin.
+ if ( s.crossDomain == null ) {
+ urlAnchor = document.createElement( "a" );
+
+ // Support: IE <=8 - 11, Edge 12 - 15
+ // IE throws exception on accessing the href property if url is malformed,
+ // e.g. http://example.com:80x/
+ try {
+ urlAnchor.href = s.url;
+
+ // Support: IE <=8 - 11 only
+ // Anchor's host property isn't correctly set when s.url is relative
+ urlAnchor.href = urlAnchor.href;
+ s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+ urlAnchor.protocol + "//" + urlAnchor.host;
+ } catch ( e ) {
+
+ // If there is an error parsing the URL, assume it is crossDomain,
+ // it can be rejected by the transport if it is invalid
+ s.crossDomain = true;
+ }
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ // Remove hash to simplify url manipulation
+ cacheURL = s.url.replace( rhash, "" );
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // Remember the hash so we can put it back
+ uncached = s.url.slice( cacheURL.length );
+
+ // If data is available and should be processed, append data to url
+ if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
+ cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
+
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add or update anti-cache param if needed
+ if ( s.cache === false ) {
+ cacheURL = cacheURL.replace( rantiCache, "$1" );
+ uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
+ uncached;
+ }
+
+ // Put hash and anti-cache on the URL that will be requested (gh-1732)
+ s.url = cacheURL + uncached;
+
+ // Change '%20' to '+' if this is encoded form body content (gh-2658)
+ } else if ( s.data && s.processData &&
+ ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
+ s.data = s.data.replace( r20, "+" );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+ s.accepts[ s.dataTypes[ 0 ] ] +
+ ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend &&
+ ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
+
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // Aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ completeDeferred.add( s.complete );
+ jqXHR.done( s.success );
+ jqXHR.fail( s.error );
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+
+ // If request was aborted inside ajaxSend, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = window.setTimeout( function() {
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ completed = false;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+
+ // Rethrow post-completion exceptions
+ if ( completed ) {
+ throw e;
+ }
+
+ // Propagate others as results
+ done( -1, e );
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Ignore repeat invocations
+ if ( completed ) {
+ return;
+ }
+
+ completed = true;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ window.clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Use a noop converter for missing script
+ if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) {
+ s.converters[ "text script" ] = function() {};
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader( "Last-Modified" );
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader( "etag" );
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+
+ // Extract error from statusText and normalize for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+} );
+
+jQuery.each( [ "get", "post" ], function( _i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+
+ // Shift arguments if data argument was omitted
+ if ( isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ // The url can be an options object (which then must have .url)
+ return jQuery.ajax( jQuery.extend( {
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ }, jQuery.isPlainObject( url ) && url ) );
+ };
+} );
+
+jQuery.ajaxPrefilter( function( s ) {
+ var i;
+ for ( i in s.headers ) {
+ if ( i.toLowerCase() === "content-type" ) {
+ s.contentType = s.headers[ i ] || "";
+ }
+ }
+} );
+
+
+jQuery._evalUrl = function( url, options, doc ) {
+ return jQuery.ajax( {
+ url: url,
+
+ // Make this explicit, since user can override this through ajaxSetup (#11264)
+ type: "GET",
+ dataType: "script",
+ cache: true,
+ async: false,
+ global: false,
+
+ // Only evaluate the response if it is successful (gh-4126)
+ // dataFilter is not invoked for failure responses, so using it instead
+ // of the default converter is kludgy but it works.
+ converters: {
+ "text script": function() {}
+ },
+ dataFilter: function( response ) {
+ jQuery.globalEval( response, options, doc );
+ }
+ } );
+};
+
+
+jQuery.fn.extend( {
+ wrapAll: function( html ) {
+ var wrap;
+
+ if ( this[ 0 ] ) {
+ if ( isFunction( html ) ) {
+ html = html.call( this[ 0 ] );
+ }
+
+ // The elements to wrap the target around
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
+ }
+
+ wrap.map( function() {
+ var elem = this;
+
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
+ }
+
+ return elem;
+ } ).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( isFunction( html ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).wrapInner( html.call( this, i ) );
+ } );
+ }
+
+ return this.each( function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ } );
+ },
+
+ wrap: function( html ) {
+ var htmlIsFunction = isFunction( html );
+
+ return this.each( function( i ) {
+ jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
+ } );
+ },
+
+ unwrap: function( selector ) {
+ this.parent( selector ).not( "body" ).each( function() {
+ jQuery( this ).replaceWith( this.childNodes );
+ } );
+ return this;
+ }
+} );
+
+
+jQuery.expr.pseudos.hidden = function( elem ) {
+ return !jQuery.expr.pseudos.visible( elem );
+};
+jQuery.expr.pseudos.visible = function( elem ) {
+ return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
+};
+
+
+
+
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch ( e ) {}
+};
+
+var xhrSuccessStatus = {
+
+ // File protocol always yields status code 0, assume 200
+ 0: 200,
+
+ // Support: IE <=9 only
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport( function( options ) {
+ var callback, errorCallback;
+
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr();
+
+ xhr.open(
+ options.type,
+ options.url,
+ options.async,
+ options.username,
+ options.password
+ );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ callback = errorCallback = xhr.onload =
+ xhr.onerror = xhr.onabort = xhr.ontimeout =
+ xhr.onreadystatechange = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+
+ // Support: IE <=9 only
+ // On a manual native abort, IE9 throws
+ // errors on any property access that is not readyState
+ if ( typeof xhr.status !== "number" ) {
+ complete( 0, "error" );
+ } else {
+ complete(
+
+ // File: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
+ }
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+
+ // Support: IE <=9 only
+ // IE9 has no XHR2 but throws on binary (trac-11426)
+ // For XHR2 non-text, let the caller handle it (gh-2498)
+ ( xhr.responseType || "text" ) !== "text" ||
+ typeof xhr.responseText !== "string" ?
+ { binary: xhr.response } :
+ { text: xhr.responseText },
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
+
+ // Support: IE 9 only
+ // Use onreadystatechange to replace onabort
+ // to handle uncaught aborts
+ if ( xhr.onabort !== undefined ) {
+ xhr.onabort = errorCallback;
+ } else {
+ xhr.onreadystatechange = function() {
+
+ // Check readyState before timeout as it changes
+ if ( xhr.readyState === 4 ) {
+
+ // Allow onerror to be called first,
+ // but that will not handle a native abort
+ // Also, save errorCallback to a variable
+ // as xhr.onerror cannot be accessed
+ window.setTimeout( function() {
+ if ( callback ) {
+ errorCallback();
+ }
+ } );
+ }
+ };
+ }
+
+ // Create the abort callback
+ callback = callback( "abort" );
+
+ try {
+
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+
+ // #14683: Only rethrow if this hasn't been notified as an error yet
+ if ( callback ) {
+ throw e;
+ }
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
+jQuery.ajaxPrefilter( function( s ) {
+ if ( s.crossDomain ) {
+ s.contents.script = false;
+ }
+} );
+
+// Install script dataType
+jQuery.ajaxSetup( {
+ accepts: {
+ script: "text/javascript, application/javascript, " +
+ "application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /\b(?:java|ecma)script\b/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+} );
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ }
+} );
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+
+ // This transport only deals with cross domain or forced-by-attrs requests
+ if ( s.crossDomain || s.scriptAttrs ) {
+ var script, callback;
+ return {
+ send: function( _, complete ) {
+ script = jQuery( "<script>" )
+ .attr( s.scriptAttrs || {} )
+ .prop( { charset: s.scriptCharset, src: s.url } )
+ .on( "load error", callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
+ }
+ } );
+
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ document.head.appendChild( script[ 0 ] );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup( {
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+} );
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" &&
+ ( s.contentType || "" )
+ .indexOf( "application/x-www-form-urlencoded" ) === 0 &&
+ rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters[ "script json" ] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // Force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always( function() {
+
+ // If previous value didn't exist - remove it
+ if ( overwritten === undefined ) {
+ jQuery( window ).removeProp( callbackName );
+
+ // Otherwise restore preexisting value
+ } else {
+ window[ callbackName ] = overwritten;
+ }
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+
+ // Make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // Save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ } );
+
+ // Delegate to script
+ return "script";
+ }
+} );
+
+
+
+
+// Support: Safari 8 only
+// In Safari 8 documents created via document.implementation.createHTMLDocument
+// collapse sibling forms: the second one becomes a child of the first one.
+// Because of that, this security measure has to be disabled in Safari 8.
+// https://bugs.webkit.org/show_bug.cgi?id=137337
+support.createHTMLDocument = ( function() {
+ var body = document.implementation.createHTMLDocument( "" ).body;
+ body.innerHTML = "<form></form><form></form>";
+ return body.childNodes.length === 2;
+} )();
+
+
+// Argument "data" should be string of html
+// context (optional): If specified, the fragment will be created in this context,
+// defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( typeof data !== "string" ) {
+ return [];
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+
+ var base, parsed, scripts;
+
+ if ( !context ) {
+
+ // Stop scripts or inline event handlers from being executed immediately
+ // by using document.implementation
+ if ( support.createHTMLDocument ) {
+ context = document.implementation.createHTMLDocument( "" );
+
+ // Set the base href for the created document
+ // so any parsed elements with URLs
+ // are based on the document's URL (gh-2965)
+ base = context.createElement( "base" );
+ base.href = document.location.href;
+ context.head.appendChild( base );
+ } else {
+ context = document;
+ }
+ }
+
+ parsed = rsingleTag.exec( data );
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[ 1 ] ) ];
+ }
+
+ parsed = buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ var selector, type, response,
+ self = this,
+ off = url.indexOf( " " );
+
+ if ( off > -1 ) {
+ selector = stripAndCollapse( url.slice( off ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax( {
+ url: url,
+
+ // If "type" variable is undefined, then "GET" method will be used.
+ // Make value of this field explicit since
+ // user can override it through ajaxSetup method
+ type: type || "GET",
+ dataType: "html",
+ data: params
+ } ).done( function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ // If the request succeeds, this function gets "data", "status", "jqXHR"
+ // but they are ignored because response was set above.
+ // If it fails, this function gets "jqXHR", "status", "error"
+ } ).always( callback && function( jqXHR, status ) {
+ self.each( function() {
+ callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
+ } );
+ } );
+ }
+
+ return this;
+};
+
+
+
+
+jQuery.expr.pseudos.animated = function( elem ) {
+ return jQuery.grep( jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ } ).length;
+};
+
+
+
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // Set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
+
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( isFunction( options ) ) {
+
+ // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+ options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+
+ } else {
+ if ( typeof props.top === "number" ) {
+ props.top += "px";
+ }
+ if ( typeof props.left === "number" ) {
+ props.left += "px";
+ }
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend( {
+
+ // offset() relates an element's border box to the document origin
+ offset: function( options ) {
+
+ // Preserve chaining for setter
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each( function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ } );
+ }
+
+ var rect, win,
+ elem = this[ 0 ];
+
+ if ( !elem ) {
+ return;
+ }
+
+ // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a
+ // disconnected node in IE throws an error
+ if ( !elem.getClientRects().length ) {
+ return { top: 0, left: 0 };
+ }
+
+ // Get document-relative position by adding viewport scroll to viewport-relative gBCR
+ rect = elem.getBoundingClientRect();
+ win = elem.ownerDocument.defaultView;
+ return {
+ top: rect.top + win.pageYOffset,
+ left: rect.left + win.pageXOffset
+ };
+ },
+
+ // position() relates an element's margin box to its offset parent's padding box
+ // This corresponds to the behavior of CSS absolute positioning
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset, doc,
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
+
+ // position:fixed elements are offset from the viewport, which itself always has zero offset
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+
+ // Assume position:fixed implies availability of getBoundingClientRect
+ offset = elem.getBoundingClientRect();
+
+ } else {
+ offset = this.offset();
+
+ // Account for the *real* offset parent, which can be the document or its root element
+ // when a statically positioned element is identified
+ doc = elem.ownerDocument;
+ offsetParent = elem.offsetParent || doc.documentElement;
+ while ( offsetParent &&
+ ( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
+ jQuery.css( offsetParent, "position" ) === "static" ) {
+
+ offsetParent = offsetParent.parentNode;
+ }
+ if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
+
+ // Incorporate borders into its offset, since they are outside its content origin
+ parentOffset = jQuery( offsetParent ).offset();
+ parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
+ }
+ }
+
+ // Subtract parent offsets and element margins
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+ };
+ },
+
+ // This method will return documentElement in the following cases:
+ // 1) For the element inside the iframe without offsetParent, this method will return
+ // documentElement of the parent window
+ // 2) For the hidden or detached element
+ // 3) For body or html element, i.e. in case of the html node - it will return itself
+ //
+ // but those exceptions were never presented as a real life use-cases
+ // and might be considered as more preferable results.
+ //
+ // This logic, however, is not guaranteed and can change at any point in the future
+ offsetParent: function() {
+ return this.map( function() {
+ var offsetParent = this.offsetParent;
+
+ while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || documentElement;
+ } );
+ }
+} );
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+
+ // Coalesce documents and windows
+ var win;
+ if ( isWindow( elem ) ) {
+ win = elem;
+ } else if ( elem.nodeType === 9 ) {
+ win = elem.defaultView;
+ }
+
+ if ( val === undefined ) {
+ return win ? win[ prop ] : elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : win.pageXOffset,
+ top ? val : win.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length );
+ };
+} );
+
+// Support: Safari <=7 - 9.1, Chrome <=37 - 49
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( _i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+
+ // If curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+} );
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
+ function( defaultExtra, funcName ) {
+
+ // Margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( isWindow( elem ) ) {
+
+ // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
+ return funcName.indexOf( "outer" ) === 0 ?
+ elem[ "inner" + name ] :
+ elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable );
+ };
+ } );
+} );
+
+
+jQuery.each( [
+ "ajaxStart",
+ "ajaxStop",
+ "ajaxComplete",
+ "ajaxError",
+ "ajaxSuccess",
+ "ajaxSend"
+], function( _i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+} );
+
+
+
+
+jQuery.fn.extend( {
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ?
+ this.off( selector, "**" ) :
+ this.off( types, selector || "**", fn );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+} );
+
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+ function( _i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+ } );
+
+
+
+
+// Support: Android <=4.0 only
+// Make sure we trim BOM and NBSP
+var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+
+// Bind a function to a context, optionally partially applying any
+// arguments.
+// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
+// However, it is not slated for removal any time soon
+jQuery.proxy = function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+};
+
+jQuery.holdReady = function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+};
+jQuery.isArray = Array.isArray;
+jQuery.parseJSON = JSON.parse;
+jQuery.nodeName = nodeName;
+jQuery.isFunction = isFunction;
+jQuery.isWindow = isWindow;
+jQuery.camelCase = camelCase;
+jQuery.type = toType;
+
+jQuery.now = Date.now;
+
+jQuery.isNumeric = function( obj ) {
+
+ // As of jQuery 3.0, isNumeric is limited to
+ // strings and numbers (primitives or objects)
+ // that can be coerced to finite numbers (gh-2662)
+ var type = jQuery.type( obj );
+ return ( type === "number" || type === "string" ) &&
+
+ // parseFloat NaNs numeric-cast false positives ("")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ !isNaN( obj - parseFloat( obj ) );
+};
+
+jQuery.trim = function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+};
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ } );
+}
+
+
+
+
+var
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === "undefined" ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+} );
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..cd43001
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..e376256
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..4caff27
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..ade4aea
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..7202e44
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..e898778
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..e723e17
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..1f5f497
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..618f5b0
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..ee5e33f
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..7e8ebc1
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js
new file mode 100644
index 0000000..2a4e76d
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js
@@ -0,0 +1,2815 @@
+/*! jQuery UI - v1.12.1 - 2020-06-16
+* http://jqueryui.com
+* Includes: widget.js, form-reset-mixin.js, keycode.js, labels.js, unique-id.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/tabs.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define([ "jquery" ], factory );
+ } else {
+
+ // Browser globals
+ factory( jQuery );
+ }
+}(function( $ ) {
+
+$.ui = $.ui || {};
+
+var version = $.ui.version = "1.12.1";
+
+
+/*!
+ * jQuery UI Widget 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Widget
+//>>group: Core
+//>>description: Provides a factory for creating stateful widgets with a common API.
+//>>docs: http://api.jqueryui.com/jQuery.widget/
+//>>demos: http://jqueryui.com/widget/
+
+
+
+var widgetUuid = 0;
+var widgetSlice = Array.prototype.slice;
+
+$.cleanData = ( function( orig ) {
+ return function( elems ) {
+ var events, elem, i;
+ for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
+ try {
+
+ // Only trigger remove when necessary to save time
+ events = $._data( elem, "events" );
+ if ( events && events.remove ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+
+ // Http://bugs.jquery.com/ticket/8235
+ } catch ( e ) {}
+ }
+ orig( elems );
+ };
+} )( $.cleanData );
+
+$.widget = function( name, base, prototype ) {
+ var existingConstructor, constructor, basePrototype;
+
+ // ProxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ var proxiedPrototype = {};
+
+ var namespace = name.split( "." )[ 0 ];
+ name = name.split( "." )[ 1 ];
+ var fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ if ( $.isArray( prototype ) ) {
+ prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
+ }
+
+ // Create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+
+ // Allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // Allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ // Extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+
+ // Copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+
+ // Track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ } );
+
+ basePrototype = new base();
+
+ // We need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = ( function() {
+ function _super() {
+ return base.prototype[ prop ].apply( this, arguments );
+ }
+
+ function _superApply( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ }
+
+ return function() {
+ var __super = this._super;
+ var __superApply = this._superApply;
+ var returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ } )();
+ } );
+ constructor.prototype = $.widget.extend( basePrototype, {
+
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ } );
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // Redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
+ child._proto );
+ } );
+
+ // Remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+
+ return constructor;
+};
+
+$.widget.extend = function( target ) {
+ var input = widgetSlice.call( arguments, 1 );
+ var inputIndex = 0;
+ var inputLength = input.length;
+ var key;
+ var value;
+
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string";
+ var args = widgetSlice.call( arguments, 1 );
+ var returnValue = this;
+
+ if ( isMethodCall ) {
+
+ // If this is an empty collection, we need to have the instance method
+ // return undefined instead of the jQuery instance
+ if ( !this.length && options === "instance" ) {
+ returnValue = undefined;
+ } else {
+ this.each( function() {
+ var methodValue;
+ var instance = $.data( this, fullName );
+
+ if ( options === "instance" ) {
+ returnValue = instance;
+ return false;
+ }
+
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name +
+ " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+
+ if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name +
+ " widget instance" );
+ }
+
+ methodValue = instance[ options ].apply( instance, args );
+
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ } );
+ }
+ } else {
+
+ // Allow multiple hashes to be passed on init
+ if ( args.length ) {
+ options = $.widget.extend.apply( null, [ options ].concat( args ) );
+ }
+
+ this.each( function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} );
+ if ( instance._init ) {
+ instance._init();
+ }
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ } );
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+
+ options: {
+ classes: {},
+ disabled: false,
+
+ // Callbacks
+ create: null
+ },
+
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widgetUuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+ this.classesElementLookup = {};
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ } );
+ this.document = $( element.style ?
+
+ // Element within the document
+ element.ownerDocument :
+
+ // Element is window or document
+ element.document || element );
+ this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+
+ if ( this.options.disabled ) {
+ this._setOptionDisabled( this.options.disabled );
+ }
+
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+
+ _getCreateOptions: function() {
+ return {};
+ },
+
+ _getCreateEventData: $.noop,
+
+ _create: $.noop,
+
+ _init: $.noop,
+
+ destroy: function() {
+ var that = this;
+
+ this._destroy();
+ $.each( this.classesElementLookup, function( key, value ) {
+ that._removeClass( value, key );
+ } );
+
+ // We can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .off( this.eventNamespace )
+ .removeData( this.widgetFullName );
+ this.widget()
+ .off( this.eventNamespace )
+ .removeAttr( "aria-disabled" );
+
+ // Clean up events and states
+ this.bindings.off( this.eventNamespace );
+ },
+
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+ var parts;
+ var curOption;
+ var i;
+
+ if ( arguments.length === 0 ) {
+
+ // Don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+
+ // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "classes" ) {
+ this._setOptionClasses( value );
+ }
+
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this._setOptionDisabled( value );
+ }
+
+ return this;
+ },
+
+ _setOptionClasses: function( value ) {
+ var classKey, elements, currentElements;
+
+ for ( classKey in value ) {
+ currentElements = this.classesElementLookup[ classKey ];
+ if ( value[ classKey ] === this.options.classes[ classKey ] ||
+ !currentElements ||
+ !currentElements.length ) {
+ continue;
+ }
+
+ // We are doing this to create a new jQuery object because the _removeClass() call
+ // on the next line is going to destroy the reference to the current elements being
+ // tracked. We need to save a copy of this collection so that we can add the new classes
+ // below.
+ elements = $( currentElements.get() );
+ this._removeClass( currentElements, classKey );
+
+ // We don't use _addClass() here, because that uses this.options.classes
+ // for generating the string of classes. We want to use the value passed in from
+ // _setOption(), this is the new value of the classes option which was passed to
+ // _setOption(). We pass this value directly to _classes().
+ elements.addClass( this._classes( {
+ element: elements,
+ keys: classKey,
+ classes: value,
+ add: true
+ } ) );
+ }
+ },
+
+ _setOptionDisabled: function( value ) {
+ this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this._removeClass( this.hoverable, null, "ui-state-hover" );
+ this._removeClass( this.focusable, null, "ui-state-focus" );
+ }
+ },
+
+ enable: function() {
+ return this._setOptions( { disabled: false } );
+ },
+
+ disable: function() {
+ return this._setOptions( { disabled: true } );
+ },
+
+ _classes: function( options ) {
+ var full = [];
+ var that = this;
+
+ options = $.extend( {
+ element: this.element,
+ classes: this.options.classes || {}
+ }, options );
+
+ function processClassString( classes, checkOption ) {
+ var current, i;
+ for ( i = 0; i < classes.length; i++ ) {
+ current = that.classesElementLookup[ classes[ i ] ] || $();
+ if ( options.add ) {
+ current = $( $.unique( current.get().concat( options.element.get() ) ) );
+ } else {
+ current = $( current.not( options.element ).get() );
+ }
+ that.classesElementLookup[ classes[ i ] ] = current;
+ full.push( classes[ i ] );
+ if ( checkOption && options.classes[ classes[ i ] ] ) {
+ full.push( options.classes[ classes[ i ] ] );
+ }
+ }
+ }
+
+ this._on( options.element, {
+ "remove": "_untrackClassesElement"
+ } );
+
+ if ( options.keys ) {
+ processClassString( options.keys.match( /\S+/g ) || [], true );
+ }
+ if ( options.extra ) {
+ processClassString( options.extra.match( /\S+/g ) || [] );
+ }
+
+ return full.join( " " );
+ },
+
+ _untrackClassesElement: function( event ) {
+ var that = this;
+ $.each( that.classesElementLookup, function( key, value ) {
+ if ( $.inArray( event.target, value ) !== -1 ) {
+ that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
+ }
+ } );
+ },
+
+ _removeClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, false );
+ },
+
+ _addClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, true );
+ },
+
+ _toggleClass: function( element, keys, extra, add ) {
+ add = ( typeof add === "boolean" ) ? add : extra;
+ var shift = ( typeof element === "string" || element === null ),
+ options = {
+ extra: shift ? keys : extra,
+ keys: shift ? element : keys,
+ element: shift ? this.element : element,
+ add: add
+ };
+ options.element.toggleClass( this._classes( options ), add );
+ return this;
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement;
+ var instance = this;
+
+ // No suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // No element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+
+ // Allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // Copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ );
+ var eventName = match[ 1 ] + instance.eventNamespace;
+ var selector = match[ 2 ];
+
+ if ( selector ) {
+ delegateElement.on( eventName, selector, handlerProxy );
+ } else {
+ element.on( eventName, handlerProxy );
+ }
+ } );
+ },
+
+ _off: function( element, eventName ) {
+ eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.off( eventName ).off( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
+ }
+ } );
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
+ }
+ } );
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig;
+ var callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+
+ // The original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // Copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+
+ var hasOptions;
+ var effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue( function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ } );
+ }
+ };
+} );
+
+var widget = $.widget;
+
+
+
+
+// Support: IE8 Only
+// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
+// with a string, so we need to find the proper form.
+var form = $.fn.form = function() {
+ return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
+};
+
+
+/*!
+ * jQuery UI Form Reset Mixin 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Form Reset Mixin
+//>>group: Core
+//>>description: Refresh input widgets when their form is reset
+//>>docs: http://api.jqueryui.com/form-reset-mixin/
+
+
+
+var formResetMixin = $.ui.formResetMixin = {
+ _formResetHandler: function() {
+ var form = $( this );
+
+ // Wait for the form reset to actually happen before refreshing
+ setTimeout( function() {
+ var instances = form.data( "ui-form-reset-instances" );
+ $.each( instances, function() {
+ this.refresh();
+ } );
+ } );
+ },
+
+ _bindFormResetHandler: function() {
+ this.form = this.element.form();
+ if ( !this.form.length ) {
+ return;
+ }
+
+ var instances = this.form.data( "ui-form-reset-instances" ) || [];
+ if ( !instances.length ) {
+
+ // We don't use _on() here because we use a single event handler per form
+ this.form.on( "reset.ui-form-reset", this._formResetHandler );
+ }
+ instances.push( this );
+ this.form.data( "ui-form-reset-instances", instances );
+ },
+
+ _unbindFormResetHandler: function() {
+ if ( !this.form.length ) {
+ return;
+ }
+
+ var instances = this.form.data( "ui-form-reset-instances" );
+ instances.splice( $.inArray( this, instances ), 1 );
+ if ( instances.length ) {
+ this.form.data( "ui-form-reset-instances", instances );
+ } else {
+ this.form
+ .removeData( "ui-form-reset-instances" )
+ .off( "reset.ui-form-reset" );
+ }
+ }
+};
+
+
+/*!
+ * jQuery UI Keycode 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Keycode
+//>>group: Core
+//>>description: Provide keycodes as keynames
+//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
+
+
+var keycode = $.ui.keyCode = {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+};
+
+
+
+
+// Internal use only
+var escapeSelector = $.ui.escapeSelector = ( function() {
+ var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
+ return function( selector ) {
+ return selector.replace( selectorEscape, "\\$1" );
+ };
+} )();
+
+
+/*!
+ * jQuery UI Labels 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: labels
+//>>group: Core
+//>>description: Find all the labels associated with a given input
+//>>docs: http://api.jqueryui.com/labels/
+
+
+
+var labels = $.fn.labels = function() {
+ var ancestor, selector, id, labels, ancestors;
+
+ // Check control.labels first
+ if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
+ return this.pushStack( this[ 0 ].labels );
+ }
+
+ // Support: IE <= 11, FF <= 37, Android <= 2.3 only
+ // Above browsers do not support control.labels. Everything below is to support them
+ // as well as document fragments. control.labels does not work on document fragments
+ labels = this.eq( 0 ).parents( "label" );
+
+ // Look for the label based on the id
+ id = this.attr( "id" );
+ if ( id ) {
+
+ // We don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.eq( 0 ).parents().last();
+
+ // Get a full set of top level ancestors
+ ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
+
+ // Create a selector for the label based on the id
+ selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
+
+ labels = labels.add( ancestors.find( selector ).addBack( selector ) );
+
+ }
+
+ // Return whatever we have found for labels
+ return this.pushStack( labels );
+};
+
+
+/*!
+ * jQuery UI Unique ID 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: uniqueId
+//>>group: Core
+//>>description: Functions to generate and remove uniqueId's
+//>>docs: http://api.jqueryui.com/uniqueId/
+
+
+
+var uniqueId = $.fn.extend( {
+ uniqueId: ( function() {
+ var uuid = 0;
+
+ return function() {
+ return this.each( function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + ( ++uuid );
+ }
+ } );
+ };
+ } )(),
+
+ removeUniqueId: function() {
+ return this.each( function() {
+ if ( /^ui-id-\d+$/.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ } );
+ }
+} );
+
+
+/*!
+ * jQuery UI Controlgroup 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Controlgroup
+//>>group: Widgets
+//>>description: Visually groups form control widgets
+//>>docs: http://api.jqueryui.com/controlgroup/
+//>>demos: http://jqueryui.com/controlgroup/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/controlgroup.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
+
+var widgetsControlgroup = $.widget( "ui.controlgroup", {
+ version: "1.12.1",
+ defaultElement: "<div>",
+ options: {
+ direction: "horizontal",
+ disabled: null,
+ onlyVisible: true,
+ items: {
+ "button": "input[type=button], input[type=submit], input[type=reset], button, a",
+ "controlgroupLabel": ".ui-controlgroup-label",
+ "checkboxradio": "input[type='checkbox'], input[type='radio']",
+ "selectmenu": "select",
+ "spinner": ".ui-spinner-input"
+ }
+ },
+
+ _create: function() {
+ this._enhance();
+ },
+
+ // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
+ _enhance: function() {
+ this.element.attr( "role", "toolbar" );
+ this.refresh();
+ },
+
+ _destroy: function() {
+ this._callChildMethod( "destroy" );
+ this.childWidgets.removeData( "ui-controlgroup-data" );
+ this.element.removeAttr( "role" );
+ if ( this.options.items.controlgroupLabel ) {
+ this.element
+ .find( this.options.items.controlgroupLabel )
+ .find( ".ui-controlgroup-label-contents" )
+ .contents().unwrap();
+ }
+ },
+
+ _initWidgets: function() {
+ var that = this,
+ childWidgets = [];
+
+ // First we iterate over each of the items options
+ $.each( this.options.items, function( widget, selector ) {
+ var labels;
+ var options = {};
+
+ // Make sure the widget has a selector set
+ if ( !selector ) {
+ return;
+ }
+
+ if ( widget === "controlgroupLabel" ) {
+ labels = that.element.find( selector );
+ labels.each( function() {
+ var element = $( this );
+
+ if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
+ return;
+ }
+ element.contents()
+ .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
+ } );
+ that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
+ childWidgets = childWidgets.concat( labels.get() );
+ return;
+ }
+
+ // Make sure the widget actually exists
+ if ( !$.fn[ widget ] ) {
+ return;
+ }
+
+ // We assume everything is in the middle to start because we can't determine
+ // first / last elements until all enhancments are done.
+ if ( that[ "_" + widget + "Options" ] ) {
+ options = that[ "_" + widget + "Options" ]( "middle" );
+ } else {
+ options = { classes: {} };
+ }
+
+ // Find instances of this widget inside controlgroup and init them
+ that.element
+ .find( selector )
+ .each( function() {
+ var element = $( this );
+ var instance = element[ widget ]( "instance" );
+
+ // We need to clone the default options for this type of widget to avoid
+ // polluting the variable options which has a wider scope than a single widget.
+ var instanceOptions = $.widget.extend( {}, options );
+
+ // If the button is the child of a spinner ignore it
+ // TODO: Find a more generic solution
+ if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
+ return;
+ }
+
+ // Create the widget if it doesn't exist
+ if ( !instance ) {
+ instance = element[ widget ]()[ widget ]( "instance" );
+ }
+ if ( instance ) {
+ instanceOptions.classes =
+ that._resolveClassesValues( instanceOptions.classes, instance );
+ }
+ element[ widget ]( instanceOptions );
+
+ // Store an instance of the controlgroup to be able to reference
+ // from the outermost element for changing options and refresh
+ var widgetElement = element[ widget ]( "widget" );
+ $.data( widgetElement[ 0 ], "ui-controlgroup-data",
+ instance ? instance : element[ widget ]( "instance" ) );
+
+ childWidgets.push( widgetElement[ 0 ] );
+ } );
+ } );
+
+ this.childWidgets = $( $.unique( childWidgets ) );
+ this._addClass( this.childWidgets, "ui-controlgroup-item" );
+ },
+
+ _callChildMethod: function( method ) {
+ this.childWidgets.each( function() {
+ var element = $( this ),
+ data = element.data( "ui-controlgroup-data" );
+ if ( data && data[ method ] ) {
+ data[ method ]();
+ }
+ } );
+ },
+
+ _updateCornerClass: function( element, position ) {
+ var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
+ var add = this._buildSimpleOptions( position, "label" ).classes.label;
+
+ this._removeClass( element, null, remove );
+ this._addClass( element, null, add );
+ },
+
+ _buildSimpleOptions: function( position, key ) {
+ var direction = this.options.direction === "vertical";
+ var result = {
+ classes: {}
+ };
+ result.classes[ key ] = {
+ "middle": "",
+ "first": "ui-corner-" + ( direction ? "top" : "left" ),
+ "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
+ "only": "ui-corner-all"
+ }[ position ];
+
+ return result;
+ },
+
+ _spinnerOptions: function( position ) {
+ var options = this._buildSimpleOptions( position, "ui-spinner" );
+
+ options.classes[ "ui-spinner-up" ] = "";
+ options.classes[ "ui-spinner-down" ] = "";
+
+ return options;
+ },
+
+ _buttonOptions: function( position ) {
+ return this._buildSimpleOptions( position, "ui-button" );
+ },
+
+ _checkboxradioOptions: function( position ) {
+ return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
+ },
+
+ _selectmenuOptions: function( position ) {
+ var direction = this.options.direction === "vertical";
+ return {
+ width: direction ? "auto" : false,
+ classes: {
+ middle: {
+ "ui-selectmenu-button-open": "",
+ "ui-selectmenu-button-closed": ""
+ },
+ first: {
+ "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
+ "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
+ },
+ last: {
+ "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
+ "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
+ },
+ only: {
+ "ui-selectmenu-button-open": "ui-corner-top",
+ "ui-selectmenu-button-closed": "ui-corner-all"
+ }
+
+ }[ position ]
+ };
+ },
+
+ _resolveClassesValues: function( classes, instance ) {
+ var result = {};
+ $.each( classes, function( key ) {
+ var current = instance.options.classes[ key ] || "";
+ current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
+ result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
+ } );
+ return result;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "direction" ) {
+ this._removeClass( "ui-controlgroup-" + this.options.direction );
+ }
+
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ this._callChildMethod( value ? "disable" : "enable" );
+ return;
+ }
+
+ this.refresh();
+ },
+
+ refresh: function() {
+ var children,
+ that = this;
+
+ this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
+
+ if ( this.options.direction === "horizontal" ) {
+ this._addClass( null, "ui-helper-clearfix" );
+ }
+ this._initWidgets();
+
+ children = this.childWidgets;
+
+ // We filter here because we need to track all childWidgets not just the visible ones
+ if ( this.options.onlyVisible ) {
+ children = children.filter( ":visible" );
+ }
+
+ if ( children.length ) {
+
+ // We do this last because we need to make sure all enhancment is done
+ // before determining first and last
+ $.each( [ "first", "last" ], function( index, value ) {
+ var instance = children[ value ]().data( "ui-controlgroup-data" );
+
+ if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
+ var options = that[ "_" + instance.widgetName + "Options" ](
+ children.length === 1 ? "only" : value
+ );
+ options.classes = that._resolveClassesValues( options.classes, instance );
+ instance.element[ instance.widgetName ]( options );
+ } else {
+ that._updateCornerClass( children[ value ](), value );
+ }
+ } );
+
+ // Finally call the refresh method on each of the child widgets.
+ this._callChildMethod( "refresh" );
+ }
+ }
+} );
+
+/*!
+ * jQuery UI Checkboxradio 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Checkboxradio
+//>>group: Widgets
+//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
+//>>docs: http://api.jqueryui.com/checkboxradio/
+//>>demos: http://jqueryui.com/checkboxradio/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/button.css
+//>>css.structure: ../../themes/base/checkboxradio.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
+ version: "1.12.1",
+ options: {
+ disabled: null,
+ label: null,
+ icon: true,
+ classes: {
+ "ui-checkboxradio-label": "ui-corner-all",
+ "ui-checkboxradio-icon": "ui-corner-all"
+ }
+ },
+
+ _getCreateOptions: function() {
+ var disabled, labels;
+ var that = this;
+ var options = this._super() || {};
+
+ // We read the type here, because it makes more sense to throw a element type error first,
+ // rather then the error for lack of a label. Often if its the wrong type, it
+ // won't have a label (e.g. calling on a div, btn, etc)
+ this._readType();
+
+ labels = this.element.labels();
+
+ // If there are multiple labels, use the last one
+ this.label = $( labels[ labels.length - 1 ] );
+ if ( !this.label.length ) {
+ $.error( "No label found for checkboxradio widget" );
+ }
+
+ this.originalLabel = "";
+
+ // We need to get the label text but this may also need to make sure it does not contain the
+ // input itself.
+ this.label.contents().not( this.element[ 0 ] ).each( function() {
+
+ // The label contents could be text, html, or a mix. We concat each element to get a
+ // string representation of the label, without the input as part of it.
+ that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
+ } );
+
+ // Set the label option if we found label text
+ if ( this.originalLabel ) {
+ options.label = this.originalLabel;
+ }
+
+ disabled = this.element[ 0 ].disabled;
+ if ( disabled != null ) {
+ options.disabled = disabled;
+ }
+ return options;
+ },
+
+ _create: function() {
+ var checked = this.element[ 0 ].checked;
+
+ this._bindFormResetHandler();
+
+ if ( this.options.disabled == null ) {
+ this.options.disabled = this.element[ 0 ].disabled;
+ }
+
+ this._setOption( "disabled", this.options.disabled );
+ this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
+ this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
+
+ if ( this.type === "radio" ) {
+ this._addClass( this.label, "ui-checkboxradio-radio-label" );
+ }
+
+ if ( this.options.label && this.options.label !== this.originalLabel ) {
+ this._updateLabel();
+ } else if ( this.originalLabel ) {
+ this.options.label = this.originalLabel;
+ }
+
+ this._enhance();
+
+ if ( checked ) {
+ this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
+ if ( this.icon ) {
+ this._addClass( this.icon, null, "ui-state-hover" );
+ }
+ }
+
+ this._on( {
+ change: "_toggleClasses",
+ focus: function() {
+ this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
+ },
+ blur: function() {
+ this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
+ }
+ } );
+ },
+
+ _readType: function() {
+ var nodeName = this.element[ 0 ].nodeName.toLowerCase();
+ this.type = this.element[ 0 ].type;
+ if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
+ $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
+ " and element.type=" + this.type );
+ }
+ },
+
+ // Support jQuery Mobile enhanced option
+ _enhance: function() {
+ this._updateIcon( this.element[ 0 ].checked );
+ },
+
+ widget: function() {
+ return this.label;
+ },
+
+ _getRadioGroup: function() {
+ var group;
+ var name = this.element[ 0 ].name;
+ var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
+
+ if ( !name ) {
+ return $( [] );
+ }
+
+ if ( this.form.length ) {
+ group = $( this.form[ 0 ].elements ).filter( nameSelector );
+ } else {
+
+ // Not inside a form, check all inputs that also are not inside a form
+ group = $( nameSelector ).filter( function() {
+ return $( this ).form().length === 0;
+ } );
+ }
+
+ return group.not( this.element );
+ },
+
+ _toggleClasses: function() {
+ var checked = this.element[ 0 ].checked;
+ this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
+
+ if ( this.options.icon && this.type === "checkbox" ) {
+ this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
+ ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
+ }
+
+ if ( this.type === "radio" ) {
+ this._getRadioGroup()
+ .each( function() {
+ var instance = $( this ).checkboxradio( "instance" );
+
+ if ( instance ) {
+ instance._removeClass( instance.label,
+ "ui-checkboxradio-checked", "ui-state-active" );
+ }
+ } );
+ }
+ },
+
+ _destroy: function() {
+ this._unbindFormResetHandler();
+
+ if ( this.icon ) {
+ this.icon.remove();
+ this.iconSpace.remove();
+ }
+ },
+
+ _setOption: function( key, value ) {
+
+ // We don't allow the value to be set to nothing
+ if ( key === "label" && !value ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ this._toggleClass( this.label, null, "ui-state-disabled", value );
+ this.element[ 0 ].disabled = value;
+
+ // Don't refresh when setting disabled
+ return;
+ }
+ this.refresh();
+ },
+
+ _updateIcon: function( checked ) {
+ var toAdd = "ui-icon ui-icon-background ";
+
+ if ( this.options.icon ) {
+ if ( !this.icon ) {
+ this.icon = $( "<span>" );
+ this.iconSpace = $( "<span> </span>" );
+ this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
+ }
+
+ if ( this.type === "checkbox" ) {
+ toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
+ this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
+ } else {
+ toAdd += "ui-icon-blank";
+ }
+ this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
+ if ( !checked ) {
+ this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
+ }
+ this.icon.prependTo( this.label ).after( this.iconSpace );
+ } else if ( this.icon !== undefined ) {
+ this.icon.remove();
+ this.iconSpace.remove();
+ delete this.icon;
+ }
+ },
+
+ _updateLabel: function() {
+
+ // Remove the contents of the label ( minus the icon, icon space, and input )
+ var contents = this.label.contents().not( this.element[ 0 ] );
+ if ( this.icon ) {
+ contents = contents.not( this.icon[ 0 ] );
+ }
+ if ( this.iconSpace ) {
+ contents = contents.not( this.iconSpace[ 0 ] );
+ }
+ contents.remove();
+
+ this.label.append( this.options.label );
+ },
+
+ refresh: function() {
+ var checked = this.element[ 0 ].checked,
+ isDisabled = this.element[ 0 ].disabled;
+
+ this._updateIcon( checked );
+ this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
+ if ( this.options.label !== null ) {
+ this._updateLabel();
+ }
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOptions( { "disabled": isDisabled } );
+ }
+ }
+
+} ] );
+
+var widgetsCheckboxradio = $.ui.checkboxradio;
+
+
+/*!
+ * jQuery UI Button 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Button
+//>>group: Widgets
+//>>description: Enhances a form with themeable buttons.
+//>>docs: http://api.jqueryui.com/button/
+//>>demos: http://jqueryui.com/button/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/button.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.button", {
+ version: "1.12.1",
+ defaultElement: "<button>",
+ options: {
+ classes: {
+ "ui-button": "ui-corner-all"
+ },
+ disabled: null,
+ icon: null,
+ iconPosition: "beginning",
+ label: null,
+ showLabel: true
+ },
+
+ _getCreateOptions: function() {
+ var disabled,
+
+ // This is to support cases like in jQuery Mobile where the base widget does have
+ // an implementation of _getCreateOptions
+ options = this._super() || {};
+
+ this.isInput = this.element.is( "input" );
+
+ disabled = this.element[ 0 ].disabled;
+ if ( disabled != null ) {
+ options.disabled = disabled;
+ }
+
+ this.originalLabel = this.isInput ? this.element.val() : this.element.html();
+ if ( this.originalLabel ) {
+ options.label = this.originalLabel;
+ }
+
+ return options;
+ },
+
+ _create: function() {
+ if ( !this.option.showLabel & !this.options.icon ) {
+ this.options.showLabel = true;
+ }
+
+ // We have to check the option again here even though we did in _getCreateOptions,
+ // because null may have been passed on init which would override what was set in
+ // _getCreateOptions
+ if ( this.options.disabled == null ) {
+ this.options.disabled = this.element[ 0 ].disabled || false;
+ }
+
+ this.hasTitle = !!this.element.attr( "title" );
+
+ // Check to see if the label needs to be set or if its already correct
+ if ( this.options.label && this.options.label !== this.originalLabel ) {
+ if ( this.isInput ) {
+ this.element.val( this.options.label );
+ } else {
+ this.element.html( this.options.label );
+ }
+ }
+ this._addClass( "ui-button", "ui-widget" );
+ this._setOption( "disabled", this.options.disabled );
+ this._enhance();
+
+ if ( this.element.is( "a" ) ) {
+ this._on( {
+ "keyup": function( event ) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ event.preventDefault();
+
+ // Support: PhantomJS <= 1.9, IE 8 Only
+ // If a native click is available use it so we actually cause navigation
+ // otherwise just trigger a click event
+ if ( this.element[ 0 ].click ) {
+ this.element[ 0 ].click();
+ } else {
+ this.element.trigger( "click" );
+ }
+ }
+ }
+ } );
+ }
+ },
+
+ _enhance: function() {
+ if ( !this.element.is( "button" ) ) {
+ this.element.attr( "role", "button" );
+ }
+
+ if ( this.options.icon ) {
+ this._updateIcon( "icon", this.options.icon );
+ this._updateTooltip();
+ }
+ },
+
+ _updateTooltip: function() {
+ this.title = this.element.attr( "title" );
+
+ if ( !this.options.showLabel && !this.title ) {
+ this.element.attr( "title", this.options.label );
+ }
+ },
+
+ _updateIcon: function( option, value ) {
+ var icon = option !== "iconPosition",
+ position = icon ? this.options.iconPosition : value,
+ displayBlock = position === "top" || position === "bottom";
+
+ // Create icon
+ if ( !this.icon ) {
+ this.icon = $( "<span>" );
+
+ this._addClass( this.icon, "ui-button-icon", "ui-icon" );
+
+ if ( !this.options.showLabel ) {
+ this._addClass( "ui-button-icon-only" );
+ }
+ } else if ( icon ) {
+
+ // If we are updating the icon remove the old icon class
+ this._removeClass( this.icon, null, this.options.icon );
+ }
+
+ // If we are updating the icon add the new icon class
+ if ( icon ) {
+ this._addClass( this.icon, null, value );
+ }
+
+ this._attachIcon( position );
+
+ // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
+ // the iconSpace if there is one.
+ if ( displayBlock ) {
+ this._addClass( this.icon, null, "ui-widget-icon-block" );
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ } else {
+
+ // Position is beginning or end so remove the ui-widget-icon-block class and add the
+ // space if it does not exist
+ if ( !this.iconSpace ) {
+ this.iconSpace = $( "<span> </span>" );
+ this._addClass( this.iconSpace, "ui-button-icon-space" );
+ }
+ this._removeClass( this.icon, null, "ui-wiget-icon-block" );
+ this._attachIconSpace( position );
+ }
+ },
+
+ _destroy: function() {
+ this.element.removeAttr( "role" );
+
+ if ( this.icon ) {
+ this.icon.remove();
+ }
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ if ( !this.hasTitle ) {
+ this.element.removeAttr( "title" );
+ }
+ },
+
+ _attachIconSpace: function( iconPosition ) {
+ this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
+ },
+
+ _attachIcon: function( iconPosition ) {
+ this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
+ },
+
+ _setOptions: function( options ) {
+ var newShowLabel = options.showLabel === undefined ?
+ this.options.showLabel :
+ options.showLabel,
+ newIcon = options.icon === undefined ? this.options.icon : options.icon;
+
+ if ( !newShowLabel && !newIcon ) {
+ options.showLabel = true;
+ }
+ this._super( options );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icon" ) {
+ if ( value ) {
+ this._updateIcon( key, value );
+ } else if ( this.icon ) {
+ this.icon.remove();
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ }
+ }
+
+ if ( key === "iconPosition" ) {
+ this._updateIcon( key, value );
+ }
+
+ // Make sure we can't end up with a button that has neither text nor icon
+ if ( key === "showLabel" ) {
+ this._toggleClass( "ui-button-icon-only", null, !value );
+ this._updateTooltip();
+ }
+
+ if ( key === "label" ) {
+ if ( this.isInput ) {
+ this.element.val( value );
+ } else {
+
+ // If there is an icon, append it, else nothing then append the value
+ // this avoids removal of the icon when setting label text
+ this.element.html( value );
+ if ( this.icon ) {
+ this._attachIcon( this.options.iconPosition );
+ this._attachIconSpace( this.options.iconPosition );
+ }
+ }
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ this._toggleClass( null, "ui-state-disabled", value );
+ this.element[ 0 ].disabled = value;
+ if ( value ) {
+ this.element.blur();
+ }
+ }
+ },
+
+ refresh: function() {
+
+ // Make sure to only check disabled if its an element that supports this otherwise
+ // check for the disabled class to determine state
+ var isDisabled = this.element.is( "input, button" ) ?
+ this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOptions( { disabled: isDisabled } );
+ }
+
+ this._updateTooltip();
+ }
+} );
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+
+ // Text and Icons options
+ $.widget( "ui.button", $.ui.button, {
+ options: {
+ text: true,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+
+ _create: function() {
+ if ( this.options.showLabel && !this.options.text ) {
+ this.options.showLabel = this.options.text;
+ }
+ if ( !this.options.showLabel && this.options.text ) {
+ this.options.text = this.options.showLabel;
+ }
+ if ( !this.options.icon && ( this.options.icons.primary ||
+ this.options.icons.secondary ) ) {
+ if ( this.options.icons.primary ) {
+ this.options.icon = this.options.icons.primary;
+ } else {
+ this.options.icon = this.options.icons.secondary;
+ this.options.iconPosition = "end";
+ }
+ } else if ( this.options.icon ) {
+ this.options.icons.primary = this.options.icon;
+ }
+ this._super();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "text" ) {
+ this._super( "showLabel", value );
+ return;
+ }
+ if ( key === "showLabel" ) {
+ this.options.text = value;
+ }
+ if ( key === "icon" ) {
+ this.options.icons.primary = value;
+ }
+ if ( key === "icons" ) {
+ if ( value.primary ) {
+ this._super( "icon", value.primary );
+ this._super( "iconPosition", "beginning" );
+ } else if ( value.secondary ) {
+ this._super( "icon", value.secondary );
+ this._super( "iconPosition", "end" );
+ }
+ }
+ this._superApply( arguments );
+ }
+ } );
+
+ $.fn.button = ( function( orig ) {
+ return function() {
+ if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
+ ( this.length && this[ 0 ].tagName === "INPUT" && (
+ this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
+ ) ) ) {
+ return orig.apply( this, arguments );
+ }
+ if ( !$.ui.checkboxradio ) {
+ $.error( "Checkboxradio widget missing" );
+ }
+ if ( arguments.length === 0 ) {
+ return this.checkboxradio( {
+ "icon": false
+ } );
+ }
+ return this.checkboxradio.apply( this, arguments );
+ };
+ } )( $.fn.button );
+
+ $.fn.buttonset = function() {
+ if ( !$.ui.controlgroup ) {
+ $.error( "Controlgroup widget missing" );
+ }
+ if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
+ return this.controlgroup.apply( this,
+ [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
+ }
+ if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
+ return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
+ }
+ if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
+ arguments[ 0 ].items = {
+ button: arguments[ 0 ].items
+ };
+ }
+ return this.controlgroup.apply( this, arguments );
+ };
+}
+
+var widgetsButton = $.ui.button;
+
+
+
+var safeActiveElement = $.ui.safeActiveElement = function( document ) {
+ var activeElement;
+
+ // Support: IE 9 only
+ // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+ try {
+ activeElement = document.activeElement;
+ } catch ( error ) {
+ activeElement = document.body;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE may return null instead of an element
+ // Interestingly, this only seems to occur when NOT in an iframe
+ if ( !activeElement ) {
+ activeElement = document.body;
+ }
+
+ // Support: IE 11 only
+ // IE11 returns a seemingly empty object in some cases when accessing
+ // document.activeElement from an <iframe>
+ if ( !activeElement.nodeName ) {
+ activeElement = document.body;
+ }
+
+ return activeElement;
+};
+
+
+/*!
+ * jQuery UI Tabs 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Tabs
+//>>group: Widgets
+//>>description: Transforms a set of container elements into a tab structure.
+//>>docs: http://api.jqueryui.com/tabs/
+//>>demos: http://jqueryui.com/tabs/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/tabs.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.tabs", {
+ version: "1.12.1",
+ delay: 300,
+ options: {
+ active: null,
+ classes: {
+ "ui-tabs": "ui-corner-all",
+ "ui-tabs-nav": "ui-corner-all",
+ "ui-tabs-panel": "ui-corner-bottom",
+ "ui-tabs-tab": "ui-corner-top"
+ },
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // Callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _isLocal: ( function() {
+ var rhash = /#.*$/;
+
+ return function( anchor ) {
+ var anchorUrl, locationUrl;
+
+ anchorUrl = anchor.href.replace( rhash, "" );
+ locationUrl = location.href.replace( rhash, "" );
+
+ // Decoding may throw an error if the URL isn't UTF-8 (#9518)
+ try {
+ anchorUrl = decodeURIComponent( anchorUrl );
+ } catch ( error ) {}
+ try {
+ locationUrl = decodeURIComponent( locationUrl );
+ } catch ( error ) {}
+
+ return anchor.hash.length > 1 && anchorUrl === locationUrl;
+ };
+ } )(),
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
+ this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ } )
+ ) ).sort();
+ }
+
+ // Check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each( function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ } );
+ }
+
+ // Check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // No active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // Handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // Don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control/command key will prevent automatic activation
+ if ( !event.ctrlKey && !event.metaKey ) {
+
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay( function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.trigger( "focus" );
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).trigger( "focus" );
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "collapsible" ) {
+ this._toggleClass( "ui-tabs-collapsible", null, value );
+
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // Get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ } );
+
+ this._processTabs();
+
+ // Was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+
+ // was active, active tab still exists
+ } else {
+
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setOptionDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr( {
+ "aria-selected": "false",
+ "aria-expanded": "false",
+ tabIndex: -1
+ } );
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr( {
+ "aria-hidden": "true"
+ } );
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .attr( {
+ "aria-selected": "true",
+ "aria-expanded": "true",
+ tabIndex: 0
+ } );
+ this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
+ this._getPanelForTab( this.active )
+ .show()
+ .attr( {
+ "aria-hidden": "false"
+ } );
+ }
+ },
+
+ _processTabs: function() {
+ var that = this,
+ prevTabs = this.tabs,
+ prevAnchors = this.anchors,
+ prevPanels = this.panels;
+
+ this.tablist = this._getList().attr( "role", "tablist" );
+ this._addClass( this.tablist, "ui-tabs-nav",
+ "ui-helper-reset ui-helper-clearfix ui-widget-header" );
+
+ // Prevent users from focusing disabled tabs via click
+ this.tablist
+ .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ } )
+
+ // Support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ } );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .attr( {
+ role: "tab",
+ tabIndex: -1
+ } );
+ this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
+
+ this.anchors = this.tabs.map( function() {
+ return $( "a", this )[ 0 ];
+ } )
+ .attr( {
+ role: "presentation",
+ tabIndex: -1
+ } );
+ this._addClass( this.anchors, "ui-tabs-anchor" );
+
+ this.panels = $();
+
+ this.anchors.each( function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // Inline tab
+ if ( that._isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panelId = selector.substring( 1 );
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+
+ // remote tab
+ } else {
+
+ // If the tab doesn't already have aria-controls,
+ // generate an id by using a throw-away element
+ panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length ) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr( {
+ "aria-controls": panelId,
+ "aria-labelledby": anchorId
+ } );
+ panel.attr( "aria-labelledby", anchorId );
+ } );
+
+ this.panels.attr( "role", "tabpanel" );
+ this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
+
+ // Avoid memory leaks (#10056)
+ if ( prevTabs ) {
+ this._off( prevTabs.not( this.tabs ) );
+ this._off( prevAnchors.not( this.anchors ) );
+ this._off( prevPanels.not( this.panels ) );
+ }
+ },
+
+ // Allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setOptionDisabled: function( disabled ) {
+ var currentItem, li, i;
+
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // Disable tabs
+ for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
+ currentItem = $( li );
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ currentItem.attr( "aria-disabled", "true" );
+ this._addClass( currentItem, null, "ui-state-disabled" );
+ } else {
+ currentItem.removeAttr( "aria-disabled" );
+ this._removeClass( currentItem, null, "ui-state-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+
+ this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
+ disabled === true );
+ },
+
+ _setupEvents: function( event ) {
+ var events = {};
+ if ( event ) {
+ $.each( event.split( " " ), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ } );
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+
+ // Always prevent the default action, even when disabled
+ this._on( true, this.anchors, {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ } );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each( function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ } );
+
+ this.element.children().not( this.panels ).each( function() {
+ maxHeight -= $( this ).outerHeight( true );
+ } );
+
+ this.panels.each( function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ } )
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each( function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ } ).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+
+ // can't switch durning an animation
+ this.running ||
+
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // Handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // Start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ that._removeClass( eventData.oldTab.closest( "li" ),
+ "ui-tabs-active", "ui-state-active" );
+ show();
+ } );
+ } else {
+ this._removeClass( eventData.oldTab.closest( "li" ),
+ "ui-tabs-active", "ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr( "aria-hidden", "true" );
+ eventData.oldTab.attr( {
+ "aria-selected": "false",
+ "aria-expanded": "false"
+ } );
+
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter( function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ } )
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr( "aria-hidden", "false" );
+ eventData.newTab.attr( {
+ "aria-selected": "true",
+ "aria-expanded": "true",
+ tabIndex: 0
+ } );
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // Trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // Trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler( {
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ } );
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" +
+ $.ui.escapeSelector( index ) + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.tablist
+ .removeAttr( "role" )
+ .off( this.eventNamespace );
+
+ this.anchors
+ .removeAttr( "role tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each( function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this ).removeAttr( "role tabIndex " +
+ "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
+ }
+ } );
+
+ this.tabs.each( function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ } );
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ } );
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ } );
+ }
+ }
+ this._setOptionDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setOptionDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ },
+ complete = function( jqXHR, status ) {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ that._removeClass( tab, "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ };
+
+ // Not remote
+ if ( this._isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // Support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ this._addClass( tab, "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .done( function( response, status, jqXHR ) {
+
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout( function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+
+ complete( jqXHR, status );
+ }, 1 );
+ } )
+ .fail( function( jqXHR, status ) {
+
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout( function() {
+ complete( jqXHR, status );
+ }, 1 );
+ } );
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+
+ // Support: IE <11 only
+ // Strip any hash that exists to prevent errors with the Ajax request
+ url: anchor.attr( "href" ).replace( /#.*$/, "" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+} );
+
+// DEPRECATED
+// TODO: Switch return back to widget declaration at top of file when this is removed
+if ( $.uiBackCompat !== false ) {
+
+ // Backcompat for ui-tab class (now ui-tabs-tab)
+ $.widget( "ui.tabs", $.ui.tabs, {
+ _processTabs: function() {
+ this._superApply( arguments );
+ this._addClass( this.tabs, "ui-tab" );
+ }
+ } );
+}
+
+var widgetsTabs = $.ui.tabs;
+
+
+
+
+})); \ No newline at end of file
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css
new file mode 100644
index 0000000..b4e4056
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css
@@ -0,0 +1,286 @@
+/*!
+ * jQuery UI CSS Framework 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ */
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+ z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important;
+ pointer-events: none;
+}
+
+
+/* Icons
+----------------------------------*/
+.ui-icon {
+ display: inline-block;
+ vertical-align: middle;
+ margin-top: -.25em;
+ position: relative;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
+
+.ui-widget-icon-block {
+ left: 50%;
+ margin-left: -8px;
+ display: block;
+}
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+.ui-button {
+ padding: .4em 1em;
+ display: inline-block;
+ position: relative;
+ line-height: normal;
+ margin-right: .1em;
+ cursor: pointer;
+ vertical-align: middle;
+ text-align: center;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ /* Support: IE <= 11 */
+ overflow: visible;
+}
+
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+ text-decoration: none;
+}
+
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+ width: 2em;
+ box-sizing: border-box;
+ text-indent: -9999px;
+ white-space: nowrap;
+}
+
+/* no icon support for input elements */
+input.ui-button.ui-button-icon-only {
+ text-indent: 0;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-top: -8px;
+ margin-left: -8px;
+}
+
+.ui-button.ui-icon-notext .ui-icon {
+ padding: 0;
+ width: 2.1em;
+ height: 2.1em;
+ text-indent: -9999px;
+ white-space: nowrap;
+
+}
+
+input.ui-button.ui-icon-notext .ui-icon {
+ width: auto;
+ height: auto;
+ text-indent: 0;
+ white-space: normal;
+ padding: .4em 1em;
+}
+
+/* workarounds */
+/* Support: Firefox 5 - 40 */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+.ui-controlgroup {
+ vertical-align: middle;
+ display: inline-block;
+}
+.ui-controlgroup > .ui-controlgroup-item {
+ float: left;
+ margin-left: 0;
+ margin-right: 0;
+}
+.ui-controlgroup > .ui-controlgroup-item:focus,
+.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus {
+ z-index: 9999;
+}
+.ui-controlgroup-vertical > .ui-controlgroup-item {
+ display: block;
+ float: none;
+ width: 100%;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: left;
+}
+.ui-controlgroup-vertical .ui-controlgroup-item {
+ box-sizing: border-box;
+}
+.ui-controlgroup .ui-controlgroup-label {
+ padding: .4em 1em;
+}
+.ui-controlgroup .ui-controlgroup-label span {
+ font-size: 80%;
+}
+.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item {
+ border-left: none;
+}
+.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item {
+ border-top: none;
+}
+.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content {
+ border-right: none;
+}
+.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content {
+ border-bottom: none;
+}
+
+/* Spinner specific style fixes */
+.ui-controlgroup-vertical .ui-spinner-input {
+
+ /* Support: IE8 only, Android < 4.4 only */
+ width: 75%;
+ width: calc( 100% - 2.4em );
+}
+.ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
+ border-top-style: solid;
+}
+
+.ui-checkboxradio-label .ui-icon-background {
+ box-shadow: inset 1px 1px 1px #ccc;
+ border-radius: .12em;
+ border: none;
+}
+.ui-checkboxradio-radio-label .ui-icon-background {
+ width: 16px;
+ height: 16px;
+ border-radius: 1em;
+ overflow: visible;
+ border: none;
+}
+.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
+.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
+ background-image: none;
+ width: 8px;
+ height: 8px;
+ border-width: 4px;
+ border-style: solid;
+}
+.ui-checkboxradio-disabled {
+ pointer-events: none;
+}
+.ui-tabs {
+ position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+ padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+ margin: 0;
+ padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+ list-style: none;
+ float: left;
+ position: relative;
+ top: 0;
+ margin: 1px .2em 0 0;
+ border-bottom-width: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+ float: left;
+ padding: .5em 1em;
+ text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+ margin-bottom: -1px;
+ padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+ cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+ cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+ display: block;
+ border-width: 0;
+ padding: 1em 1.4em;
+ background: none;
+}
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css
new file mode 100644
index 0000000..3c5908b
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css
@@ -0,0 +1,443 @@
+/*!
+ * jQuery UI CSS Framework 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=smoothness&cornerRadiusShadow=8px&offsetLeftShadow=-8px&offsetTopShadow=-8px&thicknessShadow=8px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=aaaaaa&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cd0a0a&fcError=cd0a0a&borderColorError=cd0a0a&bgImgOpacityError=95&bgTextureError=glass&bgColorError=fef1ec&iconColorHighlight=2e83ff&fcHighlight=363636&borderColorHighlight=fcefa1&bgImgOpacityHighlight=55&bgTextureHighlight=glass&bgColorHighlight=fbf9ee&iconColorActive=454545&fcActive=212121&borderColorActive=aaaaaa&bgImgOpacityActive=65&bgTextureActive=glass&bgColorActive=ffffff&iconColorHover=454545&fcHover=212121&borderColorHover=999999&bgImgOpacityHover=75&bgTextureHover=glass&bgColorHover=dadada&iconColorDefault=888888&fcDefault=555555&borderColorDefault=d3d3d3&bgImgOpacityDefault=75&bgTextureDefault=glass&bgColorDefault=e6e6e6&iconColorContent=222222&fcContent=222222&borderColorContent=aaaaaa&bgImgOpacityContent=75&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=222222&fcHeader=222222&borderColorHeader=aaaaaa&bgImgOpacityHeader=75&bgTextureHeader=highlight_soft&bgColorHeader=cccccc&cornerRadius=4px&fsDefault=1.1em&fwDefault=normal&ffDefault=Verdana%2CArial%2Csans-serif
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+ font-family: Verdana,Arial,sans-serif;
+ font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+ font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+ font-family: Verdana,Arial,sans-serif;
+ font-size: 1em;
+}
+.ui-widget.ui-widget-content {
+ border: 1px solid #d3d3d3;
+}
+.ui-widget-content {
+ border: 1px solid #aaaaaa;
+ background: #ffffff;
+ color: #222222;
+}
+.ui-widget-content a {
+ color: #222222;
+}
+.ui-widget-header {
+ border: 1px solid #aaaaaa;
+ background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+ color: #222222;
+ font-weight: bold;
+}
+.ui-widget-header a {
+ color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default,
+.ui-button,
+
+/* We use html here because we need a greater specificity to make sure disabled
+works properly when clicked or hovered */
+html .ui-button.ui-state-disabled:hover,
+html .ui-button.ui-state-disabled:active {
+ border: 1px solid #d3d3d3;
+ background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #555555;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited,
+a.ui-button,
+a:link.ui-button,
+a:visited.ui-button,
+.ui-button {
+ color: #555555;
+ text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus,
+.ui-button:hover,
+.ui-button:focus {
+ border: 1px solid #999999;
+ background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #212121;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited,
+a.ui-button:hover,
+a.ui-button:focus {
+ color: #212121;
+ text-decoration: none;
+}
+
+.ui-visual-focus {
+ box-shadow: 0 0 3px 1px rgb(94, 158, 214);
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active,
+a.ui-button:active,
+.ui-button:active,
+.ui-button.ui-state-active:hover {
+ border: 1px solid #aaaaaa;
+ background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #212121;
+}
+.ui-icon-background,
+.ui-state-active .ui-icon-background {
+ border: #aaaaaa;
+ background-color: #212121;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+ color: #212121;
+ text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+ border: 1px solid #fcefa1;
+ background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
+ color: #363636;
+}
+.ui-state-checked {
+ border: 1px solid #fcefa1;
+ background: #fbf9ee;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+ color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+ border: 1px solid #cd0a0a;
+ background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
+ color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+ color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+ color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+ font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+ opacity: .7;
+ filter:Alpha(Opacity=70); /* support: IE8 */
+ font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+ opacity: .35;
+ filter:Alpha(Opacity=35); /* support: IE8 */
+ background-image: none;
+}
+.ui-state-disabled .ui-icon {
+ filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ width: 16px;
+ height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+ background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+ background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon,
+.ui-button:hover .ui-icon,
+.ui-button:focus .ui-icon {
+ background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-active .ui-icon,
+.ui-button:active .ui-icon {
+ background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon,
+.ui-button .ui-state-highlight.ui-icon {
+ background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+ background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+.ui-button .ui-icon {
+ background-image: url("images/ui-icons_888888_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-caret-1-n { background-position: 0 0; }
+.ui-icon-caret-1-ne { background-position: -16px 0; }
+.ui-icon-caret-1-e { background-position: -32px 0; }
+.ui-icon-caret-1-se { background-position: -48px 0; }
+.ui-icon-caret-1-s { background-position: -65px 0; }
+.ui-icon-caret-1-sw { background-position: -80px 0; }
+.ui-icon-caret-1-w { background-position: -96px 0; }
+.ui-icon-caret-1-nw { background-position: -112px 0; }
+.ui-icon-caret-2-n-s { background-position: -128px 0; }
+.ui-icon-caret-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -65px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -65px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 1px -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+ border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+ border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+ border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+ border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+ background: #aaaaaa;
+ opacity: .3;
+ filter: Alpha(Opacity=30); /* support: IE8 */
+}
+.ui-widget-shadow {
+ -webkit-box-shadow: -8px -8px 8px #aaaaaa;
+ box-shadow: -8px -8px 8px #aaaaaa;
+}
diff --git a/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2 b/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2
new file mode 100644
index 0000000..f055e4a
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css b/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css
new file mode 100644
index 0000000..63fb850
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css
@@ -0,0 +1,839 @@
+/**
+ * ----------------------------------------------------------------------
+ * Icon Font for jQuery UI
+ * ----------------------------------------------------------------------
+ *
+ * ICON FONT Version: 2.1
+ * Glyphs: 332
+ * Copyright: (c) 2015-2017 Michael Keck.
+ * License: CC BY-SA 3.0
+ * https://creativecommons.org/licenses/by-sa/3.0/
+ * Generated: with IcoMoon-App (Chromium)
+ *
+ * STYLESHEET Version: 2.3.2
+ * Modified: 2017-03-04
+ * jQuery UI: 1.12 & 1.12.1
+ * jQMobile: 1.4.5
+ * Copyright: (c) 2015-2017 Michael Keck.
+ * License: GPL license
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+/* load icon font */
+@font-face {
+ font-family: 'jquery-ui';
+ src: url('font/jquery-ui.woff2?juif-bac778') format("woff2");
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+}
+
+
+/* basic settings */
+html .ui-icon {
+ background-image: none !important;
+ display: inline-block;
+ font: normal normal normal 14px/16px sans-serif;
+ height: 1.2em;
+ line-height: 1.2em;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: relative;
+ text-indent: -99999em;
+ vertical-align: middle;
+ width: 1.2em;
+}
+
+/* UI-Icons */
+html .ui-icon:after {
+ display: block;
+ font-family: 'jquery-ui', sans-serif;
+ height: 1em;
+ left: 50%;
+ line-height: 1;
+ margin: -.5em;
+ position: absolute;
+ text-align: center;
+ text-indent: 0;
+ text-transform: none;
+ top: 50%;
+ vertical-align: middle;
+ width: 1em;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-transform: translate(0,0);
+ -moz-transform: translate(0,0);
+ transform: translate(0,0);
+}
+
+
+/**
+ * --------------------------------------------------------
+ * jQuery UI 1.12.x
+ * --------------------------------------------------------
+ */
+
+/* positioning on button element(s) */
+html .ui-button,
+html .ui-controlgroup .ui-controlgroup-label,
+html .ui-spinner .ui-spinner-input {
+ line-height: inherit;
+}
+html .ui-controlgroup .ui-controlgroup-label span {
+ line-height: 1;
+ margin: 0;
+ padding: 0;
+}
+html .ui-button .ui-icon {
+ margin: -.25em 0 -.15em 0;
+}
+html .ui-button-icon-only {
+ min-width: 2.5em;
+}
+html .ui-button-icon-only .ui-icon {
+ left: 50%;
+ margin: -0.6em 0 0 -.6em;
+ position: absolute;
+ top: 50%;
+}
+html .ui-selectmenu-button .ui-icon {
+ margin: -.6em 0 0 0;
+ position: absolute;
+ right: .5em;
+ top: 50%;
+}
+html .ui-selectmenu-text {
+ margin-right: 1em;
+}
+html .ui-spinner .ui-spinner-input {
+ margin: 0;
+ padding: .4em 2.5em .4em 1em;
+}
+html .ui-widget-icon-block {
+ display: block;
+ left: auto;
+ margin: 0;
+ width: 100%;
+ position: relative;
+}
+
+html .ui-datepicker .ui-datepicker-prev .ui-icon,
+html .ui-datepicker .ui-datepicker-next .ui-icon {
+ margin-left: -0.6em;
+ margin-top: -0.6em;
+}
+
+/* close button positioning on dialogs titlebar */
+html .ui-dialog .ui-dialog-titlebar-close {
+ height: 1.8em;
+ margin: -0.9em 0 0 0;
+ right: 0.3em;
+ width: 1.8em;
+}
+/* resizable on dialog */
+html .ui-dialog .ui-resizable-se {
+ bottom: 1px;
+ display: block;
+ height: 1em;
+ position: absolute;
+ right: 1px;
+ width: 1em;
+}
+.ui-dialog .ui-resizable-se:after {
+ left: 0;
+ margin: 0;
+ top: 0
+}
+/* positioning on accordion(s) */
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+ margin-left: -0.2em;
+ margin-right: 0.4em;
+}
+
+html .ui-icon-background,
+html .ui-state-active .ui-icon-background,
+html .ui-checkboxradio-label .ui-icon-background,
+html .ui-checkboxradio-radio-label .ui-icon-background,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
+ background-color: rgba(0,0,0,.25);
+ border: 0 none;
+ color:inherit;
+ font: normal normal normal 14px/16px sans-serif;
+ height: 1.2em;
+ line-height: 1.2em;
+ width: 1.2em;
+ -webkit-box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ -moz-box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+
+/* etxra */
+.has-left-icon li,
+li.has-left-icon {
+ list-style: none;
+}
+.has-left-icon[class^="ui-icon-"],
+.has-left-icon[class*=" ui-icon-"],
+.has-left-icon [class^="ui-icon-"],
+.has-left-icon [class*=" ui-icon-"] {
+ padding-left: 1.5em;
+ position: relative;
+}
+.has-left-icon[class^="ui-icon-"]:after,
+.has-left-icon[class*=" ui-icon-"]:after,
+.has-left-icon [class^="ui-icon-"]:after,
+.has-left-icon [class*=" ui-icon-"]:after {
+ left: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+}
+.has-right-icon[class^="ui-icon-"],
+.has-right-icon[class*=" ui-icon-"],
+.has-right-icon [class^="ui-icon-"],
+.has-right-icon [class*=" ui-icon-"] {
+ padding-right: 1.5em;
+ position: relative;
+}
+.has-right-icon[class^="ui-icon-"]:after,
+.has-right-icon[class*=" ui-icon-"]:after,
+.has-right-icon [class^="ui-icon-"]:after,
+.has-right-icon [class*=" ui-icon-"]:after {
+ right: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+}
+
+
+/**
+ * --------------------------------------------------------
+ * jQuery Mobile
+ * (testet with version 1.4.5)
+ * --------------------------------------------------------
+ */
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-btn-icon-left:after,
+.ui-mobile .ui-btn-icon-right:after,
+.ui-mobile .ui-btn-icon-top:after,
+.ui-mobile .ui-btn-icon-bottom:after,
+.ui-mobile .ui-btn-icon-notext:after {
+ background-image: none !important;
+ color: #fff;
+ display: block;
+ height: 20px;
+ font: normal normal normal 14px 'jquery-ui', sans-serif;
+ left: 50%;
+ line-height: 14px;
+ margin-left: -10px;
+ margin-top: -10px;
+ padding: 3px;
+ position: absolute;
+ text-align: center;
+ text-indent: 0;
+ text-shadow: none;
+ text-transform: none;
+ top: 50%;
+ vertical-align: middle;
+ width: 20px;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-transform: translate(0,0);
+ -moz-transform: translate(0,0);
+ transform: translate(0,0);
+}
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-left:after, .ui-mobile .ui-alt-icon .ui-btn-icon-left:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-right:after, .ui-mobile .ui-alt-icon .ui-btn-icon-right:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-top:after, .ui-mobile .ui-alt-icon .ui-btn-icon-top:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-bottom:after, .ui-mobile .ui-alt-icon .ui-btn-icon-bottom:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-notext:after, .ui-mobile .ui-alt-icon .ui-btn-icon-notext:after {
+ color: #000;
+}
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-btn-icon-left:after {
+ left: .37em;
+ margin-left: 0;
+}
+.ui-mobile .ui-btn-icon-right:after {
+ left: auto;
+ margin-left: 0;
+ right: .37em;
+}
+.ui-mobile .ui-mini.ui-btn-icon-left:after,
+.ui-mobile .ui-mini .ui-btn-icon-left:after,
+.ui-mobile .ui-header .ui-btn-icon-left:after,
+.ui-mobile .ui-footer .ui-btn-icon-left:after {
+ left: .37em;
+}
+.ui-mobile .ui-mini.ui-btn-icon-right:after,
+.ui-mobile .ui-mini .ui-btn-icon-right:after,
+.ui-mobile .ui-header .ui-btn-icon-right:after,
+.ui-mobile .ui-footer .ui-btn-icon-right:after {
+ right: .37em;
+}
+.ui-mobile .ui-btn-icon-top:after {
+ margin-top: 0;
+ top: .5625em;
+}
+.ui-mobile .ui-btn-icon-bottom:after {
+ bottom: .5625em;
+ margin-top: 0;
+ top: auto;
+}
+
+.ui-btn.ui-checkbox-on.ui-checkbox-on:after {
+ color: #fff;
+}
+.ui-btn.ui-checkbox-off:after,
+.ui-btn.ui-checkbox-on:after,
+.ui-btn.ui-radio-off:after,
+.ui-btn.ui-radio-on:after {
+ display: block;
+ font-size: 14px;
+ height: 20px;
+ margin: -10px 2px 0 2px;
+ padding: 3px;
+ width: 20px;
+}
+.ui-mini .ui-btn.ui-checkbox-off:after,
+.ui-mini .ui-btn.ui-checkbox-on:after,
+.ui-mini .ui-btn.ui-radio-off:after,
+.ui-mini .ui-btn.ui-radio-on:after {
+ height: 18px;
+ margin: -9px 2px 0 2px;
+ padding: 2px;
+ width: 18px;
+}
+.ui-alt-icon.ui-btn.ui-checkbox-on:after,
+.ui-alt-icon .ui-btn.ui-checkbox-on:after {
+ color: #000;
+}
+.ui-radio .ui-btn.ui-radio-on:after {
+ background: #fff none 0 0 no-repeat;
+ border-style: solid;
+ border-width: 5px;
+ height: 20px;
+ padding: 0;
+ text-indent: -9999px;
+ width: 20px;
+}
+.ui-mini .ui-radio .ui-btn.ui-radio-on:after {
+ height: 18px;
+ border-width: 4px;
+ width: 18px;
+}
+.ui-alt-icon.ui-btn.ui-radio-on:after,
+.ui-alt-icon .ui-btn.ui-radio-on:after {
+ background-color: #000;
+}
+
+
+
+/* apply glyphs to icons */
+.ui-icon-blank:after { content: ' '; } /* <-- yeah, this really needed! */
+.ui-icon-addon:after,
+.ui-icon-puzzle:after { content: '\e6ca'; }
+.ui-icon-address:after { content: '\e702'; }
+.ui-icon-alert:after { content: '\e65f'; }
+.ui-icon-alert-b:after { content: '\e660'; }
+.ui-icon-anchor:after { content: '\e6ba'; }
+.ui-icon-archive:after { content: '\e70d'; }
+.ui-icon-arrow-1-e:after,
+.ui-icon-arrow-r:after { content: '\e603'; }
+.ui-icon-arrow-1-n:after,
+.ui-icon-arrow-u:after { content: '\e601'; }
+.ui-icon-arrow-1-ne:after,
+.ui-icon-arrow-u-r:after { content: '\e602'; }
+.ui-icon-arrow-1-nw:after,
+.ui-icon-arrow-u-l:after { content: '\e608'; }
+.ui-icon-arrow-1-s:after,
+.ui-icon-arrow-d:after { content: '\e605'; }
+.ui-icon-arrow-1-se:after,
+.ui-icon-arrow-d-r:after { content: '\e604'; }
+.ui-icon-arrow-1-sw:after,
+.ui-icon-arrow-d-l:after { content: '\e606'; }
+.ui-icon-arrow-1-w:after,
+.ui-icon-arrow-l:after { content: '\e607'; }
+.ui-icon-arrow-2-e-w:after,
+.ui-icon-move-h:after,
+.ui-icon-resize-h:after { content: '\e617'; }
+.ui-icon-arrow-2-n-s:after,
+.ui-icon-move-v:after,
+.ui-icon-resize-v:after { content: '\e615'; }
+.ui-icon-arrow-2-ne-sw:after { content: '\e616'; }
+.ui-icon-arrow-2-se-nw:after { content: '\e618'; }
+.ui-icon-arrow-4:after,
+.ui-icon-move:after { content: '\e619'; }
+.ui-icon-arrow-4-diag:after { content: '\e61a'; }
+.ui-icon-arrowrefresh-1-e:after { content: '\e612'; }
+.ui-icon-arrowrefresh-1-n:after { content: '\e611'; }
+.ui-icon-arrowrefresh-1-s:after { content: '\e613'; }
+.ui-icon-arrowrefresh-1-w:after { content: '\e614'; }
+.ui-icon-arrowreturn-1-e:after,
+.ui-icon-forward:after { content: '\e60e'; }
+.ui-icon-arrowreturn-1-n:after { content: '\e60d'; }
+.ui-icon-arrowreturn-1-s:after,
+.ui-icon-back:after { content: '\e60f'; }
+.ui-icon-arrowreturn-1-w:after { content: '\e610'; }
+.ui-icon-arrowreturnthick-1-e:after { content: '\e628'; }
+.ui-icon-arrowreturnthick-1-n:after { content: '\e627'; }
+.ui-icon-arrowreturnthick-1-s:after { content: '\e629'; }
+.ui-icon-arrowreturnthick-1-w:after { content: '\e62a'; }
+.ui-icon-arrowstop-1-e:after { content: '\e60a'; }
+.ui-icon-arrowstop-1-n:after { content: '\e609'; }
+.ui-icon-arrowstop-1-s:after { content: '\e60b'; }
+.ui-icon-arrowstop-1-w:after { content: '\e60c'; }
+.ui-icon-arrowthick-1-e:after { content: '\e61d'; }
+.ui-icon-arrowthick-1-n:after { content: '\e61b'; }
+.ui-icon-arrowthick-1-ne:after { content: '\e61c'; }
+.ui-icon-arrowthick-1-nw:after { content: '\e622'; }
+.ui-icon-arrowthick-1-s:after { content: '\e61f'; }
+.ui-icon-arrowthick-1-se:after { content: '\e61e'; }
+.ui-icon-arrowthick-1-sw:after { content: '\e620'; }
+.ui-icon-arrowthick-1-w:after { content: '\e621'; }
+.ui-icon-arrowthick-2-e-w:after { content: '\e62d'; }
+.ui-icon-arrowthick-2-n-s:after { content: '\e62b'; }
+.ui-icon-arrowthick-2-ne-sw:after { content: '\e62c'; }
+.ui-icon-arrowthick-2-se-nw:after { content: '\e62e'; }
+.ui-icon-arrowthickstop-1-e:after { content: '\e624'; }
+.ui-icon-arrowthickstop-1-n:after { content: '\e623'; }
+.ui-icon-arrowthickstop-1-s:after { content: '\e625'; }
+.ui-icon-arrowthickstop-1-w:after { content: '\e626'; }
+.ui-icon-battery-0:after { content: '\e721'; }
+.ui-icon-battery-1:after { content: '\e722'; }
+.ui-icon-battery-2:after { content: '\e723'; }
+.ui-icon-battery-3:after { content: '\e724'; }
+.ui-icon-book:after { content: '\e6fb'; }
+.ui-icon-book-b:after { content: '\e6fc'; }
+.ui-icon-bookmark:after { content: '\e6c5'; }
+.ui-icon-bookmark-b:after { content: '\e6c6'; }
+.ui-icon-box:after { content: '\e6eb'; }
+.ui-icon-bucket:after { content: '\e728'; }
+.ui-icon-bug:after { content: '\e72e'; }
+.ui-icon-bullet:after,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon:after,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon:after { content: '\e65d'; }
+.ui-icon-bullhorn:after { content: '\e731'; }
+.ui-icon-calculator:after { content: '\e6fd'; }
+.ui-icon-calculator-b:after { content: '\e6fe'; }
+.ui-icon-calendar:after { content: '\e6ff'; }
+.ui-icon-calendar-b:after { content: '\e700'; }
+.ui-icon-calendar-day:after { content: '\e701'; }
+.ui-icon-camera:after { content: '\e6e8'; }
+.ui-icon-cancel:after,
+.ui-icon-forbidden:after { content: '\e675'; }
+.ui-icon-caret-1-e:after,
+.ui-icon-caret-r:after,
+.ui-icon-carat-r:after { content: '\e639'; }
+.ui-icon-caret-1-n:after,
+.ui-icon-caret-u:after,
+.ui-icon-carat-u:after { content: '\e637'; }
+.ui-icon-caret-1-ne:after { content: '\e638'; }
+.ui-icon-caret-1-nw:after { content: '\e63e'; }
+.ui-icon-caret-1-s:after,
+.ui-icon-caret-d:after,
+.ui-icon-carat-d:after { content: '\e63b'; }
+.ui-icon-caret-1-se:after { content: '\e63a'; }
+.ui-icon-caret-1-sw:after { content: '\e63c'; }
+.ui-icon-caret-1-w:after,
+.ui-icon-caret-l:after,
+.ui-icon-carat-l:after { content: '\e63d'; }
+.ui-icon-caret-2-e:after { content: '\e640'; }
+.ui-icon-caret-2-e-w:after { content: '\e643'; }
+.ui-icon-caret-2-n:after { content: '\e63f'; }
+.ui-icon-caret-2-n-s:after { content: '\e644'; }
+.ui-icon-caret-2-s:after { content: '\e641'; }
+.ui-icon-caret-2-w:after { content: '\e642'; }
+.ui-icon-caretstop-1-e:after,
+.ui-icon-caratstop-1-e:after { content: '\e905'; }
+.ui-icon-caretstop-1-n:after,
+.ui-icon-caratstop-1-n:after { content: '\e901'; }
+.ui-icon-caretstop-1-s:after,
+.ui-icon-caratstop-1-s:after { content: '\e900'; }
+.ui-icon-caretstop-1-w:after,
+.ui-icon-caratstop-1-w:after { content: '\e904'; }
+.ui-icon-cart:after,
+.ui-icon-shop:after { content: '\e6d6'; }
+.ui-icon-cart-b:after,
+.ui-icon-shop-b:after { content: '\e6d7'; }
+.ui-icon-chart-bars:after { content: '\e734'; }
+.ui-icon-chart-line:after { content: '\e735'; }
+.ui-icon-chart-pie:after { content: '\e733'; }
+.ui-icon-check:after,
+html .ui-btn.ui-checkbox-on.ui-checkbox-on:after,
+html .ui-alt-icon.ui-btn.ui-checkbox-on:after,
+html .ui-alt-icon .ui-btn.ui-checkbox-on:after { content: '\e670'; }
+.ui-icon-check-off:after,
+.ui-icon-checkbox:after,
+.ui-icon-checkbox-off:after,
+.ui-icon-checkbox-unchecked:after { content: '\e673'; }
+.ui-icon-check-on:after,
+.ui-icon-checkbox-on:after,
+.ui-icon-checkbox-checked:after { content: '\e674'; }
+.ui-icon-circle:after,
+.ui-icon-radio-off:after,
+.ui-icon-radio-btn:after,
+.ui-icon-radio-btn-off:after,
+.ui-icon-radio-btn-unchecked:after { content: '\e65e'; }
+.ui-icon-circle-arrow-e:after { content: '\e630'; }
+.ui-icon-circle-arrow-n:after { content: '\e62f'; }
+.ui-icon-circle-arrow-s:after { content: '\e631'; }
+.ui-icon-circle-arrow-w:after { content: '\e632'; }
+.ui-icon-circle-b-arrow-e:after { content: '\e634'; }
+.ui-icon-circle-b-arrow-n:after { content: '\e633'; }
+.ui-icon-circle-b-arrow-s:after { content: '\e635'; }
+.ui-icon-circle-b-arrow-w:after { content: '\e636'; }
+.ui-icon-circle-b-check:after { content: '\e672'; }
+.ui-icon-circle-b-close:after { content: '\e678'; }
+.ui-icon-circle-b-help:after { content: '\e663'; }
+.ui-icon-circle-b-info:after { content: '\e666'; }
+.ui-icon-circle-b-minus:after { content: '\e67e'; }
+.ui-icon-circle-b-notice:after { content: '\e669'; }
+.ui-icon-circle-b-plus:after { content: '\e684'; }
+.ui-icon-circle-b-triangle-e:after { content: '\e65a'; }
+.ui-icon-circle-b-triangle-n:after { content: '\e659'; }
+.ui-icon-circle-b-triangle-s:after { content: '\e65b'; }
+.ui-icon-circle-b-triangle-w:after { content: '\e65c'; }
+.ui-icon-circle-check:after { content: '\e671'; }
+.ui-icon-circle-close:after { content: '\e677'; }
+.ui-icon-circle-help:after,
+.ui-icon-help:after { content: '\e662'; }
+.ui-icon-circle-info:after,
+.ui-icon-info:after { content: '\e665'; }
+.ui-icon-circle-minus:after { content: '\e67d'; }
+.ui-icon-circle-notice:after,
+.ui-icon-notice:after { content: '\e668'; }
+.ui-icon-circle-phone:after { content: '\e705'; }
+.ui-icon-circle-plus:after { content: '\e683'; }
+.ui-icon-circle-triangle-e:after { content: '\e656'; }
+.ui-icon-circle-triangle-n:after { content: '\e655'; }
+.ui-icon-circle-triangle-s:after { content: '\e657'; }
+.ui-icon-circle-triangle-w:after { content: '\e658'; }
+.ui-icon-circle-zoom:after { content: '\e712'; }
+.ui-icon-circle-zoomin:after { content: '\e714'; }
+.ui-icon-circle-zoomout:after { content: '\e716'; }
+.ui-icon-circlesmall-close:after { content: '\e67b'; }
+.ui-icon-circlesmall-minus:after { content: '\e681'; }
+.ui-icon-circlesmall-plus:after { content: '\e687'; }
+.ui-icon-client:after { content: '\e72f'; }
+.ui-icon-clipboard:after,
+.ui-icon-paste:after { content: '\e68b'; }
+.ui-icon-clock:after { content: '\e6d9'; }
+.ui-icon-clock-b:after { content: '\e6da'; }
+.ui-icon-close:after,
+.ui-icon-delete:after { content: '\e676'; }
+.ui-icon-closethick:after { content: '\e679'; }
+.ui-icon-cloud:after { content: '\e6dc'; }
+.ui-icon-cloud-b:after { content: '\e6dd'; }
+.ui-icon-cloud-download:after { content: '\e6de'; }
+.ui-icon-cloud-upload:after { content: '\e6df'; }
+.ui-icon-comment:after { content: '\e6e0'; }
+.ui-icon-comments:after { content: '\e6e1'; }
+.ui-icon-console:after { content: '\e6c0'; }
+.ui-icon-contact:after,
+.ui-icon-vcard:after { content: '\e703'; }
+.ui-icon-copy:after,
+.ui-icon-files:after { content: '\e689'; }
+.ui-icon-creditcard:after { content: '\e6d8'; }
+.ui-icon-database:after { content: '\e6f9'; }
+.ui-icon-databases:after { content: '\e6fa'; }
+.ui-icon-disk:after,
+.ui-icon-save:after { content: '\e68c'; }
+.ui-icon-document:after,
+.ui-icon-file:after { content: '\e69c'; }
+.ui-icon-document-b:after { content: '\e69d'; }
+.ui-icon-download:after { content: '\e6aa'; }
+.ui-icon-eject:after { content: '\e6b6'; }
+.ui-icon-erase:after { content: '\e72b'; }
+.ui-icon-extlink:after,
+.ui-icon-linkext:after,
+.ui-icon-action:after { content: '\e6b8'; }
+.ui-icon-eye:after { content: '\e6ea'; }
+.ui-icon-file-audio:after,
+.ui-icon-audio:after { content: '\e69e'; }
+.ui-icon-file-pdf:after { content: '\e6a3'; }
+.ui-icon-file-report:after { content: '\e6a6'; }
+.ui-icon-file-richtext:after { content: '\e6a4'; }
+.ui-icon-file-table:after { content: '\e6a5'; }
+.ui-icon-file-text:after { content: '\e6a7'; }
+.ui-icon-file-word:after { content: '\e6a8'; }
+.ui-icon-file-zip:after { content: '\e6a9'; }
+.ui-icon-flag:after { content: '\e6e9'; }
+.ui-icon-folder-collapsed:after,
+.ui-icon-folder:after,
+.ui-icon-folder-closed:after { content: '\e69a'; }
+.ui-icon-folder-open:after { content: '\e69b'; }
+.ui-icon-fullscreen:after,
+.ui-icon-fullscreen-on:after { content: '\e902'; }
+.ui-icon-fullscreen-off:after { content: '\e903'; }
+.ui-icon-gear:after { content: '\e6e6'; }
+.ui-icon-gears:after { content: '\e6e7'; }
+.ui-icon-globe:after { content: '\e6e2'; }
+.ui-icon-globe-b:after { content: '\e6e3'; }
+.ui-icon-grip-diagonal-se:after { content: '\e66a'; }
+.ui-icon-grip-dotted-horizontal:after { content: '\e66e'; }
+.ui-icon-grip-dotted-vertical:after { content: '\e66f'; }
+.ui-icon-grip-solid-horizontal:after { content: '\e66c'; }
+.ui-icon-grip-solid-vertical:after { content: '\e66d'; }
+.ui-icon-gripsmall-diagonal-se:after { content: '\e66b'; }
+.ui-icon-heart:after { content: '\e6d1'; }
+.ui-icon-heart-b:after { content: '\e6d2'; }
+.ui-icon-heart-beat:after { content: '\e6d3'; }
+.ui-icon-help-plain:after { content: '\e661'; }
+.ui-icon-history:after { content: '\e6db'; }
+.ui-icon-home:after { content: '\e6c4'; }
+.ui-icon-image:after,
+.ui-icon-file-image:after { content: '\e6a1'; }
+.ui-icon-info-plain:after { content: '\e664'; }
+.ui-icon-jquery:after { content: '\e746'; }
+.ui-icon-key:after { content: '\e6d4'; }
+.ui-icon-lightbulb:after { content: '\e6d5'; }
+.ui-icon-link:after { content: '\e6b7'; }
+.ui-icon-link-broken:after { content: '\e6b9'; }
+.ui-icon-loading-status-balls:after { content: '\e741'; }
+.ui-icon-loading-status-circle:after { content: '\e742'; }
+.ui-icon-loading-status-comet:after { content: '\e743'; }
+.ui-icon-loading-status-lines:after { content: '\e744'; }
+.ui-icon-loading-status-planet:after { content: '\e745'; }
+.ui-icon-location:after { content: '\e6e4'; }
+.ui-icon-locked:after,
+.ui-icon-lock:after { content: '\e6bb'; }
+.ui-icon-mail-attachment:after { content: '\e70b'; }
+.ui-icon-mail-closed:after,
+.ui-icon-mail:after,
+.ui-icon-email:after { content: '\e706'; }
+.ui-icon-mail-forward:after { content: '\e708'; }
+.ui-icon-mail-open:after,
+.ui-icon-mail-read:after { content: '\e707'; }
+.ui-icon-mail-reply:after { content: '\e709'; }
+.ui-icon-mail-replyall:after { content: '\e70a'; }
+.ui-icon-mail-send:after { content: '\e70c'; }
+.ui-icon-marker:after { content: '\e72c'; }
+.ui-icon-menu:after,
+.ui-icon-bars:after { content: '\e6c3'; }
+.ui-icon-microphone:after { content: '\e6b2'; }
+.ui-icon-microphone-off:after { content: '\e6b3'; }
+.ui-icon-minus:after { content: '\e67c'; }
+.ui-icon-minusthick:after { content: '\e67f'; }
+.ui-icon-movie:after,
+.ui-icon-file-movie:after { content: '\e69f'; }
+.ui-icon-navigation:after { content: '\e6e5'; }
+.ui-icon-newspaper:after,
+.ui-icon-newsletter:after,
+.ui-icon-news:after { content: '\e70e'; }
+.ui-icon-newwin:after,
+.ui-icon-popup:after,
+.ui-icon-windows:after { content: '\e6be'; }
+.ui-icon-note:after { content: '\e695'; }
+.ui-icon-notice-plain:after { content: '\e667'; }
+.ui-icon-package:after { content: '\e6cc'; }
+.ui-icon-palette:after { content: '\e729'; }
+.ui-icon-pause:after { content: '\e6ad'; }
+.ui-icon-pencil:after,
+.ui-icon-edit:after { content: '\e688'; }
+.ui-icon-person:after,
+.ui-icon-user:after { content: '\e6d0'; }
+.ui-icon-persons:after,
+.ui-icon-users:after,
+.ui-icon-group:after { content: '\e6cf'; }
+.ui-icon-phone:after { content: '\e704'; }
+.ui-icon-pilcrow:after { content: '\e727'; }
+.ui-icon-pin-s:after { content: '\e70f'; }
+.ui-icon-pin-w:after { content: '\e710'; }
+.ui-icon-play:after { content: '\e6ac'; }
+.ui-icon-plugin:after { content: '\e6cb'; }
+.ui-icon-plus:after { content: '\e682'; }
+.ui-icon-plusthick:after { content: '\e685'; }
+.ui-icon-power:after,
+.ui-icon-switch:after { content: '\e6cd'; }
+.ui-icon-print:after { content: '\e692'; }
+.ui-icon-print-b:after { content: '\e693'; }
+.ui-icon-print-layout:after { content: '\e694'; }
+.ui-icon-prush:after { content: '\e72a'; }
+.ui-icon-radio-on:after,
+.ui-icon-radio-btn-on:after,
+.ui-icon-radio-btn-checked:after { content: '\e6f5'; }
+.ui-icon-redo:after { content: '\e68e'; }
+.ui-icon-refresh:after,
+.ui-icon-reload:after { content: '\e6ce'; }
+.ui-icon-rename:after,
+.ui-icon-input:after { content: '\e68f'; }
+.ui-icon-retweet:after { content: '\e6b5'; }
+.ui-icon-scissors:after,
+.ui-icon-cut:after { content: '\e68a'; }
+.ui-icon-screen-desktop:after,
+.ui-icon-desktop:after { content: '\e718'; }
+.ui-icon-screen-laptop:after,
+.ui-icon-laptop:after { content: '\e719'; }
+.ui-icon-screen-mobile:after,
+.ui-icon-mobile:after { content: '\e71a'; }
+.ui-icon-script:after,
+.ui-icon-file-script:after { content: '\e6a2'; }
+.ui-icon-search:after,
+.ui-input-search:after { content: '\e6f2'; }
+.ui-icon-select:after { content: '\e72d'; }
+.ui-icon-selectbox:after { content: '\e6f6'; }
+.ui-icon-server:after { content: '\e730'; }
+.ui-icon-settings:after { content: '\e6f4'; }
+.ui-icon-shield:after { content: '\e732'; }
+.ui-icon-shuffle:after { content: '\e6b4'; }
+.ui-icon-shuttle:after { content: '\e73f'; }
+.ui-icon-sign-in:after,
+.ui-icon-login:after { content: '\e6ee'; }
+.ui-icon-sign-out:after,
+.ui-icon-logout:after,
+.ui-icon-logoff:after { content: '\e6ef'; }
+.ui-icon-signal:after { content: '\e725'; }
+.ui-icon-signal-diag:after,
+.ui-icon-rss:after,
+.ui-icon-feed:after { content: '\e726'; }
+.ui-icon-sitemap:after { content: '\e736'; }
+.ui-icon-sorting:after { content: '\e71e'; }
+.ui-icon-sorting-asc:after { content: '\e71f'; }
+.ui-icon-sorting-desc:after { content: '\e720'; }
+.ui-icon-squaresmall-close:after { content: '\e67a'; }
+.ui-icon-squaresmall-minus:after { content: '\e680'; }
+.ui-icon-squaresmall-plus:after { content: '\e686'; }
+.ui-icon-star:after { content: '\e6c7'; }
+.ui-icon-star-b:after { content: '\e6c9'; }
+.ui-icon-star-h:after { content: '\e6c8'; }
+.ui-icon-stop:after { content: '\e6ae'; }
+.ui-icon-structure:after { content: '\e737'; }
+.ui-icon-suitcase:after { content: '\e6f7'; }
+.ui-icon-table:after { content: '\e696'; }
+.ui-icon-tag:after { content: '\e697'; }
+.ui-icon-tags:after { content: '\e698'; }
+.ui-icon-template:after { content: '\e738'; }
+.ui-icon-ticket:after { content: '\e699'; }
+.ui-icon-toggle-off:after { content: '\e6f0'; }
+.ui-icon-toggle-on:after { content: '\e6f1'; }
+.ui-icon-transfer-e-w:after { content: '\e6ec'; }
+.ui-icon-transferthick-e-w:after { content: '\e6ed'; }
+.ui-icon-transform:after { content: '\e739'; }
+.ui-icon-translate:after { content: '\e740'; }
+.ui-icon-trash:after,
+.ui-icon-recycle:after { content: '\e690'; }
+.ui-icon-trash-b:after { content: '\e691'; }
+.ui-icon-triangle-1-e:after { content: '\e647'; }
+.ui-icon-triangle-1-e-stop:after,
+.ui-icon-seek-end:after { content: '\e64e'; }
+.ui-icon-triangle-1-n:after { content: '\e645'; }
+.ui-icon-triangle-1-n-stop:after { content: '\e64d'; }
+.ui-icon-triangle-1-ne:after { content: '\e646'; }
+.ui-icon-triangle-1-nw:after { content: '\e64c'; }
+.ui-icon-triangle-1-s:after { content: '\e64b'; }
+.ui-icon-triangle-1-s-stop:after { content: '\e64f'; }
+.ui-icon-triangle-1-se:after { content: '\e64a'; }
+.ui-icon-triangle-1-sw:after { content: '\e648'; }
+.ui-icon-triangle-1-w:after { content: '\e649'; }
+.ui-icon-triangle-1-w-stop:after,
+.ui-icon-seek-first:after { content: '\e650'; }
+.ui-icon-triangle-2-e:after,
+.ui-icon-seek-next:after { content: '\e651'; }
+.ui-icon-triangle-2-e-w:after { content: '\e654'; }
+.ui-icon-triangle-2-n-s:after { content: '\e653'; }
+.ui-icon-triangle-2-w:after,
+.ui-icon-seek-prev:after { content: '\e652'; }
+.ui-icon-truck:after { content: '\e6f8'; }
+.ui-icon-undo:after { content: '\e68d'; }
+.ui-icon-unlocked:after,
+.ui-icon-lock-open:after { content: '\e6bc'; }
+.ui-icon-upload:after { content: '\e6ab'; }
+.ui-icon-vcs-branch:after { content: '\e73d'; }
+.ui-icon-vcs-compare:after { content: '\e73b'; }
+.ui-icon-vcs-fork:after { content: '\e73a'; }
+.ui-icon-vcs-merge:after { content: '\e73e'; }
+.ui-icon-vcs-pull-request:after { content: '\e73c'; }
+.ui-icon-video:after,
+.ui-icon-file-video:after { content: '\e6a0'; }
+.ui-icon-view-icons:after,
+.ui-icon-grid-b:after { content: '\e71b'; }
+.ui-icon-view-icons-b:after,
+.ui-icon-grid:after { content: '\e71c'; }
+.ui-icon-view-list:after,
+.ui-icon-list:after,
+.ui-icon-bullets:after { content: '\e71d'; }
+.ui-icon-volume-off:after,
+.ui-icon-volume-mute:after { content: '\e6af'; }
+.ui-icon-volume-on:after,
+.ui-icon-volume-high:after { content: '\e6b0'; }
+.ui-icon-volume-on-b:after,
+.ui-icon-volume-low:after { content: '\e6b1'; }
+.ui-icon-window:after { content: '\e6bd'; }
+.ui-icon-window-close:after { content: '\e6c1'; }
+.ui-icon-window-minimize:after { content: '\e6c2'; }
+.ui-icon-window-sidebar:after { content: '\e6bf'; }
+.ui-icon-wrench:after { content: '\e6f3'; }
+.ui-icon-zoom:after { content: '\e711'; }
+.ui-icon-zoomequal:after { content: '\e717'; }
+.ui-icon-zoomin:after { content: '\e713'; }
+.ui-icon-zoomout:after { content: '\e715'; }
+
+.ui-icon-carat-1-e:after { content: '\e639'; } /* deprecated: use '.ui-icon-caret-1-e' instead */
+.ui-icon-carat-1-n:after { content: '\e637'; } /* deprecated: use '.ui-icon-caret-1-n' instead */
+.ui-icon-carat-1-s:after { content: '\e63b'; } /* deprecated: use '.ui-icon-caret-1-s' instead */
+.ui-icon-carat-1-w:after { content: '\e63d'; } /* deprecated: use '.ui-icon-caret-1-w' instead */
+.ui-icon-carat-2-e:after { content: '\e640'; } /* deprecated: use '.ui-icon-caret-2-e' instead */
+.ui-icon-carat-2-e-w:after { content: '\e643'; } /* deprecated: use '.ui-icon-caret-2-e-w' instead */
+.ui-icon-carat-2-n:after { content: '\e63f'; } /* deprecated: use '.ui-icon-caret-2-n' instead */
+.ui-icon-carat-2-n-s:after { content: '\e644'; } /* deprecated: use '.ui-icon-caret-2-n-s' instead */
+.ui-icon-carat-2-s:after { content: '\e641'; } /* deprecated: use '.ui-icon-caret-2-s' instead */
+.ui-icon-carat-2-w:after { content: '\e642'; } /* deprecated: use '.ui-icon-caret-2-w' instead */
+.ui-icon-caratstop-1-e:after { content: '\e905'; } /* deprecated: use '.ui-icon-caretstop-1-e' instead */
+.ui-icon-caratstop-1-n:after { content: '\e901'; } /* deprecated: use '.ui-icon-caretstop-1-n' instead */
+.ui-icon-caratstop-1-s:after { content: '\e900'; } /* deprecated: use '.ui-icon-caretstop-1-s' instead */
+.ui-icon-caratstop-1-w:after { content: '\e904'; } /* deprecated: use '.ui-icon-caretstop-1-w' instead */
+
+/* bounce animations */
+@keyframes bounce {
+ 0%, 100% { -webkit-transform: scale(0.2); -moz-transform: scale(0.2); -ms-transform: scale(0.2); transform: scale(0.2); }
+ 50% { -webkit-transform: scale(1.0); -moz-transform: scale(1.0); -ms-transform: scale(1.0); transform: scale(1.0); }
+}
+@-moz-keyframes bounce { 0%, 100% { -moz-transform: scale(0.2); transform: scale(0.2); } 50% { -moz-transform: scale(1.0); transform: scale(1.0); } }
+@-ms-keyframes bounce { 0%, 100% { -ms-transform: scale(0.2); transform: scale(0.2); } 50% { -ms-transform: scale(1.0); transform: scale(1.0); } }
+@-webkit-keyframes bounce { 0%, 100% { -webkit-transform: scale(0.2); transform: scale(0.2); } 50% { -webkit-transform: scale(1.0); transform: scale(1.0); } }
+
+[class^='ui-icon-'].bounce:after,
+[class*=' ui-icon-'].bounce:after {
+ animation: bounce 1s infinite ease-in-out;
+ -moz-animation: bounce 1s infinite ease-in-out;
+ -ms-animation: bounce 1s infinite ease-in-out;
+ -webkit-animation: bounce 1s infinite ease-in-out;
+}
+
+
+/* rotated animations */
+@keyframes rotate {
+ from { -webkit-transform: rotate(0deg); -moz-transform: rotate(0deg); -ms-transform: rotate(0deg); transform: rotate(0deg); }
+ to { -webkit-transform: rotate(359deg); -moz-transform: rotate(359deg); -ms-transform: rotate(359deg); transform: rotate(359deg); }
+}
+@-moz-keyframes rotate { from { -moz-transform: rotate(0deg); transform: rotate(0deg); } to { -moz-transform: rotate(359deg); transform: rotate(359deg); } }
+@-ms-keyframes rotate { from { -ms-transform: rotate(0deg); transform: rotate(0deg); } to { -ms-transform: rotate(359deg); transform: rotate(359deg); } }
+@-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg); transform: rotate(0deg); } to { -webkit-transform: rotate(359deg); transform: rotate(359deg); } }
+
+[class^='ui-icon-'].rotate, /* clockwise */
+[class*=' ui-icon-'].rotate, /* clockwise */
+[class^='ui-icon-'].rotate-reverse, /* anti clockwise */
+[class*=' ui-icon-'].rotate-reverse /* anti clockwise */ {
+ animation: rotate 1s infinite linear;
+ -moz-animation: rotate 1s infinite linear;
+ -ms-animation: rotate 1s infinite linear;
+ -webkit-animation: rotate 1s infinite linear;
+}
+[class^='ui-icon-'].rotate-reverse, /* anti clockwise */
+[class*=' ui-icon-'].rotate-reverse /* anti clockwise */ {
+ animation-direction: reverse;
+ -moz-animation-direction: reverse;
+ -ms-animation-direction: reverse;
+ -webkit-animation-direction: reverse;
+}
diff --git a/src/lib/vendor/jquery.smooth-scroll.js b/src/lib/vendor/jquery.smooth-scroll.js
new file mode 100644
index 0000000..e2d4fd6
--- /dev/null
+++ b/src/lib/vendor/jquery.smooth-scroll.js
@@ -0,0 +1,357 @@
+/*!
+ * jQuery Smooth Scroll - v2.2.0 - 2017-05-05
+ * https://github.com/kswedberg/jquery-smooth-scroll
+ * Copyright (c) 2017 Karl Swedberg
+ * Licensed MIT
+ */
+
+(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // CommonJS
+ factory(require('jquery'));
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function($) {
+
+ var version = '2.2.0';
+ var optionOverrides = {};
+ var defaults = {
+ exclude: [],
+ excludeWithin: [],
+ offset: 0,
+
+ // one of 'top' or 'left'
+ direction: 'top',
+
+ // if set, bind click events through delegation
+ // supported since jQuery 1.4.2
+ delegateSelector: null,
+
+ // jQuery set of elements you wish to scroll (for $.smoothScroll).
+ // if null (default), $('html, body').firstScrollable() is used.
+ scrollElement: null,
+
+ // only use if you want to override default behavior
+ scrollTarget: null,
+
+ // automatically focus the target element after scrolling to it
+ autoFocus: false,
+
+ // fn(opts) function to be called before scrolling occurs.
+ // `this` is the element(s) being scrolled
+ beforeScroll: function() {},
+
+ // fn(opts) function to be called after scrolling occurs.
+ // `this` is the triggering element
+ afterScroll: function() {},
+
+ // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
+ // from jQuery UI or elsewhere
+ easing: 'swing',
+
+ // speed can be a number or 'auto'
+ // if 'auto', the speed will be calculated based on the formula:
+ // (current scroll position - target scroll position) / autoCoeffic
+ speed: 400,
+
+ // coefficient for "auto" speed
+ autoCoefficient: 2,
+
+ // $.fn.smoothScroll only: whether to prevent the default click action
+ preventDefault: true
+ };
+
+ var getScrollable = function(opts) {
+ var scrollable = [];
+ var scrolled = false;
+ var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
+
+ this.each(function() {
+ var el = $(this);
+
+ if (this === document || this === window) {
+ return;
+ }
+
+ if (document.scrollingElement && (this === document.documentElement || this === document.body)) {
+ scrollable.push(document.scrollingElement);
+
+ return false;
+ }
+
+ if (el[dir]() > 0) {
+ scrollable.push(this);
+ } else {
+ // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
+ el[dir](1);
+ scrolled = el[dir]() > 0;
+
+ if (scrolled) {
+ scrollable.push(this);
+ }
+ // then put it back, of course
+ el[dir](0);
+ }
+ });
+
+ if (!scrollable.length) {
+ this.each(function() {
+ // If no scrollable elements and <html> has scroll-behavior:smooth because
+ // "When this property is specified on the root element, it applies to the viewport instead."
+ // and "The scroll-behavior property of the … body element is *not* propagated to the viewport."
+ // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior
+ if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') {
+ scrollable = [this];
+ }
+
+ // If still no scrollable elements, fall back to <body>,
+ // if it's in the jQuery collection
+ // (doing this because Safari sets scrollTop async,
+ // so can't set it to 1 and immediately get the value.)
+ if (!scrollable.length && this.nodeName === 'BODY') {
+ scrollable = [this];
+ }
+ });
+ }
+
+ // Use the first scrollable element if we're calling firstScrollable()
+ if (opts.el === 'first' && scrollable.length > 1) {
+ scrollable = [scrollable[0]];
+ }
+
+ return scrollable;
+ };
+
+ var rRelative = /^([\-\+]=)(\d+)/;
+
+ $.fn.extend({
+ scrollable: function(dir) {
+ var scrl = getScrollable.call(this, {dir: dir});
+
+ return this.pushStack(scrl);
+ },
+ firstScrollable: function(dir) {
+ var scrl = getScrollable.call(this, {el: 'first', dir: dir});
+
+ return this.pushStack(scrl);
+ },
+
+ smoothScroll: function(options, extra) {
+ options = options || {};
+
+ if (options === 'options') {
+ if (!extra) {
+ return this.first().data('ssOpts');
+ }
+
+ return this.each(function() {
+ var $this = $(this);
+ var opts = $.extend($this.data('ssOpts') || {}, extra);
+
+ $(this).data('ssOpts', opts);
+ });
+ }
+
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
+
+ var clickHandler = function(event) {
+ var escapeSelector = function(str) {
+ return str.replace(/(:|\.|\/)/g, '\\$1');
+ };
+
+ var link = this;
+ var $link = $(this);
+ var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {});
+ var exclude = opts.exclude;
+ var excludeWithin = thisOpts.excludeWithin;
+ var elCounter = 0;
+ var ewlCounter = 0;
+ var include = true;
+ var clickOpts = {};
+ var locationPath = $.smoothScroll.filterPath(location.pathname);
+ var linkPath = $.smoothScroll.filterPath(link.pathname);
+ var hostMatch = location.hostname === link.hostname || !link.hostname;
+ var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath);
+ var thisHash = escapeSelector(link.hash);
+
+ if (thisHash && !$(thisHash).length) {
+ include = false;
+ }
+
+ if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) {
+ include = false;
+ } else {
+ while (include && elCounter < exclude.length) {
+ if ($link.is(escapeSelector(exclude[elCounter++]))) {
+ include = false;
+ }
+ }
+
+ while (include && ewlCounter < excludeWithin.length) {
+ if ($link.closest(excludeWithin[ewlCounter++]).length) {
+ include = false;
+ }
+ }
+ }
+
+ if (include) {
+ if (thisOpts.preventDefault) {
+ event.preventDefault();
+ }
+
+ $.extend(clickOpts, thisOpts, {
+ scrollTarget: thisOpts.scrollTarget || thisHash,
+ link: link
+ });
+
+ $.smoothScroll(clickOpts);
+ }
+ };
+
+ if (options.delegateSelector !== null) {
+ this
+ .off('click.smoothscroll', options.delegateSelector)
+ .on('click.smoothscroll', options.delegateSelector, clickHandler);
+ } else {
+ this
+ .off('click.smoothscroll')
+ .on('click.smoothscroll', clickHandler);
+ }
+
+ return this;
+ }
+ });
+
+ var getExplicitOffset = function(val) {
+ var explicit = {relative: ''};
+ var parts = typeof val === 'string' && rRelative.exec(val);
+
+ if (typeof val === 'number') {
+ explicit.px = val;
+ } else if (parts) {
+ explicit.relative = parts[1];
+ explicit.px = parseFloat(parts[2]) || 0;
+ }
+
+ return explicit;
+ };
+
+ var onAfterScroll = function(opts) {
+ var $tgt = $(opts.scrollTarget);
+
+ if (opts.autoFocus && $tgt.length) {
+ $tgt[0].focus();
+
+ if (!$tgt.is(document.activeElement)) {
+ $tgt.prop({tabIndex: -1});
+ $tgt[0].focus();
+ }
+ }
+
+ opts.afterScroll.call(opts.link, opts);
+ };
+
+ $.smoothScroll = function(options, px) {
+ if (options === 'options' && typeof px === 'object') {
+ return $.extend(optionOverrides, px);
+ }
+ var opts, $scroller, speed, delta;
+ var explicitOffset = getExplicitOffset(options);
+ var scrollTargetOffset = {};
+ var scrollerOffset = 0;
+ var offPos = 'offset';
+ var scrollDir = 'scrollTop';
+ var aniProps = {};
+ var aniOpts = {};
+
+ if (explicitOffset.px) {
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
+ } else {
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
+
+ if (opts.scrollElement) {
+ offPos = 'position';
+
+ if (opts.scrollElement.css('position') === 'static') {
+ opts.scrollElement.css('position', 'relative');
+ }
+ }
+
+ if (px) {
+ explicitOffset = getExplicitOffset(px);
+ }
+ }
+
+ scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
+
+ if (opts.scrollElement) {
+ $scroller = opts.scrollElement;
+
+ if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) {
+ scrollerOffset = $scroller[scrollDir]();
+ }
+ } else {
+ $scroller = $('html, body').firstScrollable(opts.direction);
+ }
+
+ // beforeScroll callback function must fire before calculating offset
+ opts.beforeScroll.call($scroller, opts);
+
+ scrollTargetOffset = explicitOffset.px ? explicitOffset : {
+ relative: '',
+ px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0
+ };
+
+ aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset);
+
+ speed = opts.speed;
+
+ // automatically calculate the speed of the scroll based on distance / coefficient
+ if (speed === 'auto') {
+
+ // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after
+ // When delta is greater, speed will be greater.
+ delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]());
+
+ // Divide the delta by the coefficient
+ speed = delta / opts.autoCoefficient;
+ }
+
+ aniOpts = {
+ duration: speed,
+ easing: opts.easing,
+ complete: function() {
+ onAfterScroll(opts);
+ }
+ };
+
+ if (opts.step) {
+ aniOpts.step = opts.step;
+ }
+
+ if ($scroller.length) {
+ $scroller.stop().animate(aniProps, aniOpts);
+ } else {
+ onAfterScroll(opts);
+ }
+ };
+
+ $.smoothScroll.version = version;
+ $.smoothScroll.filterPath = function(string) {
+ string = string || '';
+
+ return string
+ .replace(/^\//, '')
+ .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '')
+ .replace(/\/$/, '');
+ };
+
+ // default options
+ $.fn.smoothScroll.defaults = defaults;
+
+}));
diff --git a/src/lib/vendor/punycode-1.4.1.js b/src/lib/vendor/punycode-1.4.1.js
new file mode 100644
index 0000000..2c87f6c
--- /dev/null
+++ b/src/lib/vendor/punycode-1.4.1.js
@@ -0,0 +1,533 @@
+/*! https://mths.be/punycode v1.4.1 by @mathias */
+;(function(root) {
+
+ /** Detect free variables */
+ var freeExports = typeof exports == 'object' && exports &&
+ !exports.nodeType && exports;
+ var freeModule = typeof module == 'object' && module &&
+ !module.nodeType && module;
+ var freeGlobal = typeof global == 'object' && global;
+ if (
+ freeGlobal.global === freeGlobal ||
+ freeGlobal.window === freeGlobal ||
+ freeGlobal.self === freeGlobal
+ ) {
+ root = freeGlobal;
+ }
+
+ /**
+ * The `punycode` object.
+ * @name punycode
+ * @type Object
+ */
+ var punycode,
+
+ /** Highest positive signed 32-bit float value */
+ maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+ /** Bootstring parameters */
+ base = 36,
+ tMin = 1,
+ tMax = 26,
+ skew = 38,
+ damp = 700,
+ initialBias = 72,
+ initialN = 128, // 0x80
+ delimiter = '-', // '\x2D'
+
+ /** Regular expressions */
+ regexPunycode = /^xn--/,
+ regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+ regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+ /** Error messages */
+ errors = {
+ 'overflow': 'Overflow: input needs wider integers to process',
+ 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+ 'invalid-input': 'Invalid input'
+ },
+
+ /** Convenience shortcuts */
+ baseMinusTMin = base - tMin,
+ floor = Math.floor,
+ stringFromCharCode = String.fromCharCode,
+
+ /** Temporary variable */
+ key;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * A generic error utility function.
+ * @private
+ * @param {String} type The error type.
+ * @returns {Error} Throws a `RangeError` with the applicable error message.
+ */
+ function error(type) {
+ throw new RangeError(errors[type]);
+ }
+
+ /**
+ * A generic `Array#map` utility function.
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} callback The function that gets called for every array
+ * item.
+ * @returns {Array} A new array of values returned by the callback function.
+ */
+ function map(array, fn) {
+ var length = array.length;
+ var result = [];
+ while (length--) {
+ result[length] = fn(array[length]);
+ }
+ return result;
+ }
+
+ /**
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
+ * addresses.
+ * @private
+ * @param {String} domain The domain name or email address.
+ * @param {Function} callback The function that gets called for every
+ * character.
+ * @returns {Array} A new string of characters returned by the callback
+ * function.
+ */
+ function mapDomain(string, fn) {
+ var parts = string.split('@');
+ var result = '';
+ if (parts.length > 1) {
+ // In email addresses, only the domain name should be punycoded. Leave
+ // the local part (i.e. everything up to `@`) intact.
+ result = parts[0] + '@';
+ string = parts[1];
+ }
+ // Avoid `split(regex)` for IE8 compatibility. See #17.
+ string = string.replace(regexSeparators, '\x2E');
+ var labels = string.split('.');
+ var encoded = map(labels, fn).join('.');
+ return result + encoded;
+ }
+
+ /**
+ * Creates an array containing the numeric code points of each Unicode
+ * character in the string. While JavaScript uses UCS-2 internally,
+ * this function will convert a pair of surrogate halves (each of which
+ * UCS-2 exposes as separate characters) into a single code point,
+ * matching UTF-16.
+ * @see `punycode.ucs2.encode`
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode.ucs2
+ * @name decode
+ * @param {String} string The Unicode input string (UCS-2).
+ * @returns {Array} The new array of code points.
+ */
+ function ucs2decode(string) {
+ var output = [],
+ counter = 0,
+ length = string.length,
+ value,
+ extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Creates a string based on an array of numeric code points.
+ * @see `punycode.ucs2.decode`
+ * @memberOf punycode.ucs2
+ * @name encode
+ * @param {Array} codePoints The array of numeric code points.
+ * @returns {String} The new Unicode string (UCS-2).
+ */
+ function ucs2encode(array) {
+ return map(array, function(value) {
+ var output = '';
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ return output;
+ }).join('');
+ }
+
+ /**
+ * Converts a basic code point into a digit/integer.
+ * @see `digitToBasic()`
+ * @private
+ * @param {Number} codePoint The basic numeric code point value.
+ * @returns {Number} The numeric value of a basic code point (for use in
+ * representing integers) in the range `0` to `base - 1`, or `base` if
+ * the code point does not represent a value.
+ */
+ function basicToDigit(codePoint) {
+ if (codePoint - 48 < 10) {
+ return codePoint - 22;
+ }
+ if (codePoint - 65 < 26) {
+ return codePoint - 65;
+ }
+ if (codePoint - 97 < 26) {
+ return codePoint - 97;
+ }
+ return base;
+ }
+
+ /**
+ * Converts a digit/integer into a basic code point.
+ * @see `basicToDigit()`
+ * @private
+ * @param {Number} digit The numeric value of a basic code point.
+ * @returns {Number} The basic code point whose value (when used for
+ * representing integers) is `digit`, which needs to be in the range
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+ * used; else, the lowercase form is used. The behavior is undefined
+ * if `flag` is non-zero and `digit` has no uppercase form.
+ */
+ function digitToBasic(digit, flag) {
+ // 0..25 map to ASCII a..z or A..Z
+ // 26..35 map to ASCII 0..9
+ return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+ }
+
+ /**
+ * Bias adaptation function as per section 3.4 of RFC 3492.
+ * https://tools.ietf.org/html/rfc3492#section-3.4
+ * @private
+ */
+ function adapt(delta, numPoints, firstTime) {
+ var k = 0;
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
+ delta += floor(delta / numPoints);
+ for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+ delta = floor(delta / baseMinusTMin);
+ }
+ return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+ }
+
+ /**
+ * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+ * symbols.
+ * @memberOf punycode
+ * @param {String} input The Punycode string of ASCII-only symbols.
+ * @returns {String} The resulting string of Unicode symbols.
+ */
+ function decode(input) {
+ // Don't use UCS-2
+ var output = [],
+ inputLength = input.length,
+ out,
+ i = 0,
+ n = initialN,
+ bias = initialBias,
+ basic,
+ j,
+ index,
+ oldi,
+ w,
+ k,
+ digit,
+ t,
+ /** Cached calculation results */
+ baseMinusT;
+
+ // Handle the basic code points: let `basic` be the number of input code
+ // points before the last delimiter, or `0` if there is none, then copy
+ // the first basic code points to the output.
+
+ basic = input.lastIndexOf(delimiter);
+ if (basic < 0) {
+ basic = 0;
+ }
+
+ for (j = 0; j < basic; ++j) {
+ // if it's not a basic code point
+ if (input.charCodeAt(j) >= 0x80) {
+ error('not-basic');
+ }
+ output.push(input.charCodeAt(j));
+ }
+
+ // Main decoding loop: start just after the last delimiter if any basic code
+ // points were copied; start at the beginning otherwise.
+
+ for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+ // `index` is the index of the next character to be consumed.
+ // Decode a generalized variable-length integer into `delta`,
+ // which gets added to `i`. The overflow checking is easier
+ // if we increase `i` as we go, then subtract off its starting
+ // value at the end to obtain `delta`.
+ for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+ if (index >= inputLength) {
+ error('invalid-input');
+ }
+
+ digit = basicToDigit(input.charCodeAt(index++));
+
+ if (digit >= base || digit > floor((maxInt - i) / w)) {
+ error('overflow');
+ }
+
+ i += digit * w;
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (digit < t) {
+ break;
+ }
+
+ baseMinusT = base - t;
+ if (w > floor(maxInt / baseMinusT)) {
+ error('overflow');
+ }
+
+ w *= baseMinusT;
+
+ }
+
+ out = output.length + 1;
+ bias = adapt(i - oldi, out, oldi == 0);
+
+ // `i` was supposed to wrap around from `out` to `0`,
+ // incrementing `n` each time, so we'll fix that now:
+ if (floor(i / out) > maxInt - n) {
+ error('overflow');
+ }
+
+ n += floor(i / out);
+ i %= out;
+
+ // Insert `n` at position `i` of the output
+ output.splice(i++, 0, n);
+
+ }
+
+ return ucs2encode(output);
+ }
+
+ /**
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
+ * Punycode string of ASCII-only symbols.
+ * @memberOf punycode
+ * @param {String} input The string of Unicode symbols.
+ * @returns {String} The resulting Punycode string of ASCII-only symbols.
+ */
+ function encode(input) {
+ var n,
+ delta,
+ handledCPCount,
+ basicLength,
+ bias,
+ j,
+ m,
+ q,
+ k,
+ t,
+ currentValue,
+ output = [],
+ /** `inputLength` will hold the number of code points in `input`. */
+ inputLength,
+ /** Cached calculation results */
+ handledCPCountPlusOne,
+ baseMinusT,
+ qMinusT;
+
+ // Convert the input in UCS-2 to Unicode
+ input = ucs2decode(input);
+
+ // Cache the length
+ inputLength = input.length;
+
+ // Initialize the state
+ n = initialN;
+ delta = 0;
+ bias = initialBias;
+
+ // Handle the basic code points
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue < 0x80) {
+ output.push(stringFromCharCode(currentValue));
+ }
+ }
+
+ handledCPCount = basicLength = output.length;
+
+ // `handledCPCount` is the number of code points that have been handled;
+ // `basicLength` is the number of basic code points.
+
+ // Finish the basic string - if it is not empty - with a delimiter
+ if (basicLength) {
+ output.push(delimiter);
+ }
+
+ // Main encoding loop:
+ while (handledCPCount < inputLength) {
+
+ // All non-basic code points < n have been handled already. Find the next
+ // larger one:
+ for (m = maxInt, j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue >= n && currentValue < m) {
+ m = currentValue;
+ }
+ }
+
+ // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+ // but guard against overflow
+ handledCPCountPlusOne = handledCPCount + 1;
+ if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+ error('overflow');
+ }
+
+ delta += (m - n) * handledCPCountPlusOne;
+ n = m;
+
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+
+ if (currentValue < n && ++delta > maxInt) {
+ error('overflow');
+ }
+
+ if (currentValue == n) {
+ // Represent delta as a generalized variable-length integer
+ for (q = delta, k = base; /* no condition */; k += base) {
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+ if (q < t) {
+ break;
+ }
+ qMinusT = q - t;
+ baseMinusT = base - t;
+ output.push(
+ stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+ );
+ q = floor(qMinusT / baseMinusT);
+ }
+
+ output.push(stringFromCharCode(digitToBasic(q, 0)));
+ bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+ delta = 0;
+ ++handledCPCount;
+ }
+ }
+
+ ++delta;
+ ++n;
+
+ }
+ return output.join('');
+ }
+
+ /**
+ * Converts a Punycode string representing a domain name or an email address
+ * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+ * it doesn't matter if you call it on a string that has already been
+ * converted to Unicode.
+ * @memberOf punycode
+ * @param {String} input The Punycoded domain name or email address to
+ * convert to Unicode.
+ * @returns {String} The Unicode representation of the given Punycode
+ * string.
+ */
+ function toUnicode(input) {
+ return mapDomain(input, function(string) {
+ return regexPunycode.test(string)
+ ? decode(string.slice(4).toLowerCase())
+ : string;
+ });
+ }
+
+ /**
+ * Converts a Unicode string representing a domain name or an email address to
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
+ * i.e. it doesn't matter if you call it with a domain that's already in
+ * ASCII.
+ * @memberOf punycode
+ * @param {String} input The domain name or email address to convert, as a
+ * Unicode string.
+ * @returns {String} The Punycode representation of the given domain name or
+ * email address.
+ */
+ function toASCII(input) {
+ return mapDomain(input, function(string) {
+ return regexNonASCII.test(string)
+ ? 'xn--' + encode(string)
+ : string;
+ });
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /** Define the public API */
+ punycode = {
+ /**
+ * A string representing the current Punycode.js version number.
+ * @memberOf punycode
+ * @type String
+ */
+ 'version': '1.4.1',
+ /**
+ * An object of methods to convert from JavaScript's internal character
+ * representation (UCS-2) to Unicode code points, and back.
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode
+ * @type Object
+ */
+ 'ucs2': {
+ 'decode': ucs2decode,
+ 'encode': ucs2encode
+ },
+ 'decode': decode,
+ 'encode': encode,
+ 'toASCII': toASCII,
+ 'toUnicode': toUnicode
+ };
+
+ /** Expose `punycode` */
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define('punycode', function() {
+ return punycode;
+ });
+ } else if (freeExports && freeModule) {
+ if (module.exports == freeExports) {
+ // in Node.js, io.js, or RingoJS v0.8.0+
+ freeModule.exports = punycode;
+ } else {
+ // in Narwhal or RingoJS v0.7.0-
+ for (key in punycode) {
+ punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+ }
+ }
+ } else {
+ // in Rhino or a web browser
+ root.punycode = punycode;
+ }
+
+}(this));
diff --git a/src/lib/vendor/select2-4.0.11/select2-4.0.11.css b/src/lib/vendor/select2-4.0.11/select2-4.0.11.css
new file mode 100644
index 0000000..750b320
--- /dev/null
+++ b/src/lib/vendor/select2-4.0.11/select2-4.0.11.css
@@ -0,0 +1,481 @@
+.select2-container {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle; }
+ .select2-container .select2-selection--single {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: 28px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--single .select2-selection__rendered {
+ display: block;
+ padding-left: 8px;
+ padding-right: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-selection--single .select2-selection__clear {
+ position: relative; }
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 8px;
+ padding-left: 20px; }
+ .select2-container .select2-selection--multiple {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ min-height: 32px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
+ display: inline-block;
+ overflow: hidden;
+ padding-left: 8px;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-search--inline {
+ float: left; }
+ .select2-container .select2-search--inline .select2-search__field {
+ box-sizing: border-box;
+ border: none;
+ font-size: 100%;
+ margin-top: 5px;
+ padding: 0; }
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+.select2-dropdown {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ left: -100000px;
+ width: 100%;
+ z-index: 1051; }
+
+.select2-results {
+ display: block; }
+
+.select2-results__options {
+ list-style: none;
+ margin: 0;
+ padding: 0; }
+
+.select2-results__option {
+ padding: 6px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-results__option[aria-selected] {
+ cursor: pointer; }
+
+.select2-container--open .select2-dropdown {
+ left: 0; }
+
+.select2-container--open .select2-dropdown--above {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--open .select2-dropdown--below {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-search--dropdown {
+ display: block;
+ padding: 4px; }
+ .select2-search--dropdown .select2-search__field {
+ padding: 4px;
+ width: 100%;
+ box-sizing: border-box; }
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+ .select2-search--dropdown.select2-search--hide {
+ display: none; }
+
+.select2-close-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ display: block;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 99;
+ background-color: #fff;
+ filter: alpha(opacity=0); }
+
+.select2-hidden-accessible {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(50%) !important;
+ clip-path: inset(50%) !important;
+ height: 1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ width: 1px !important;
+ white-space: nowrap !important; }
+
+.select2-container--default .select2-selection--single {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ border-radius: 4px; }
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--default .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold; }
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto; }
+
+.select2-container--default.select2-container--disabled .select2-selection--single {
+ background-color: #eee;
+ cursor: default; }
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none; }
+
+.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--default .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none; }
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-top: 5px;
+ margin-right: 10px;
+ padding: 1px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #999;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #333; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border: solid black 1px;
+ outline: 0; }
+
+.select2-container--default.select2-container--disabled .select2-selection--multiple {
+ background-color: #eee;
+ cursor: default; }
+
+.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
+ display: none; }
+
+.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--default .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa; }
+
+.select2-container--default .select2-search--inline .select2-search__field {
+ background: transparent;
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield; }
+
+.select2-container--default .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--default .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999; }
+
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd; }
+
+.select2-container--default .select2-results__option .select2-results__option {
+ padding-left: 1em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em; }
+
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #5897fb;
+ color: white; }
+
+.select2-container--default .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic .select2-selection--single {
+ background-color: #f7f7f7;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ outline: 0;
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+ .select2-container--classic .select2-selection--single:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-right: 10px; }
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
+ background-color: #ddd;
+ border: none;
+ border-left: 1px solid #aaa;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ border: none;
+ border-right: 1px solid #aaa;
+ border-radius: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ left: 1px;
+ right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--single {
+ border: 1px solid #5897fb; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
+ background: transparent;
+ border: none; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
+
+.select2-container--classic .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text;
+ outline: 0; }
+ .select2-container--classic .select2-selection--multiple:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
+ list-style: none;
+ margin: 0;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
+ display: none; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
+ color: #888;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #555; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ float: right;
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--multiple {
+ border: 1px solid #5897fb; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--classic .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa;
+ outline: 0; }
+
+.select2-container--classic .select2-search--inline .select2-search__field {
+ outline: 0;
+ box-shadow: none; }
+
+.select2-container--classic .select2-dropdown {
+ background-color: white;
+ border: 1px solid transparent; }
+
+.select2-container--classic .select2-dropdown--above {
+ border-bottom: none; }
+
+.select2-container--classic .select2-dropdown--below {
+ border-top: none; }
+
+.select2-container--classic .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--classic .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--classic .select2-results__option[aria-disabled=true] {
+ color: grey; }
+
+.select2-container--classic .select2-results__option--highlighted[aria-selected] {
+ background-color: #3875d7;
+ color: white; }
+
+.select2-container--classic .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic.select2-container--open .select2-dropdown {
+ border-color: #5897fb; }
diff --git a/src/lib/vendor/select2-4.0.11/select2-4.0.11.js b/src/lib/vendor/select2-4.0.11/select2-4.0.11.js
new file mode 100644
index 0000000..6da089a
--- /dev/null
+++ b/src/lib/vendor/select2-4.0.11/select2-4.0.11.js
@@ -0,0 +1,6044 @@
+/*!
+ * Select2 4.0.11
+ * https://select2.github.io
+ *
+ * Released under the MIT license
+ * https://github.com/select2/select2/blob/master/LICENSE.md
+ */
+;(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node/CommonJS
+ module.exports = function (root, jQuery) {
+ if (jQuery === undefined) {
+ // require('jQuery') returns a factory that requires window to
+ // build a jQuery instance, we normalize how we use modules
+ // that require this pattern but the window provided is a noop
+ // if it's defined (how jquery works)
+ if (typeof window !== 'undefined') {
+ jQuery = require('jquery');
+ }
+ else {
+ jQuery = require('jquery')(root);
+ }
+ }
+ factory(jQuery);
+ return jQuery;
+ };
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+} (function (jQuery) {
+ // This is needed so we can catch the AMD loader configuration and use it
+ // The inner file should be wrapped (by `banner.start.js`) in a function that
+ // returns the AMD loader references.
+ var S2 =(function () {
+ // Restore the Select2 AMD loader so it can be used
+ // Needed mostly in the language files, where the loader is not inserted
+ if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
+ var S2 = jQuery.fn.select2.amd;
+ }
+var S2;(function () { if (!S2 || !S2.requirejs) {
+if (!S2) { S2 = {}; } else { require = S2; }
+/**
+ * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
+ * Released under MIT license, http://github.com/requirejs/almond/LICENSE
+ */
+//Going sloppy to avoid 'use strict' string cost, but strict practices should
+//be followed.
+/*global setTimeout: false */
+
+var requirejs, require, define;
+(function (undef) {
+ var main, req, makeMap, handlers,
+ defined = {},
+ waiting = {},
+ config = {},
+ defining = {},
+ hasOwn = Object.prototype.hasOwnProperty,
+ aps = [].slice,
+ jsSuffixRegExp = /\.js$/;
+
+ function hasProp(obj, prop) {
+ return hasOwn.call(obj, prop);
+ }
+
+ /**
+ * Given a relative module name, like ./something, normalize it to
+ * a real name that can be mapped to a path.
+ * @param {String} name the relative name
+ * @param {String} baseName a real name that the name arg is relative
+ * to.
+ * @returns {String} normalized name
+ */
+ function normalize(name, baseName) {
+ var nameParts, nameSegment, mapValue, foundMap, lastIndex,
+ foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
+ baseParts = baseName && baseName.split("/"),
+ map = config.map,
+ starMap = (map && map['*']) || {};
+
+ //Adjust any relative paths.
+ if (name) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
+
+ // If wanting node ID compatibility, strip .js from end
+ // of IDs. Have to do this here, and not in nameToUrl
+ // because node allows either .js or non .js to map
+ // to same file.
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
+
+ // Starts with a '.' so need the baseName
+ if (name[0].charAt(0) === '.' && baseParts) {
+ //Convert baseName to array, and lop off the last part,
+ //so that . matches that 'directory' and not name of the baseName's
+ //module. For instance, baseName of 'one/two/three', maps to
+ //'one/two/three.js', but we want the directory, 'one/two' for
+ //this normalization.
+ normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
+ name = normalizedBaseParts.concat(name);
+ }
+
+ //start trimDots
+ for (i = 0; i < name.length; i++) {
+ part = name[i];
+ if (part === '.') {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === '..') {
+ // If at the start, or previous value is still ..,
+ // keep them so that when converted to a path it may
+ // still work when converted to a path, even though
+ // as an ID it is less than ideal. In larger point
+ // releases, may be better to just kick out an error.
+ if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
+ continue;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
+ }
+ }
+ //end trimDots
+
+ name = name.join('/');
+ }
+
+ //Apply map config if available.
+ if ((baseParts || starMap) && map) {
+ nameParts = name.split('/');
+
+ for (i = nameParts.length; i > 0; i -= 1) {
+ nameSegment = nameParts.slice(0, i).join("/");
+
+ if (baseParts) {
+ //Find the longest baseName segment match in the config.
+ //So, do joins on the biggest to smallest lengths of baseParts.
+ for (j = baseParts.length; j > 0; j -= 1) {
+ mapValue = map[baseParts.slice(0, j).join('/')];
+
+ //baseName segment has config, find if it has one for
+ //this name.
+ if (mapValue) {
+ mapValue = mapValue[nameSegment];
+ if (mapValue) {
+ //Match, update name to the new value.
+ foundMap = mapValue;
+ foundI = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundMap) {
+ break;
+ }
+
+ //Check for a star map match, but just hold on to it,
+ //if there is a shorter segment match later in a matching
+ //config, then favor over this star map.
+ if (!foundStarMap && starMap && starMap[nameSegment]) {
+ foundStarMap = starMap[nameSegment];
+ starI = i;
+ }
+ }
+
+ if (!foundMap && foundStarMap) {
+ foundMap = foundStarMap;
+ foundI = starI;
+ }
+
+ if (foundMap) {
+ nameParts.splice(0, foundI, foundMap);
+ name = nameParts.join('/');
+ }
+ }
+
+ return name;
+ }
+
+ function makeRequire(relName, forceSync) {
+ return function () {
+ //A version of a require function that passes a moduleName
+ //value for items that may need to
+ //look up paths relative to the moduleName
+ var args = aps.call(arguments, 0);
+
+ //If first arg is not require('string'), and there is only
+ //one arg, it is the array form without a callback. Insert
+ //a null so that the following concat is correct.
+ if (typeof args[0] !== 'string' && args.length === 1) {
+ args.push(null);
+ }
+ return req.apply(undef, args.concat([relName, forceSync]));
+ };
+ }
+
+ function makeNormalize(relName) {
+ return function (name) {
+ return normalize(name, relName);
+ };
+ }
+
+ function makeLoad(depName) {
+ return function (value) {
+ defined[depName] = value;
+ };
+ }
+
+ function callDep(name) {
+ if (hasProp(waiting, name)) {
+ var args = waiting[name];
+ delete waiting[name];
+ defining[name] = true;
+ main.apply(undef, args);
+ }
+
+ if (!hasProp(defined, name) && !hasProp(defining, name)) {
+ throw new Error('No ' + name);
+ }
+ return defined[name];
+ }
+
+ //Turns a plugin!resource to [plugin, resource]
+ //with the plugin being undefined if the name
+ //did not have a plugin prefix.
+ function splitPrefix(name) {
+ var prefix,
+ index = name ? name.indexOf('!') : -1;
+ if (index > -1) {
+ prefix = name.substring(0, index);
+ name = name.substring(index + 1, name.length);
+ }
+ return [prefix, name];
+ }
+
+ //Creates a parts array for a relName where first part is plugin ID,
+ //second part is resource ID. Assumes relName has already been normalized.
+ function makeRelParts(relName) {
+ return relName ? splitPrefix(relName) : [];
+ }
+
+ /**
+ * Makes a name map, normalizing the name, and using a plugin
+ * for normalization if necessary. Grabs a ref to plugin
+ * too, as an optimization.
+ */
+ makeMap = function (name, relParts) {
+ var plugin,
+ parts = splitPrefix(name),
+ prefix = parts[0],
+ relResourceName = relParts[1];
+
+ name = parts[1];
+
+ if (prefix) {
+ prefix = normalize(prefix, relResourceName);
+ plugin = callDep(prefix);
+ }
+
+ //Normalize according
+ if (prefix) {
+ if (plugin && plugin.normalize) {
+ name = plugin.normalize(name, makeNormalize(relResourceName));
+ } else {
+ name = normalize(name, relResourceName);
+ }
+ } else {
+ name = normalize(name, relResourceName);
+ parts = splitPrefix(name);
+ prefix = parts[0];
+ name = parts[1];
+ if (prefix) {
+ plugin = callDep(prefix);
+ }
+ }
+
+ //Using ridiculous property names for space reasons
+ return {
+ f: prefix ? prefix + '!' + name : name, //fullName
+ n: name,
+ pr: prefix,
+ p: plugin
+ };
+ };
+
+ function makeConfig(name) {
+ return function () {
+ return (config && config.config && config.config[name]) || {};
+ };
+ }
+
+ handlers = {
+ require: function (name) {
+ return makeRequire(name);
+ },
+ exports: function (name) {
+ var e = defined[name];
+ if (typeof e !== 'undefined') {
+ return e;
+ } else {
+ return (defined[name] = {});
+ }
+ },
+ module: function (name) {
+ return {
+ id: name,
+ uri: '',
+ exports: defined[name],
+ config: makeConfig(name)
+ };
+ }
+ };
+
+ main = function (name, deps, callback, relName) {
+ var cjsModule, depName, ret, map, i, relParts,
+ args = [],
+ callbackType = typeof callback,
+ usingExports;
+
+ //Use name if no relName
+ relName = relName || name;
+ relParts = makeRelParts(relName);
+
+ //Call the callback to define the module, if necessary.
+ if (callbackType === 'undefined' || callbackType === 'function') {
+ //Pull out the defined dependencies and pass the ordered
+ //values to the callback.
+ //Default to [require, exports, module] if no deps
+ deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
+ for (i = 0; i < deps.length; i += 1) {
+ map = makeMap(deps[i], relParts);
+ depName = map.f;
+
+ //Fast path CommonJS standard dependencies.
+ if (depName === "require") {
+ args[i] = handlers.require(name);
+ } else if (depName === "exports") {
+ //CommonJS module spec 1.1
+ args[i] = handlers.exports(name);
+ usingExports = true;
+ } else if (depName === "module") {
+ //CommonJS module spec 1.1
+ cjsModule = args[i] = handlers.module(name);
+ } else if (hasProp(defined, depName) ||
+ hasProp(waiting, depName) ||
+ hasProp(defining, depName)) {
+ args[i] = callDep(depName);
+ } else if (map.p) {
+ map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
+ args[i] = defined[depName];
+ } else {
+ throw new Error(name + ' missing ' + depName);
+ }
+ }
+
+ ret = callback ? callback.apply(defined[name], args) : undefined;
+
+ if (name) {
+ //If setting exports via "module" is in play,
+ //favor that over return value and exports. After that,
+ //favor a non-undefined return value over exports use.
+ if (cjsModule && cjsModule.exports !== undef &&
+ cjsModule.exports !== defined[name]) {
+ defined[name] = cjsModule.exports;
+ } else if (ret !== undef || !usingExports) {
+ //Use the return value from the function.
+ defined[name] = ret;
+ }
+ }
+ } else if (name) {
+ //May just be an object definition for the module. Only
+ //worry about defining if have a module name.
+ defined[name] = callback;
+ }
+ };
+
+ requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
+ if (typeof deps === "string") {
+ if (handlers[deps]) {
+ //callback in this case is really relName
+ return handlers[deps](callback);
+ }
+ //Just return the module wanted. In this scenario, the
+ //deps arg is the module name, and second arg (if passed)
+ //is just the relName.
+ //Normalize module name, if it contains . or ..
+ return callDep(makeMap(deps, makeRelParts(callback)).f);
+ } else if (!deps.splice) {
+ //deps is a config object, not an array.
+ config = deps;
+ if (config.deps) {
+ req(config.deps, config.callback);
+ }
+ if (!callback) {
+ return;
+ }
+
+ if (callback.splice) {
+ //callback is an array, which means it is a dependency list.
+ //Adjust args if there are dependencies
+ deps = callback;
+ callback = relName;
+ relName = null;
+ } else {
+ deps = undef;
+ }
+ }
+
+ //Support require(['a'])
+ callback = callback || function () {};
+
+ //If relName is a function, it is an errback handler,
+ //so remove it.
+ if (typeof relName === 'function') {
+ relName = forceSync;
+ forceSync = alt;
+ }
+
+ //Simulate async callback;
+ if (forceSync) {
+ main(undef, deps, callback, relName);
+ } else {
+ //Using a non-zero value because of concern for what old browsers
+ //do, and latest browsers "upgrade" to 4 if lower value is used:
+ //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
+ //If want a value immediately, use require('id') instead -- something
+ //that works in almond on the global level, but not guaranteed and
+ //unlikely to work in other AMD implementations.
+ setTimeout(function () {
+ main(undef, deps, callback, relName);
+ }, 4);
+ }
+
+ return req;
+ };
+
+ /**
+ * Just drops the config on the floor, but returns req in case
+ * the config return value is used.
+ */
+ req.config = function (cfg) {
+ return req(cfg);
+ };
+
+ /**
+ * Expose module registry for debugging and tooling
+ */
+ requirejs._defined = defined;
+
+ define = function (name, deps, callback) {
+ if (typeof name !== 'string') {
+ throw new Error('See almond README: incorrect module build, no module name');
+ }
+
+ //This module may not have dependencies
+ if (!deps.splice) {
+ //deps is not an array, so probably means
+ //an object literal or factory function for
+ //the value. Adjust args.
+ callback = deps;
+ deps = [];
+ }
+
+ if (!hasProp(defined, name) && !hasProp(waiting, name)) {
+ waiting[name] = [name, deps, callback];
+ }
+ };
+
+ define.amd = {
+ jQuery: true
+ };
+}());
+
+S2.requirejs = requirejs;S2.require = require;S2.define = define;
+}
+}());
+S2.define("almond", function(){});
+
+/* global jQuery:false, $:false */
+S2.define('jquery',[],function () {
+ var _$ = jQuery || $;
+
+ if (_$ == null && console && console.error) {
+ console.error(
+ 'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
+ 'found. Make sure that you are including jQuery before Select2 on your ' +
+ 'web page.'
+ );
+ }
+
+ return _$;
+});
+
+S2.define('select2/utils',[
+ 'jquery'
+], function ($) {
+ var Utils = {};
+
+ Utils.Extend = function (ChildClass, SuperClass) {
+ var __hasProp = {}.hasOwnProperty;
+
+ function BaseConstructor () {
+ this.constructor = ChildClass;
+ }
+
+ for (var key in SuperClass) {
+ if (__hasProp.call(SuperClass, key)) {
+ ChildClass[key] = SuperClass[key];
+ }
+ }
+
+ BaseConstructor.prototype = SuperClass.prototype;
+ ChildClass.prototype = new BaseConstructor();
+ ChildClass.__super__ = SuperClass.prototype;
+
+ return ChildClass;
+ };
+
+ function getMethods (theClass) {
+ var proto = theClass.prototype;
+
+ var methods = [];
+
+ for (var methodName in proto) {
+ var m = proto[methodName];
+
+ if (typeof m !== 'function') {
+ continue;
+ }
+
+ if (methodName === 'constructor') {
+ continue;
+ }
+
+ methods.push(methodName);
+ }
+
+ return methods;
+ }
+
+ Utils.Decorate = function (SuperClass, DecoratorClass) {
+ var decoratedMethods = getMethods(DecoratorClass);
+ var superMethods = getMethods(SuperClass);
+
+ function DecoratedClass () {
+ var unshift = Array.prototype.unshift;
+
+ var argCount = DecoratorClass.prototype.constructor.length;
+
+ var calledConstructor = SuperClass.prototype.constructor;
+
+ if (argCount > 0) {
+ unshift.call(arguments, SuperClass.prototype.constructor);
+
+ calledConstructor = DecoratorClass.prototype.constructor;
+ }
+
+ calledConstructor.apply(this, arguments);
+ }
+
+ DecoratorClass.displayName = SuperClass.displayName;
+
+ function ctr () {
+ this.constructor = DecoratedClass;
+ }
+
+ DecoratedClass.prototype = new ctr();
+
+ for (var m = 0; m < superMethods.length; m++) {
+ var superMethod = superMethods[m];
+
+ DecoratedClass.prototype[superMethod] =
+ SuperClass.prototype[superMethod];
+ }
+
+ var calledMethod = function (methodName) {
+ // Stub out the original method if it's not decorating an actual method
+ var originalMethod = function () {};
+
+ if (methodName in DecoratedClass.prototype) {
+ originalMethod = DecoratedClass.prototype[methodName];
+ }
+
+ var decoratedMethod = DecoratorClass.prototype[methodName];
+
+ return function () {
+ var unshift = Array.prototype.unshift;
+
+ unshift.call(arguments, originalMethod);
+
+ return decoratedMethod.apply(this, arguments);
+ };
+ };
+
+ for (var d = 0; d < decoratedMethods.length; d++) {
+ var decoratedMethod = decoratedMethods[d];
+
+ DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
+ }
+
+ return DecoratedClass;
+ };
+
+ var Observable = function () {
+ this.listeners = {};
+ };
+
+ Observable.prototype.on = function (event, callback) {
+ this.listeners = this.listeners || {};
+
+ if (event in this.listeners) {
+ this.listeners[event].push(callback);
+ } else {
+ this.listeners[event] = [callback];
+ }
+ };
+
+ Observable.prototype.trigger = function (event) {
+ var slice = Array.prototype.slice;
+ var params = slice.call(arguments, 1);
+
+ this.listeners = this.listeners || {};
+
+ // Params should always come in as an array
+ if (params == null) {
+ params = [];
+ }
+
+ // If there are no arguments to the event, use a temporary object
+ if (params.length === 0) {
+ params.push({});
+ }
+
+ // Set the `_type` of the first object to the event
+ params[0]._type = event;
+
+ if (event in this.listeners) {
+ this.invoke(this.listeners[event], slice.call(arguments, 1));
+ }
+
+ if ('*' in this.listeners) {
+ this.invoke(this.listeners['*'], arguments);
+ }
+ };
+
+ Observable.prototype.invoke = function (listeners, params) {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].apply(this, params);
+ }
+ };
+
+ Utils.Observable = Observable;
+
+ Utils.generateChars = function (length) {
+ var chars = '';
+
+ for (var i = 0; i < length; i++) {
+ var randomChar = Math.floor(Math.random() * 36);
+ chars += randomChar.toString(36);
+ }
+
+ return chars;
+ };
+
+ Utils.bind = function (func, context) {
+ return function () {
+ func.apply(context, arguments);
+ };
+ };
+
+ Utils._convertData = function (data) {
+ for (var originalKey in data) {
+ var keys = originalKey.split('-');
+
+ var dataLevel = data;
+
+ if (keys.length === 1) {
+ continue;
+ }
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+
+ // Lowercase the first letter
+ // By default, dash-separated becomes camelCase
+ key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+ if (!(key in dataLevel)) {
+ dataLevel[key] = {};
+ }
+
+ if (k == keys.length - 1) {
+ dataLevel[key] = data[originalKey];
+ }
+
+ dataLevel = dataLevel[key];
+ }
+
+ delete data[originalKey];
+ }
+
+ return data;
+ };
+
+ Utils.hasScroll = function (index, el) {
+ // Adapted from the function created by @ShadowScripter
+ // and adapted by @BillBarry on the Stack Exchange Code Review website.
+ // The original code can be found at
+ // http://codereview.stackexchange.com/q/13338
+ // and was designed to be used with the Sizzle selector engine.
+
+ var $el = $(el);
+ var overflowX = el.style.overflowX;
+ var overflowY = el.style.overflowY;
+
+ //Check both x and y declarations
+ if (overflowX === overflowY &&
+ (overflowY === 'hidden' || overflowY === 'visible')) {
+ return false;
+ }
+
+ if (overflowX === 'scroll' || overflowY === 'scroll') {
+ return true;
+ }
+
+ return ($el.innerHeight() < el.scrollHeight ||
+ $el.innerWidth() < el.scrollWidth);
+ };
+
+ Utils.escapeMarkup = function (markup) {
+ var replaceMap = {
+ '\\': '&#92;',
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ '\'': '&#39;',
+ '/': '&#47;'
+ };
+
+ // Do not try to escape the markup if it's not a string
+ if (typeof markup !== 'string') {
+ return markup;
+ }
+
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
+ return replaceMap[match];
+ });
+ };
+
+ // Append an array of jQuery nodes to a given element.
+ Utils.appendMany = function ($element, $nodes) {
+ // jQuery 1.7.x does not support $.fn.append() with an array
+ // Fall back to a jQuery object collection using $.fn.add()
+ if ($.fn.jquery.substr(0, 3) === '1.7') {
+ var $jqNodes = $();
+
+ $.map($nodes, function (node) {
+ $jqNodes = $jqNodes.add(node);
+ });
+
+ $nodes = $jqNodes;
+ }
+
+ $element.append($nodes);
+ };
+
+ // Cache objects in Utils.__cache instead of $.data (see #4346)
+ Utils.__cache = {};
+
+ var id = 0;
+ Utils.GetUniqueElementId = function (element) {
+ // Get a unique element Id. If element has no id,
+ // creates a new unique number, stores it in the id
+ // attribute and returns the new id.
+ // If an id already exists, it simply returns it.
+
+ var select2Id = element.getAttribute('data-select2-id');
+ if (select2Id == null) {
+ // If element has id, use it.
+ if (element.id) {
+ select2Id = element.id;
+ element.setAttribute('data-select2-id', select2Id);
+ } else {
+ element.setAttribute('data-select2-id', ++id);
+ select2Id = id.toString();
+ }
+ }
+ return select2Id;
+ };
+
+ Utils.StoreData = function (element, name, value) {
+ // Stores an item in the cache for a specified element.
+ // name is the cache key.
+ var id = Utils.GetUniqueElementId(element);
+ if (!Utils.__cache[id]) {
+ Utils.__cache[id] = {};
+ }
+
+ Utils.__cache[id][name] = value;
+ };
+
+ Utils.GetData = function (element, name) {
+ // Retrieves a value from the cache by its key (name)
+ // name is optional. If no name specified, return
+ // all cache items for the specified element.
+ // and for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (name) {
+ if (Utils.__cache[id]) {
+ if (Utils.__cache[id][name] != null) {
+ return Utils.__cache[id][name];
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ } else {
+ return Utils.__cache[id];
+ }
+ };
+
+ Utils.RemoveData = function (element) {
+ // Removes all cached items for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (Utils.__cache[id] != null) {
+ delete Utils.__cache[id];
+ }
+
+ element.removeAttribute('data-select2-id');
+ };
+
+ return Utils;
+});
+
+S2.define('select2/results',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Results ($element, options, dataAdapter) {
+ this.$element = $element;
+ this.data = dataAdapter;
+ this.options = options;
+
+ Results.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Results, Utils.Observable);
+
+ Results.prototype.render = function () {
+ var $results = $(
+ '<ul class="select2-results__options" role="listbox"></ul>'
+ );
+
+ if (this.options.get('multiple')) {
+ $results.attr('aria-multiselectable', 'true');
+ }
+
+ this.$results = $results;
+
+ return $results;
+ };
+
+ Results.prototype.clear = function () {
+ this.$results.empty();
+ };
+
+ Results.prototype.displayMessage = function (params) {
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ this.clear();
+ this.hideLoading();
+
+ var $message = $(
+ '<li role="alert" aria-live="assertive"' +
+ ' class="select2-results__option"></li>'
+ );
+
+ var message = this.options.get('translations').get(params.message);
+
+ $message.append(
+ escapeMarkup(
+ message(params.args)
+ )
+ );
+
+ $message[0].className += ' select2-results__message';
+
+ this.$results.append($message);
+ };
+
+ Results.prototype.hideMessages = function () {
+ this.$results.find('.select2-results__message').remove();
+ };
+
+ Results.prototype.append = function (data) {
+ this.hideLoading();
+
+ var $options = [];
+
+ if (data.results == null || data.results.length === 0) {
+ if (this.$results.children().length === 0) {
+ this.trigger('results:message', {
+ message: 'noResults'
+ });
+ }
+
+ return;
+ }
+
+ data.results = this.sort(data.results);
+
+ for (var d = 0; d < data.results.length; d++) {
+ var item = data.results[d];
+
+ var $option = this.option(item);
+
+ $options.push($option);
+ }
+
+ this.$results.append($options);
+ };
+
+ Results.prototype.position = function ($results, $dropdown) {
+ var $resultsContainer = $dropdown.find('.select2-results');
+ $resultsContainer.append($results);
+ };
+
+ Results.prototype.sort = function (data) {
+ var sorter = this.options.get('sorter');
+
+ return sorter(data);
+ };
+
+ Results.prototype.highlightFirstItem = function () {
+ var $options = this.$results
+ .find('.select2-results__option[aria-selected]');
+
+ var $selected = $options.filter('[aria-selected=true]');
+
+ // Check if there are any selected options
+ if ($selected.length > 0) {
+ // If there are selected options, highlight the first
+ $selected.first().trigger('mouseenter');
+ } else {
+ // If there are no selected options, highlight the first option
+ // in the dropdown
+ $options.first().trigger('mouseenter');
+ }
+
+ this.ensureHighlightVisible();
+ };
+
+ Results.prototype.setClasses = function () {
+ var self = this;
+
+ this.data.current(function (selected) {
+ var selectedIds = $.map(selected, function (s) {
+ return s.id.toString();
+ });
+
+ var $options = self.$results
+ .find('.select2-results__option[aria-selected]');
+
+ $options.each(function () {
+ var $option = $(this);
+
+ var item = Utils.GetData(this, 'data');
+
+ // id needs to be converted to a string when comparing
+ var id = '' + item.id;
+
+ if ((item.element != null && item.element.selected) ||
+ (item.element == null && $.inArray(id, selectedIds) > -1)) {
+ $option.attr('aria-selected', 'true');
+ } else {
+ $option.attr('aria-selected', 'false');
+ }
+ });
+
+ });
+ };
+
+ Results.prototype.showLoading = function (params) {
+ this.hideLoading();
+
+ var loadingMore = this.options.get('translations').get('searching');
+
+ var loading = {
+ disabled: true,
+ loading: true,
+ text: loadingMore(params)
+ };
+ var $loading = this.option(loading);
+ $loading.className += ' loading-results';
+
+ this.$results.prepend($loading);
+ };
+
+ Results.prototype.hideLoading = function () {
+ this.$results.find('.loading-results').remove();
+ };
+
+ Results.prototype.option = function (data) {
+ var option = document.createElement('li');
+ option.className = 'select2-results__option';
+
+ var attrs = {
+ 'role': 'option',
+ 'aria-selected': 'false'
+ };
+
+ var matches = window.Element.prototype.matches ||
+ window.Element.prototype.msMatchesSelector ||
+ window.Element.prototype.webkitMatchesSelector;
+
+ if ((data.element != null && matches.call(data.element, ':disabled')) ||
+ (data.element == null && data.disabled)) {
+ delete attrs['aria-selected'];
+ attrs['aria-disabled'] = 'true';
+ }
+
+ if (data.id == null) {
+ delete attrs['aria-selected'];
+ }
+
+ if (data._resultId != null) {
+ option.id = data._resultId;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ if (data.children) {
+ attrs.role = 'group';
+ attrs['aria-label'] = data.text;
+ delete attrs['aria-selected'];
+ }
+
+ for (var attr in attrs) {
+ var val = attrs[attr];
+
+ option.setAttribute(attr, val);
+ }
+
+ if (data.children) {
+ var $option = $(option);
+
+ var label = document.createElement('strong');
+ label.className = 'select2-results__group';
+
+ var $label = $(label);
+ this.template(data, label);
+
+ var $children = [];
+
+ for (var c = 0; c < data.children.length; c++) {
+ var child = data.children[c];
+
+ var $child = this.option(child);
+
+ $children.push($child);
+ }
+
+ var $childrenContainer = $('<ul></ul>', {
+ 'class': 'select2-results__options select2-results__options--nested'
+ });
+
+ $childrenContainer.append($children);
+
+ $option.append(label);
+ $option.append($childrenContainer);
+ } else {
+ this.template(data, option);
+ }
+
+ Utils.StoreData(option, 'data', data);
+
+ return option;
+ };
+
+ Results.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var id = container.id + '-results';
+
+ this.$results.attr('id', id);
+
+ container.on('results:all', function (params) {
+ self.clear();
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('results:append', function (params) {
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ }
+ });
+
+ container.on('query', function (params) {
+ self.hideMessages();
+ self.showLoading(params);
+ });
+
+ container.on('select', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('unselect', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expended="true"
+ self.$results.attr('aria-expanded', 'true');
+ self.$results.attr('aria-hidden', 'false');
+
+ self.setClasses();
+ self.ensureHighlightVisible();
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expended="false"
+ self.$results.attr('aria-expanded', 'false');
+ self.$results.attr('aria-hidden', 'true');
+ self.$results.removeAttr('aria-activedescendant');
+ });
+
+ container.on('results:toggle', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ $highlighted.trigger('mouseup');
+ });
+
+ container.on('results:select', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var data = Utils.GetData($highlighted[0], 'data');
+
+ if ($highlighted.attr('aria-selected') == 'true') {
+ self.trigger('close', {});
+ } else {
+ self.trigger('select', {
+ data: data
+ });
+ }
+ });
+
+ container.on('results:previous', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ // If we are already at the top, don't move further
+ // If no options, currentIndex will be -1
+ if (currentIndex <= 0) {
+ return;
+ }
+
+ var nextIndex = currentIndex - 1;
+
+ // If none are highlighted, highlight the first
+ if ($highlighted.length === 0) {
+ nextIndex = 0;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top;
+ var nextTop = $next.offset().top;
+ var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextTop - currentOffset < 0) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:next', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var nextIndex = currentIndex + 1;
+
+ // If we are at the last option, stay there
+ if (nextIndex >= $options.length) {
+ return;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top +
+ self.$results.outerHeight(false);
+ var nextBottom = $next.offset().top + $next.outerHeight(false);
+ var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextBottom > currentOffset) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ params.element.addClass('select2-results__option--highlighted');
+ });
+
+ container.on('results:message', function (params) {
+ self.displayMessage(params);
+ });
+
+ if ($.fn.mousewheel) {
+ this.$results.on('mousewheel', function (e) {
+ var top = self.$results.scrollTop();
+
+ var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
+
+ var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
+ var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
+
+ if (isAtTop) {
+ self.$results.scrollTop(0);
+
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (isAtBottom) {
+ self.$results.scrollTop(
+ self.$results.get(0).scrollHeight - self.$results.height()
+ );
+
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var $this = $(this);
+
+ var data = Utils.GetData(this, 'data');
+
+ if ($this.attr('aria-selected') === 'true') {
+ if (self.options.get('multiple')) {
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ } else {
+ self.trigger('close', {});
+ }
+
+ return;
+ }
+
+ self.trigger('select', {
+ originalEvent: evt,
+ data: data
+ });
+ });
+
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var data = Utils.GetData(this, 'data');
+
+ self.getHighlightedResults()
+ .removeClass('select2-results__option--highlighted');
+
+ self.trigger('results:focus', {
+ data: data,
+ element: $(this)
+ });
+ });
+ };
+
+ Results.prototype.getHighlightedResults = function () {
+ var $highlighted = this.$results
+ .find('.select2-results__option--highlighted');
+
+ return $highlighted;
+ };
+
+ Results.prototype.destroy = function () {
+ this.$results.remove();
+ };
+
+ Results.prototype.ensureHighlightVisible = function () {
+ var $highlighted = this.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var $options = this.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var currentOffset = this.$results.offset().top;
+ var nextTop = $highlighted.offset().top;
+ var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
+
+ var offsetDelta = nextTop - currentOffset;
+ nextOffset -= $highlighted.outerHeight(false) * 2;
+
+ if (currentIndex <= 2) {
+ this.$results.scrollTop(0);
+ } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
+ this.$results.scrollTop(nextOffset);
+ }
+ };
+
+ Results.prototype.template = function (result, container) {
+ var template = this.options.get('templateResult');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ var content = template(result, container);
+
+ if (content == null) {
+ container.style.display = 'none';
+ } else if (typeof content === 'string') {
+ container.innerHTML = escapeMarkup(content);
+ } else {
+ $(container).append(content);
+ }
+ };
+
+ return Results;
+});
+
+S2.define('select2/keys',[
+
+], function () {
+ var KEYS = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ ESC: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ DELETE: 46
+ };
+
+ return KEYS;
+});
+
+S2.define('select2/selection/base',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function BaseSelection ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ BaseSelection.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseSelection, Utils.Observable);
+
+ BaseSelection.prototype.render = function () {
+ var $selection = $(
+ '<span class="select2-selection" role="combobox" ' +
+ ' aria-haspopup="true" aria-expanded="false">' +
+ '</span>'
+ );
+
+ this._tabindex = 0;
+
+ if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
+ this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
+ } else if (this.$element.attr('tabindex') != null) {
+ this._tabindex = this.$element.attr('tabindex');
+ }
+
+ $selection.attr('title', this.$element.attr('title'));
+ $selection.attr('tabindex', this._tabindex);
+ $selection.attr('aria-disabled', 'false');
+
+ this.$selection = $selection;
+
+ return $selection;
+ };
+
+ BaseSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ this.container = container;
+
+ this.$selection.on('focus', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('blur', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ if (evt.which === KEYS.SPACE) {
+ evt.preventDefault();
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ self.$selection.attr('aria-activedescendant', params.data._resultId);
+ });
+
+ container.on('selection:update', function (params) {
+ self.update(params.data);
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expanded="true"
+ self.$selection.attr('aria-expanded', 'true');
+ self.$selection.attr('aria-owns', resultsId);
+
+ self._attachCloseHandler(container);
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expanded="false"
+ self.$selection.attr('aria-expanded', 'false');
+ self.$selection.removeAttr('aria-activedescendant');
+ self.$selection.removeAttr('aria-owns');
+
+ self.$selection.trigger('focus');
+
+ self._detachCloseHandler(container);
+ });
+
+ container.on('enable', function () {
+ self.$selection.attr('tabindex', self._tabindex);
+ self.$selection.attr('aria-disabled', 'false');
+ });
+
+ container.on('disable', function () {
+ self.$selection.attr('tabindex', '-1');
+ self.$selection.attr('aria-disabled', 'true');
+ });
+ };
+
+ BaseSelection.prototype._handleBlur = function (evt) {
+ var self = this;
+
+ // This needs to be delayed as the active element is the body when the tab
+ // key is pressed, possibly along with others.
+ window.setTimeout(function () {
+ // Don't trigger `blur` if the focus is still in the selection
+ if (
+ (document.activeElement == self.$selection[0]) ||
+ ($.contains(self.$selection[0], document.activeElement))
+ ) {
+ return;
+ }
+
+ self.trigger('blur', evt);
+ }, 1);
+ };
+
+ BaseSelection.prototype._attachCloseHandler = function (container) {
+
+ $(document.body).on('mousedown.select2.' + container.id, function (e) {
+ var $target = $(e.target);
+
+ var $select = $target.closest('.select2');
+
+ var $all = $('.select2.select2-container--open');
+
+ $all.each(function () {
+ if (this == $select[0]) {
+ return;
+ }
+
+ var $element = Utils.GetData(this, 'element');
+
+ $element.select2('close');
+ });
+ });
+ };
+
+ BaseSelection.prototype._detachCloseHandler = function (container) {
+ $(document.body).off('mousedown.select2.' + container.id);
+ };
+
+ BaseSelection.prototype.position = function ($selection, $container) {
+ var $selectionContainer = $container.find('.selection');
+ $selectionContainer.append($selection);
+ };
+
+ BaseSelection.prototype.destroy = function () {
+ this._detachCloseHandler(this.container);
+ };
+
+ BaseSelection.prototype.update = function (data) {
+ throw new Error('The `update` method must be defined in child classes.');
+ };
+
+ return BaseSelection;
+});
+
+S2.define('select2/selection/single',[
+ 'jquery',
+ './base',
+ '../utils',
+ '../keys'
+], function ($, BaseSelection, Utils, KEYS) {
+ function SingleSelection () {
+ SingleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(SingleSelection, BaseSelection);
+
+ SingleSelection.prototype.render = function () {
+ var $selection = SingleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--single');
+
+ $selection.html(
+ '<span class="select2-selection__rendered"></span>' +
+ '<span class="select2-selection__arrow" role="presentation">' +
+ '<b role="presentation"></b>' +
+ '</span>'
+ );
+
+ return $selection;
+ };
+
+ SingleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ SingleSelection.__super__.bind.apply(this, arguments);
+
+ var id = container.id + '-container';
+
+ this.$selection.find('.select2-selection__rendered')
+ .attr('id', id)
+ .attr('role', 'textbox')
+ .attr('aria-readonly', 'true');
+ this.$selection.attr('aria-labelledby', id);
+
+ this.$selection.on('mousedown', function (evt) {
+ // Only respond to left clicks
+ if (evt.which !== 1) {
+ return;
+ }
+
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on('focus', function (evt) {
+ // User focuses on the container
+ });
+
+ this.$selection.on('blur', function (evt) {
+ // User exits the container
+ });
+
+ container.on('focus', function (evt) {
+ if (!container.isOpen()) {
+ self.$selection.trigger('focus');
+ }
+ });
+ };
+
+ SingleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title'); // clear tooltip on empty
+ };
+
+ SingleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ SingleSelection.prototype.selectionContainer = function () {
+ return $('<span></span>');
+ };
+
+ SingleSelection.prototype.update = function (data) {
+ if (data.length === 0) {
+ this.clear();
+ return;
+ }
+
+ var selection = data[0];
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ var formatted = this.display(selection, $rendered);
+
+ $rendered.empty().append(formatted);
+
+ var title = selection.title || selection.text;
+
+ if (title) {
+ $rendered.attr('title', title);
+ } else {
+ $rendered.removeAttr('title');
+ }
+ };
+
+ return SingleSelection;
+});
+
+S2.define('select2/selection/multiple',[
+ 'jquery',
+ './base',
+ '../utils'
+], function ($, BaseSelection, Utils) {
+ function MultipleSelection ($element, options) {
+ MultipleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(MultipleSelection, BaseSelection);
+
+ MultipleSelection.prototype.render = function () {
+ var $selection = MultipleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--multiple');
+
+ $selection.html(
+ '<ul class="select2-selection__rendered"></ul>'
+ );
+
+ return $selection;
+ };
+
+ MultipleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ MultipleSelection.__super__.bind.apply(this, arguments);
+
+ this.$selection.on('click', function (evt) {
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on(
+ 'click',
+ '.select2-selection__choice__remove',
+ function (evt) {
+ // Ignore the event if it is disabled
+ if (self.options.get('disabled')) {
+ return;
+ }
+
+ var $remove = $(this);
+ var $selection = $remove.parent();
+
+ var data = Utils.GetData($selection[0], 'data');
+
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ }
+ );
+ };
+
+ MultipleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title');
+ };
+
+ MultipleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ MultipleSelection.prototype.selectionContainer = function () {
+ var $container = $(
+ '<li class="select2-selection__choice">' +
+ '<span class="select2-selection__choice__remove" role="presentation">' +
+ '&times;' +
+ '</span>' +
+ '</li>'
+ );
+
+ return $container;
+ };
+
+ MultipleSelection.prototype.update = function (data) {
+ this.clear();
+
+ if (data.length === 0) {
+ return;
+ }
+
+ var $selections = [];
+
+ for (var d = 0; d < data.length; d++) {
+ var selection = data[d];
+
+ var $selection = this.selectionContainer();
+ var formatted = this.display(selection, $selection);
+
+ $selection.append(formatted);
+
+ var title = selection.title || selection.text;
+
+ if (title) {
+ $selection.attr('title', title);
+ }
+
+ Utils.StoreData($selection[0], 'data', selection);
+
+ $selections.push($selection);
+ }
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+
+ Utils.appendMany($rendered, $selections);
+ };
+
+ return MultipleSelection;
+});
+
+S2.define('select2/selection/placeholder',[
+ '../utils'
+], function (Utils) {
+ function Placeholder (decorated, $element, options) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options);
+ }
+
+ Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
+ var $placeholder = this.selectionContainer();
+
+ $placeholder.html(this.display(placeholder));
+ $placeholder.addClass('select2-selection__placeholder')
+ .removeClass('select2-selection__choice');
+
+ return $placeholder;
+ };
+
+ Placeholder.prototype.update = function (decorated, data) {
+ var singlePlaceholder = (
+ data.length == 1 && data[0].id != this.placeholder.id
+ );
+ var multipleSelections = data.length > 1;
+
+ if (multipleSelections || singlePlaceholder) {
+ return decorated.call(this, data);
+ }
+
+ this.clear();
+
+ var $placeholder = this.createPlaceholder(this.placeholder);
+
+ this.$selection.find('.select2-selection__rendered').append($placeholder);
+ };
+
+ return Placeholder;
+});
+
+S2.define('select2/selection/allowClear',[
+ 'jquery',
+ '../keys',
+ '../utils'
+], function ($, KEYS, Utils) {
+ function AllowClear () { }
+
+ AllowClear.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ if (this.placeholder == null) {
+ if (this.options.get('debug') && window.console && console.error) {
+ console.error(
+ 'Select2: The `allowClear` option should be used in combination ' +
+ 'with the `placeholder` option.'
+ );
+ }
+ }
+
+ this.$selection.on('mousedown', '.select2-selection__clear',
+ function (evt) {
+ self._handleClear(evt);
+ });
+
+ container.on('keypress', function (evt) {
+ self._handleKeyboardClear(evt, container);
+ });
+ };
+
+ AllowClear.prototype._handleClear = function (_, evt) {
+ // Ignore the event if it is disabled
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ var $clear = this.$selection.find('.select2-selection__clear');
+
+ // Ignore the event if nothing has been selected
+ if ($clear.length === 0) {
+ return;
+ }
+
+ evt.stopPropagation();
+
+ var data = Utils.GetData($clear[0], 'data');
+
+ var previousVal = this.$element.val();
+ this.$element.val(this.placeholder.id);
+
+ var unselectData = {
+ data: data
+ };
+ this.trigger('clear', unselectData);
+ if (unselectData.prevented) {
+ this.$element.val(previousVal);
+ return;
+ }
+
+ for (var d = 0; d < data.length; d++) {
+ unselectData = {
+ data: data[d]
+ };
+
+ // Trigger the `unselect` event, so people can prevent it from being
+ // cleared.
+ this.trigger('unselect', unselectData);
+
+ // If the event was prevented, don't clear it out.
+ if (unselectData.prevented) {
+ this.$element.val(previousVal);
+ return;
+ }
+ }
+
+ this.$element.trigger('change');
+
+ this.trigger('toggle', {});
+ };
+
+ AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
+ if (container.isOpen()) {
+ return;
+ }
+
+ if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
+ this._handleClear(evt);
+ }
+ };
+
+ AllowClear.prototype.update = function (decorated, data) {
+ decorated.call(this, data);
+
+ if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
+ data.length === 0) {
+ return;
+ }
+
+ var removeAll = this.options.get('translations').get('removeAllItems');
+
+ var $remove = $(
+ '<span class="select2-selection__clear" title="' + removeAll() +'">' +
+ '&times;' +
+ '</span>'
+ );
+ Utils.StoreData($remove[0], 'data', data);
+
+ this.$selection.find('.select2-selection__rendered').prepend($remove);
+ };
+
+ return AllowClear;
+});
+
+S2.define('select2/selection/search',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function Search (decorated, $element, options) {
+ decorated.call(this, $element, options);
+ }
+
+ Search.prototype.render = function (decorated) {
+ var $search = $(
+ '<li class="select2-search select2-search--inline">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
+ '</li>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ var $rendered = decorated.call(this);
+
+ this._transferTabIndex();
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self.$search.attr('aria-controls', resultsId);
+ self.$search.trigger('focus');
+ });
+
+ container.on('close', function () {
+ self.$search.val('');
+ self.$search.removeAttr('aria-controls');
+ self.$search.removeAttr('aria-activedescendant');
+ self.$search.trigger('focus');
+ });
+
+ container.on('enable', function () {
+ self.$search.prop('disabled', false);
+
+ self._transferTabIndex();
+ });
+
+ container.on('disable', function () {
+ self.$search.prop('disabled', true);
+ });
+
+ container.on('focus', function (evt) {
+ self.$search.trigger('focus');
+ });
+
+ container.on('results:focus', function (params) {
+ if (params.data._resultId) {
+ self.$search.attr('aria-activedescendant', params.data._resultId);
+ } else {
+ self.$search.removeAttr('aria-activedescendant');
+ }
+ });
+
+ this.$selection.on('focusin', '.select2-search--inline', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('focusout', '.select2-search--inline', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', '.select2-search--inline', function (evt) {
+ evt.stopPropagation();
+
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+
+ var key = evt.which;
+
+ if (key === KEYS.BACKSPACE && self.$search.val() === '') {
+ var $previousChoice = self.$searchContainer
+ .prev('.select2-selection__choice');
+
+ if ($previousChoice.length > 0) {
+ var item = Utils.GetData($previousChoice[0], 'data');
+
+ self.searchRemoveChoice(item);
+
+ evt.preventDefault();
+ }
+ }
+ });
+
+ this.$selection.on('click', '.select2-search--inline', function (evt) {
+ if (self.$search.val()) {
+ evt.stopPropagation();
+ }
+ });
+
+ // Try to detect the IE version should the `documentMode` property that
+ // is stored on the document. This is only implemented in IE and is
+ // slightly cleaner than doing a user agent check.
+ // This property is not available in Edge, but Edge also doesn't have
+ // this bug.
+ var msie = document.documentMode;
+ var disableInputEvents = msie && msie <= 11;
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$selection.on(
+ 'input.searchcheck',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents) {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ // Unbind the duplicated `keyup` event
+ self.$selection.off('keyup.search');
+ }
+ );
+
+ this.$selection.on(
+ 'keyup.search input.search',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents && evt.type === 'input') {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ var key = evt.which;
+
+ // We can freely ignore events from modifier keys
+ if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
+ return;
+ }
+
+ // Tabbing will be handled during the `keydown` phase
+ if (key == KEYS.TAB) {
+ return;
+ }
+
+ self.handleSearch(evt);
+ }
+ );
+ };
+
+ /**
+ * This method will transfer the tabindex attribute from the rendered
+ * selection to the search box. This allows for the search box to be used as
+ * the primary focus instead of the selection container.
+ *
+ * @private
+ */
+ Search.prototype._transferTabIndex = function (decorated) {
+ this.$search.attr('tabindex', this.$selection.attr('tabindex'));
+ this.$selection.attr('tabindex', '-1');
+ };
+
+ Search.prototype.createPlaceholder = function (decorated, placeholder) {
+ this.$search.attr('placeholder', placeholder.text);
+ };
+
+ Search.prototype.update = function (decorated, data) {
+ var searchHadFocus = this.$search[0] == document.activeElement;
+
+ this.$search.attr('placeholder', '');
+
+ decorated.call(this, data);
+
+ this.$selection.find('.select2-selection__rendered')
+ .append(this.$searchContainer);
+
+ this.resizeSearch();
+ if (searchHadFocus) {
+ this.$search.trigger('focus');
+ }
+ };
+
+ Search.prototype.handleSearch = function () {
+ this.resizeSearch();
+
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.searchRemoveChoice = function (decorated, item) {
+ this.trigger('unselect', {
+ data: item
+ });
+
+ this.$search.val(item.text);
+ this.handleSearch();
+ };
+
+ Search.prototype.resizeSearch = function () {
+ this.$search.css('width', '25px');
+
+ var width = '';
+
+ if (this.$search.attr('placeholder') !== '') {
+ width = this.$selection.find('.select2-selection__rendered').width();
+ } else {
+ var minimumWidth = this.$search.val().length + 1;
+
+ width = (minimumWidth * 0.75) + 'em';
+ }
+
+ this.$search.css('width', width);
+ };
+
+ return Search;
+});
+
+S2.define('select2/selection/eventRelay',[
+ 'jquery'
+], function ($) {
+ function EventRelay () { }
+
+ EventRelay.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+ var relayEvents = [
+ 'open', 'opening',
+ 'close', 'closing',
+ 'select', 'selecting',
+ 'unselect', 'unselecting',
+ 'clear', 'clearing'
+ ];
+
+ var preventableEvents = [
+ 'opening', 'closing', 'selecting', 'unselecting', 'clearing'
+ ];
+
+ decorated.call(this, container, $container);
+
+ container.on('*', function (name, params) {
+ // Ignore events that should not be relayed
+ if ($.inArray(name, relayEvents) === -1) {
+ return;
+ }
+
+ // The parameters should always be an object
+ params = params || {};
+
+ // Generate the jQuery event for the Select2 event
+ var evt = $.Event('select2:' + name, {
+ params: params
+ });
+
+ self.$element.trigger(evt);
+
+ // Only handle preventable events if it was one
+ if ($.inArray(name, preventableEvents) === -1) {
+ return;
+ }
+
+ params.prevented = evt.isDefaultPrevented();
+ });
+ };
+
+ return EventRelay;
+});
+
+S2.define('select2/translation',[
+ 'jquery',
+ 'require'
+], function ($, require) {
+ function Translation (dict) {
+ this.dict = dict || {};
+ }
+
+ Translation.prototype.all = function () {
+ return this.dict;
+ };
+
+ Translation.prototype.get = function (key) {
+ return this.dict[key];
+ };
+
+ Translation.prototype.extend = function (translation) {
+ this.dict = $.extend({}, translation.all(), this.dict);
+ };
+
+ // Static functions
+
+ Translation._cache = {};
+
+ Translation.loadPath = function (path) {
+ if (!(path in Translation._cache)) {
+ var translations = require(path);
+
+ Translation._cache[path] = translations;
+ }
+
+ return new Translation(Translation._cache[path]);
+ };
+
+ return Translation;
+});
+
+S2.define('select2/diacritics',[
+
+], function () {
+ var 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',
+ '\u0152': 'OE',
+ '\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',
+ '\u0153': 'oe',
+ '\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',
+ '\u0386': '\u0391',
+ '\u0388': '\u0395',
+ '\u0389': '\u0397',
+ '\u038A': '\u0399',
+ '\u03AA': '\u0399',
+ '\u038C': '\u039F',
+ '\u038E': '\u03A5',
+ '\u03AB': '\u03A5',
+ '\u038F': '\u03A9',
+ '\u03AC': '\u03B1',
+ '\u03AD': '\u03B5',
+ '\u03AE': '\u03B7',
+ '\u03AF': '\u03B9',
+ '\u03CA': '\u03B9',
+ '\u0390': '\u03B9',
+ '\u03CC': '\u03BF',
+ '\u03CD': '\u03C5',
+ '\u03CB': '\u03C5',
+ '\u03B0': '\u03C5',
+ '\u03CE': '\u03C9',
+ '\u03C2': '\u03C3',
+ '\u2019': '\''
+ };
+
+ return diacritics;
+});
+
+S2.define('select2/data/base',[
+ '../utils'
+], function (Utils) {
+ function BaseAdapter ($element, options) {
+ BaseAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseAdapter, Utils.Observable);
+
+ BaseAdapter.prototype.current = function (callback) {
+ throw new Error('The `current` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.query = function (params, callback) {
+ throw new Error('The `query` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.bind = function (container, $container) {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.destroy = function () {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.generateResultId = function (container, data) {
+ var id = container.id + '-result-';
+
+ id += Utils.generateChars(4);
+
+ if (data.id != null) {
+ id += '-' + data.id.toString();
+ } else {
+ id += '-' + Utils.generateChars(4);
+ }
+ return id;
+ };
+
+ return BaseAdapter;
+});
+
+S2.define('select2/data/select',[
+ './base',
+ '../utils',
+ 'jquery'
+], function (BaseAdapter, Utils, $) {
+ function SelectAdapter ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ SelectAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(SelectAdapter, BaseAdapter);
+
+ SelectAdapter.prototype.current = function (callback) {
+ var data = [];
+ var self = this;
+
+ this.$element.find(':selected').each(function () {
+ var $option = $(this);
+
+ var option = self.item($option);
+
+ data.push(option);
+ });
+
+ callback(data);
+ };
+
+ SelectAdapter.prototype.select = function (data) {
+ var self = this;
+
+ data.selected = true;
+
+ // If data.element is a DOM node, use it instead
+ if ($(data.element).is('option')) {
+ data.element.selected = true;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ if (this.$element.prop('multiple')) {
+ this.current(function (currentData) {
+ var val = [];
+
+ data = [data];
+ data.push.apply(data, currentData);
+
+ for (var d = 0; d < data.length; d++) {
+ var id = data[d].id;
+
+ if ($.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+ self.$element.trigger('change');
+ });
+ } else {
+ var val = data.id;
+
+ this.$element.val(val);
+ this.$element.trigger('change');
+ }
+ };
+
+ SelectAdapter.prototype.unselect = function (data) {
+ var self = this;
+
+ if (!this.$element.prop('multiple')) {
+ return;
+ }
+
+ data.selected = false;
+
+ if ($(data.element).is('option')) {
+ data.element.selected = false;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ this.current(function (currentData) {
+ var val = [];
+
+ for (var d = 0; d < currentData.length; d++) {
+ var id = currentData[d].id;
+
+ if (id !== data.id && $.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+
+ self.$element.trigger('change');
+ });
+ };
+
+ SelectAdapter.prototype.bind = function (container, $container) {
+ var self = this;
+
+ this.container = container;
+
+ container.on('select', function (params) {
+ self.select(params.data);
+ });
+
+ container.on('unselect', function (params) {
+ self.unselect(params.data);
+ });
+ };
+
+ SelectAdapter.prototype.destroy = function () {
+ // Remove anything added to child elements
+ this.$element.find('*').each(function () {
+ // Remove any custom data set by Select2
+ Utils.RemoveData(this);
+ });
+ };
+
+ SelectAdapter.prototype.query = function (params, callback) {
+ var data = [];
+ var self = this;
+
+ var $options = this.$element.children();
+
+ $options.each(function () {
+ var $option = $(this);
+
+ if (!$option.is('option') && !$option.is('optgroup')) {
+ return;
+ }
+
+ var option = self.item($option);
+
+ var matches = self.matches(params, option);
+
+ if (matches !== null) {
+ data.push(matches);
+ }
+ });
+
+ callback({
+ results: data
+ });
+ };
+
+ SelectAdapter.prototype.addOptions = function ($options) {
+ Utils.appendMany(this.$element, $options);
+ };
+
+ SelectAdapter.prototype.option = function (data) {
+ var option;
+
+ if (data.children) {
+ option = document.createElement('optgroup');
+ option.label = data.text;
+ } else {
+ option = document.createElement('option');
+
+ if (option.textContent !== undefined) {
+ option.textContent = data.text;
+ } else {
+ option.innerText = data.text;
+ }
+ }
+
+ if (data.id !== undefined) {
+ option.value = data.id;
+ }
+
+ if (data.disabled) {
+ option.disabled = true;
+ }
+
+ if (data.selected) {
+ option.selected = true;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ var $option = $(option);
+
+ var normalizedData = this._normalizeItem(data);
+ normalizedData.element = option;
+
+ // Override the option's data with the combined data
+ Utils.StoreData(option, 'data', normalizedData);
+
+ return $option;
+ };
+
+ SelectAdapter.prototype.item = function ($option) {
+ var data = {};
+
+ data = Utils.GetData($option[0], 'data');
+
+ if (data != null) {
+ return data;
+ }
+
+ if ($option.is('option')) {
+ data = {
+ id: $option.val(),
+ text: $option.text(),
+ disabled: $option.prop('disabled'),
+ selected: $option.prop('selected'),
+ title: $option.prop('title')
+ };
+ } else if ($option.is('optgroup')) {
+ data = {
+ text: $option.prop('label'),
+ children: [],
+ title: $option.prop('title')
+ };
+
+ var $children = $option.children('option');
+ var children = [];
+
+ for (var c = 0; c < $children.length; c++) {
+ var $child = $($children[c]);
+
+ var child = this.item($child);
+
+ children.push(child);
+ }
+
+ data.children = children;
+ }
+
+ data = this._normalizeItem(data);
+ data.element = $option[0];
+
+ Utils.StoreData($option[0], 'data', data);
+
+ return data;
+ };
+
+ SelectAdapter.prototype._normalizeItem = function (item) {
+ if (item !== Object(item)) {
+ item = {
+ id: item,
+ text: item
+ };
+ }
+
+ item = $.extend({}, {
+ text: ''
+ }, item);
+
+ var defaults = {
+ selected: false,
+ disabled: false
+ };
+
+ if (item.id != null) {
+ item.id = item.id.toString();
+ }
+
+ if (item.text != null) {
+ item.text = item.text.toString();
+ }
+
+ if (item._resultId == null && item.id && this.container != null) {
+ item._resultId = this.generateResultId(this.container, item);
+ }
+
+ return $.extend({}, defaults, item);
+ };
+
+ SelectAdapter.prototype.matches = function (params, data) {
+ var matcher = this.options.get('matcher');
+
+ return matcher(params, data);
+ };
+
+ return SelectAdapter;
+});
+
+S2.define('select2/data/array',[
+ './select',
+ '../utils',
+ 'jquery'
+], function (SelectAdapter, Utils, $) {
+ function ArrayAdapter ($element, options) {
+ this._dataToConvert = options.get('data') || [];
+
+ ArrayAdapter.__super__.constructor.call(this, $element, options);
+ }
+
+ Utils.Extend(ArrayAdapter, SelectAdapter);
+
+ ArrayAdapter.prototype.bind = function (container, $container) {
+ ArrayAdapter.__super__.bind.call(this, container, $container);
+
+ this.addOptions(this.convertToOptions(this._dataToConvert));
+ };
+
+ ArrayAdapter.prototype.select = function (data) {
+ var $option = this.$element.find('option').filter(function (i, elm) {
+ return elm.value == data.id.toString();
+ });
+
+ if ($option.length === 0) {
+ $option = this.option(data);
+
+ this.addOptions($option);
+ }
+
+ ArrayAdapter.__super__.select.call(this, data);
+ };
+
+ ArrayAdapter.prototype.convertToOptions = function (data) {
+ var self = this;
+
+ var $existing = this.$element.find('option');
+ var existingIds = $existing.map(function () {
+ return self.item($(this)).id;
+ }).get();
+
+ var $options = [];
+
+ // Filter out all items except for the one passed in the argument
+ function onlyItem (item) {
+ return function () {
+ return $(this).val() == item.id;
+ };
+ }
+
+ for (var d = 0; d < data.length; d++) {
+ var item = this._normalizeItem(data[d]);
+
+ // Skip items which were pre-loaded, only merge the data
+ if ($.inArray(item.id, existingIds) >= 0) {
+ var $existingOption = $existing.filter(onlyItem(item));
+
+ var existingData = this.item($existingOption);
+ var newData = $.extend(true, {}, item, existingData);
+
+ var $newOption = this.option(newData);
+
+ $existingOption.replaceWith($newOption);
+
+ continue;
+ }
+
+ var $option = this.option(item);
+
+ if (item.children) {
+ var $children = this.convertToOptions(item.children);
+
+ Utils.appendMany($option, $children);
+ }
+
+ $options.push($option);
+ }
+
+ return $options;
+ };
+
+ return ArrayAdapter;
+});
+
+S2.define('select2/data/ajax',[
+ './array',
+ '../utils',
+ 'jquery'
+], function (ArrayAdapter, Utils, $) {
+ function AjaxAdapter ($element, options) {
+ this.ajaxOptions = this._applyDefaults(options.get('ajax'));
+
+ if (this.ajaxOptions.processResults != null) {
+ this.processResults = this.ajaxOptions.processResults;
+ }
+
+ AjaxAdapter.__super__.constructor.call(this, $element, options);
+ }
+
+ Utils.Extend(AjaxAdapter, ArrayAdapter);
+
+ AjaxAdapter.prototype._applyDefaults = function (options) {
+ var defaults = {
+ data: function (params) {
+ return $.extend({}, params, {
+ q: params.term
+ });
+ },
+ transport: function (params, success, failure) {
+ var $request = $.ajax(params);
+
+ $request.then(success);
+ $request.fail(failure);
+
+ return $request;
+ }
+ };
+
+ return $.extend({}, defaults, options, true);
+ };
+
+ AjaxAdapter.prototype.processResults = function (results) {
+ return results;
+ };
+
+ AjaxAdapter.prototype.query = function (params, callback) {
+ var matches = [];
+ var self = this;
+
+ if (this._request != null) {
+ // JSONP requests cannot always be aborted
+ if ($.isFunction(this._request.abort)) {
+ this._request.abort();
+ }
+
+ this._request = null;
+ }
+
+ var options = $.extend({
+ type: 'GET'
+ }, this.ajaxOptions);
+
+ if (typeof options.url === 'function') {
+ options.url = options.url.call(this.$element, params);
+ }
+
+ if (typeof options.data === 'function') {
+ options.data = options.data.call(this.$element, params);
+ }
+
+ function request () {
+ var $request = options.transport(options, function (data) {
+ var results = self.processResults(data, params);
+
+ if (self.options.get('debug') && window.console && console.error) {
+ // Check to make sure that the response included a `results` key.
+ if (!results || !results.results || !$.isArray(results.results)) {
+ console.error(
+ 'Select2: The AJAX results did not return an array in the ' +
+ '`results` key of the response.'
+ );
+ }
+ }
+
+ callback(results);
+ }, function () {
+ // Attempt to detect if a request was aborted
+ // Only works if the transport exposes a status property
+ if ('status' in $request &&
+ ($request.status === 0 || $request.status === '0')) {
+ return;
+ }
+
+ self.trigger('results:message', {
+ message: 'errorLoading'
+ });
+ });
+
+ self._request = $request;
+ }
+
+ if (this.ajaxOptions.delay && params.term != null) {
+ if (this._queryTimeout) {
+ window.clearTimeout(this._queryTimeout);
+ }
+
+ this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
+ } else {
+ request();
+ }
+ };
+
+ return AjaxAdapter;
+});
+
+S2.define('select2/data/tags',[
+ 'jquery'
+], function ($) {
+ function Tags (decorated, $element, options) {
+ var tags = options.get('tags');
+
+ var createTag = options.get('createTag');
+
+ if (createTag !== undefined) {
+ this.createTag = createTag;
+ }
+
+ var insertTag = options.get('insertTag');
+
+ if (insertTag !== undefined) {
+ this.insertTag = insertTag;
+ }
+
+ decorated.call(this, $element, options);
+
+ if ($.isArray(tags)) {
+ for (var t = 0; t < tags.length; t++) {
+ var tag = tags[t];
+ var item = this._normalizeItem(tag);
+
+ var $option = this.option(item);
+
+ this.$element.append($option);
+ }
+ }
+ }
+
+ Tags.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ this._removeOldTags();
+
+ if (params.term == null || params.page != null) {
+ decorated.call(this, params, callback);
+ return;
+ }
+
+ function wrapper (obj, child) {
+ var data = obj.results;
+
+ for (var i = 0; i < data.length; i++) {
+ var option = data[i];
+
+ var checkChildren = (
+ option.children != null &&
+ !wrapper({
+ results: option.children
+ }, true)
+ );
+
+ var optionText = (option.text || '').toUpperCase();
+ var paramsTerm = (params.term || '').toUpperCase();
+
+ var checkText = optionText === paramsTerm;
+
+ if (checkText || checkChildren) {
+ if (child) {
+ return false;
+ }
+
+ obj.data = data;
+ callback(obj);
+
+ return;
+ }
+ }
+
+ if (child) {
+ return true;
+ }
+
+ var tag = self.createTag(params);
+
+ if (tag != null) {
+ var $option = self.option(tag);
+ $option.attr('data-select2-tag', true);
+
+ self.addOptions([$option]);
+
+ self.insertTag(data, tag);
+ }
+
+ obj.results = data;
+
+ callback(obj);
+ }
+
+ decorated.call(this, params, wrapper);
+ };
+
+ Tags.prototype.createTag = function (decorated, params) {
+ var term = $.trim(params.term);
+
+ if (term === '') {
+ return null;
+ }
+
+ return {
+ id: term,
+ text: term
+ };
+ };
+
+ Tags.prototype.insertTag = function (_, data, tag) {
+ data.unshift(tag);
+ };
+
+ Tags.prototype._removeOldTags = function (_) {
+ var $options = this.$element.find('option[data-select2-tag]');
+
+ $options.each(function () {
+ if (this.selected) {
+ return;
+ }
+
+ $(this).remove();
+ });
+ };
+
+ return Tags;
+});
+
+S2.define('select2/data/tokenizer',[
+ 'jquery'
+], function ($) {
+ function Tokenizer (decorated, $element, options) {
+ var tokenizer = options.get('tokenizer');
+
+ if (tokenizer !== undefined) {
+ this.tokenizer = tokenizer;
+ }
+
+ decorated.call(this, $element, options);
+ }
+
+ Tokenizer.prototype.bind = function (decorated, container, $container) {
+ decorated.call(this, container, $container);
+
+ this.$search = container.dropdown.$search || container.selection.$search ||
+ $container.find('.select2-search__field');
+ };
+
+ Tokenizer.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ function createAndSelect (data) {
+ // Normalize the data object so we can use it for checks
+ var item = self._normalizeItem(data);
+
+ // Check if the data object already exists as a tag
+ // Select it if it doesn't
+ var $existingOptions = self.$element.find('option').filter(function () {
+ return $(this).val() === item.id;
+ });
+
+ // If an existing option wasn't found for it, create the option
+ if (!$existingOptions.length) {
+ var $option = self.option(item);
+ $option.attr('data-select2-tag', true);
+
+ self._removeOldTags();
+ self.addOptions([$option]);
+ }
+
+ // Select the item, now that we know there is an option for it
+ select(item);
+ }
+
+ function select (data) {
+ self.trigger('select', {
+ data: data
+ });
+ }
+
+ params.term = params.term || '';
+
+ var tokenData = this.tokenizer(params, this.options, createAndSelect);
+
+ if (tokenData.term !== params.term) {
+ // Replace the search term if we have the search box
+ if (this.$search.length) {
+ this.$search.val(tokenData.term);
+ this.$search.trigger('focus');
+ }
+
+ params.term = tokenData.term;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
+ var separators = options.get('tokenSeparators') || [];
+ var term = params.term;
+ var i = 0;
+
+ var createTag = this.createTag || function (params) {
+ return {
+ id: params.term,
+ text: params.term
+ };
+ };
+
+ while (i < term.length) {
+ var termChar = term[i];
+
+ if ($.inArray(termChar, separators) === -1) {
+ i++;
+
+ continue;
+ }
+
+ var part = term.substr(0, i);
+ var partParams = $.extend({}, params, {
+ term: part
+ });
+
+ var data = createTag(partParams);
+
+ if (data == null) {
+ i++;
+ continue;
+ }
+
+ callback(data);
+
+ // Reset the term to not include the tokenized portion
+ term = term.substr(i + 1) || '';
+ i = 0;
+ }
+
+ return {
+ term: term
+ };
+ };
+
+ return Tokenizer;
+});
+
+S2.define('select2/data/minimumInputLength',[
+
+], function () {
+ function MinimumInputLength (decorated, $e, options) {
+ this.minimumInputLength = options.get('minimumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MinimumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (params.term.length < this.minimumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooShort',
+ args: {
+ minimum: this.minimumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MinimumInputLength;
+});
+
+S2.define('select2/data/maximumInputLength',[
+
+], function () {
+ function MaximumInputLength (decorated, $e, options) {
+ this.maximumInputLength = options.get('maximumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (this.maximumInputLength > 0 &&
+ params.term.length > this.maximumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooLong',
+ args: {
+ maximum: this.maximumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MaximumInputLength;
+});
+
+S2.define('select2/data/maximumSelectionLength',[
+
+], function (){
+ function MaximumSelectionLength (decorated, $e, options) {
+ this.maximumSelectionLength = options.get('maximumSelectionLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumSelectionLength.prototype.bind =
+ function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('select', function () {
+ self._checkIfMaximumSelected();
+ });
+ };
+
+ MaximumSelectionLength.prototype.query =
+ function (decorated, params, callback) {
+ var self = this;
+
+ this._checkIfMaximumSelected(function () {
+ decorated.call(self, params, callback);
+ });
+ };
+
+ MaximumSelectionLength.prototype._checkIfMaximumSelected =
+ function (_, successCallback) {
+ var self = this;
+
+ this.current(function (currentData) {
+ var count = currentData != null ? currentData.length : 0;
+ if (self.maximumSelectionLength > 0 &&
+ count >= self.maximumSelectionLength) {
+ self.trigger('results:message', {
+ message: 'maximumSelected',
+ args: {
+ maximum: self.maximumSelectionLength
+ }
+ });
+ return;
+ }
+
+ if (successCallback) {
+ successCallback();
+ }
+ });
+ };
+
+ return MaximumSelectionLength;
+});
+
+S2.define('select2/dropdown',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Dropdown ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ Dropdown.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Dropdown, Utils.Observable);
+
+ Dropdown.prototype.render = function () {
+ var $dropdown = $(
+ '<span class="select2-dropdown">' +
+ '<span class="select2-results"></span>' +
+ '</span>'
+ );
+
+ $dropdown.attr('dir', this.options.get('dir'));
+
+ this.$dropdown = $dropdown;
+
+ return $dropdown;
+ };
+
+ Dropdown.prototype.bind = function () {
+ // Should be implemented in subclasses
+ };
+
+ Dropdown.prototype.position = function ($dropdown, $container) {
+ // Should be implemented in subclasses
+ };
+
+ Dropdown.prototype.destroy = function () {
+ // Remove the dropdown from the DOM
+ this.$dropdown.remove();
+ };
+
+ return Dropdown;
+});
+
+S2.define('select2/dropdown/search',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function Search () { }
+
+ Search.prototype.render = function (decorated) {
+ var $rendered = decorated.call(this);
+
+ var $search = $(
+ '<span class="select2-search select2-search--dropdown">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
+ '</span>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ $rendered.prepend($search);
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ decorated.call(this, container, $container);
+
+ this.$search.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+ });
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$search.on('input', function (evt) {
+ // Unbind the duplicated `keyup` event
+ $(this).off('keyup');
+ });
+
+ this.$search.on('keyup input', function (evt) {
+ self.handleSearch(evt);
+ });
+
+ container.on('open', function () {
+ self.$search.attr('tabindex', 0);
+ self.$search.attr('aria-controls', resultsId);
+
+ self.$search.trigger('focus');
+
+ window.setTimeout(function () {
+ self.$search.trigger('focus');
+ }, 0);
+ });
+
+ container.on('close', function () {
+ self.$search.attr('tabindex', -1);
+ self.$search.removeAttr('aria-controls');
+ self.$search.removeAttr('aria-activedescendant');
+
+ self.$search.val('');
+ self.$search.trigger('blur');
+ });
+
+ container.on('focus', function () {
+ if (!container.isOpen()) {
+ self.$search.trigger('focus');
+ }
+ });
+
+ container.on('results:all', function (params) {
+ if (params.query.term == null || params.query.term === '') {
+ var showSearch = self.showSearch(params);
+
+ if (showSearch) {
+ self.$searchContainer.removeClass('select2-search--hide');
+ } else {
+ self.$searchContainer.addClass('select2-search--hide');
+ }
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ if (params.data._resultId) {
+ self.$search.attr('aria-activedescendant', params.data._resultId);
+ } else {
+ self.$search.removeAttr('aria-activedescendant');
+ }
+ });
+ };
+
+ Search.prototype.handleSearch = function (evt) {
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.showSearch = function (_, params) {
+ return true;
+ };
+
+ return Search;
+});
+
+S2.define('select2/dropdown/hidePlaceholder',[
+
+], function () {
+ function HidePlaceholder (decorated, $element, options, dataAdapter) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ HidePlaceholder.prototype.append = function (decorated, data) {
+ data.results = this.removePlaceholder(data.results);
+
+ decorated.call(this, data);
+ };
+
+ HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ HidePlaceholder.prototype.removePlaceholder = function (_, data) {
+ var modifiedData = data.slice(0);
+
+ for (var d = data.length - 1; d >= 0; d--) {
+ var item = data[d];
+
+ if (this.placeholder.id === item.id) {
+ modifiedData.splice(d, 1);
+ }
+ }
+
+ return modifiedData;
+ };
+
+ return HidePlaceholder;
+});
+
+S2.define('select2/dropdown/infiniteScroll',[
+ 'jquery'
+], function ($) {
+ function InfiniteScroll (decorated, $element, options, dataAdapter) {
+ this.lastParams = {};
+
+ decorated.call(this, $element, options, dataAdapter);
+
+ this.$loadingMore = this.createLoadingMore();
+ this.loading = false;
+ }
+
+ InfiniteScroll.prototype.append = function (decorated, data) {
+ this.$loadingMore.remove();
+ this.loading = false;
+
+ decorated.call(this, data);
+
+ if (this.showLoadingMore(data)) {
+ this.$results.append(this.$loadingMore);
+ this.loadMoreIfNeeded();
+ }
+ };
+
+ InfiniteScroll.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('query', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ container.on('query:append', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
+ };
+
+ InfiniteScroll.prototype.loadMoreIfNeeded = function () {
+ var isLoadMoreVisible = $.contains(
+ document.documentElement,
+ this.$loadingMore[0]
+ );
+
+ if (this.loading || !isLoadMoreVisible) {
+ return;
+ }
+
+ var currentOffset = this.$results.offset().top +
+ this.$results.outerHeight(false);
+ var loadingMoreOffset = this.$loadingMore.offset().top +
+ this.$loadingMore.outerHeight(false);
+
+ if (currentOffset + 50 >= loadingMoreOffset) {
+ this.loadMore();
+ }
+ };
+
+ InfiniteScroll.prototype.loadMore = function () {
+ this.loading = true;
+
+ var params = $.extend({}, {page: 1}, this.lastParams);
+
+ params.page++;
+
+ this.trigger('query:append', params);
+ };
+
+ InfiniteScroll.prototype.showLoadingMore = function (_, data) {
+ return data.pagination && data.pagination.more;
+ };
+
+ InfiniteScroll.prototype.createLoadingMore = function () {
+ var $option = $(
+ '<li ' +
+ 'class="select2-results__option select2-results__option--load-more"' +
+ 'role="option" aria-disabled="true"></li>'
+ );
+
+ var message = this.options.get('translations').get('loadingMore');
+
+ $option.html(message(this.lastParams));
+
+ return $option;
+ };
+
+ return InfiniteScroll;
+});
+
+S2.define('select2/dropdown/attachBody',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function AttachBody (decorated, $element, options) {
+ this.$dropdownParent = $(options.get('dropdownParent') || document.body);
+
+ decorated.call(this, $element, options);
+ }
+
+ AttachBody.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self._showDropdown();
+ self._attachPositioningHandler(container);
+
+ // Must bind after the results handlers to ensure correct sizing
+ self._bindContainerResultHandlers(container);
+ });
+
+ container.on('close', function () {
+ self._hideDropdown();
+ self._detachPositioningHandler(container);
+ });
+
+ this.$dropdownContainer.on('mousedown', function (evt) {
+ evt.stopPropagation();
+ });
+ };
+
+ AttachBody.prototype.destroy = function (decorated) {
+ decorated.call(this);
+
+ this.$dropdownContainer.remove();
+ };
+
+ AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+ // Clone all of the container classes
+ $dropdown.attr('class', $container.attr('class'));
+
+ $dropdown.removeClass('select2');
+ $dropdown.addClass('select2-container--open');
+
+ $dropdown.css({
+ position: 'absolute',
+ top: -999999
+ });
+
+ this.$container = $container;
+ };
+
+ AttachBody.prototype.render = function (decorated) {
+ var $container = $('<span></span>');
+
+ var $dropdown = decorated.call(this);
+ $container.append($dropdown);
+
+ this.$dropdownContainer = $container;
+
+ return $container;
+ };
+
+ AttachBody.prototype._hideDropdown = function (decorated) {
+ this.$dropdownContainer.detach();
+ };
+
+ AttachBody.prototype._bindContainerResultHandlers =
+ function (decorated, container) {
+
+ // These should only be bound once
+ if (this._containerResultsHandlersBound) {
+ return;
+ }
+
+ var self = this;
+
+ container.on('results:all', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('results:append', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('results:message', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('select', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('unselect', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ this._containerResultsHandlersBound = true;
+ };
+
+ AttachBody.prototype._attachPositioningHandler =
+ function (decorated, container) {
+ var self = this;
+
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.each(function () {
+ Utils.StoreData(this, 'select2-scroll-position', {
+ x: $(this).scrollLeft(),
+ y: $(this).scrollTop()
+ });
+ });
+
+ $watchers.on(scrollEvent, function (ev) {
+ var position = Utils.GetData(this, 'select2-scroll-position');
+ $(this).scrollTop(position.y);
+ });
+
+ $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
+ function (e) {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+ };
+
+ AttachBody.prototype._detachPositioningHandler =
+ function (decorated, container) {
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.off(scrollEvent);
+
+ $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
+ };
+
+ AttachBody.prototype._positionDropdown = function () {
+ var $window = $(window);
+
+ var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
+ var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
+
+ var newDirection = null;
+
+ var offset = this.$container.offset();
+
+ offset.bottom = offset.top + this.$container.outerHeight(false);
+
+ var container = {
+ height: this.$container.outerHeight(false)
+ };
+
+ container.top = offset.top;
+ container.bottom = offset.top + container.height;
+
+ var dropdown = {
+ height: this.$dropdown.outerHeight(false)
+ };
+
+ var viewport = {
+ top: $window.scrollTop(),
+ bottom: $window.scrollTop() + $window.height()
+ };
+
+ var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
+ var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
+
+ var css = {
+ left: offset.left,
+ top: container.bottom
+ };
+
+ // Determine what the parent element is to use for calculating the offset
+ var $offsetParent = this.$dropdownParent;
+
+ // For statically positioned elements, we need to get the element
+ // that is determining the offset
+ if ($offsetParent.css('position') === 'static') {
+ $offsetParent = $offsetParent.offsetParent();
+ }
+
+ var parentOffset = {
+ top: 0,
+ left: 0
+ };
+
+ if ($.contains(document.body, $offsetParent[0])) {
+ parentOffset = $offsetParent.offset();
+ }
+
+ css.top -= parentOffset.top;
+ css.left -= parentOffset.left;
+
+ if (!isCurrentlyAbove && !isCurrentlyBelow) {
+ newDirection = 'below';
+ }
+
+ if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
+ newDirection = 'above';
+ } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
+ newDirection = 'below';
+ }
+
+ if (newDirection == 'above' ||
+ (isCurrentlyAbove && newDirection !== 'below')) {
+ css.top = container.top - parentOffset.top - dropdown.height;
+ }
+
+ if (newDirection != null) {
+ this.$dropdown
+ .removeClass('select2-dropdown--below select2-dropdown--above')
+ .addClass('select2-dropdown--' + newDirection);
+ this.$container
+ .removeClass('select2-container--below select2-container--above')
+ .addClass('select2-container--' + newDirection);
+ }
+
+ this.$dropdownContainer.css(css);
+ };
+
+ AttachBody.prototype._resizeDropdown = function () {
+ var css = {
+ width: this.$container.outerWidth(false) + 'px'
+ };
+
+ if (this.options.get('dropdownAutoWidth')) {
+ css.minWidth = css.width;
+ css.position = 'relative';
+ css.width = 'auto';
+ }
+
+ this.$dropdown.css(css);
+ };
+
+ AttachBody.prototype._showDropdown = function (decorated) {
+ this.$dropdownContainer.appendTo(this.$dropdownParent);
+
+ this._positionDropdown();
+ this._resizeDropdown();
+ };
+
+ return AttachBody;
+});
+
+S2.define('select2/dropdown/minimumResultsForSearch',[
+
+], function () {
+ function countResults (data) {
+ var count = 0;
+
+ for (var d = 0; d < data.length; d++) {
+ var item = data[d];
+
+ if (item.children) {
+ count += countResults(item.children);
+ } else {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
+ this.minimumResultsForSearch = options.get('minimumResultsForSearch');
+
+ if (this.minimumResultsForSearch < 0) {
+ this.minimumResultsForSearch = Infinity;
+ }
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
+ if (countResults(params.data.results) < this.minimumResultsForSearch) {
+ return false;
+ }
+
+ return decorated.call(this, params);
+ };
+
+ return MinimumResultsForSearch;
+});
+
+S2.define('select2/dropdown/selectOnClose',[
+ '../utils'
+], function (Utils) {
+ function SelectOnClose () { }
+
+ SelectOnClose.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('close', function (params) {
+ self._handleSelectOnClose(params);
+ });
+ };
+
+ SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
+ if (params && params.originalSelect2Event != null) {
+ var event = params.originalSelect2Event;
+
+ // Don't select an item if the close event was triggered from a select or
+ // unselect event
+ if (event._type === 'select' || event._type === 'unselect') {
+ return;
+ }
+ }
+
+ var $highlightedResults = this.getHighlightedResults();
+
+ // Only select highlighted results
+ if ($highlightedResults.length < 1) {
+ return;
+ }
+
+ var data = Utils.GetData($highlightedResults[0], 'data');
+
+ // Don't re-select already selected resulte
+ if (
+ (data.element != null && data.element.selected) ||
+ (data.element == null && data.selected)
+ ) {
+ return;
+ }
+
+ this.trigger('select', {
+ data: data
+ });
+ };
+
+ return SelectOnClose;
+});
+
+S2.define('select2/dropdown/closeOnSelect',[
+
+], function () {
+ function CloseOnSelect () { }
+
+ CloseOnSelect.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('select', function (evt) {
+ self._selectTriggered(evt);
+ });
+
+ container.on('unselect', function (evt) {
+ self._selectTriggered(evt);
+ });
+ };
+
+ CloseOnSelect.prototype._selectTriggered = function (_, evt) {
+ var originalEvent = evt.originalEvent;
+
+ // Don't close if the control key is being held
+ if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
+ return;
+ }
+
+ this.trigger('close', {
+ originalEvent: originalEvent,
+ originalSelect2Event: evt
+ });
+ };
+
+ return CloseOnSelect;
+});
+
+S2.define('select2/i18n/en',[],function () {
+ // English
+ return {
+ errorLoading: function () {
+ return 'The results could not be loaded.';
+ },
+ inputTooLong: function (args) {
+ var overChars = args.input.length - args.maximum;
+
+ var message = 'Please delete ' + overChars + ' character';
+
+ if (overChars != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ inputTooShort: function (args) {
+ var remainingChars = args.minimum - args.input.length;
+
+ var message = 'Please enter ' + remainingChars + ' or more characters';
+
+ return message;
+ },
+ loadingMore: function () {
+ return 'Loading more results…';
+ },
+ maximumSelected: function (args) {
+ var message = 'You can only select ' + args.maximum + ' item';
+
+ if (args.maximum != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ noResults: function () {
+ return 'No results found';
+ },
+ searching: function () {
+ return 'Searching…';
+ },
+ removeAllItems: function () {
+ return 'Remove all items';
+ }
+ };
+});
+
+S2.define('select2/defaults',[
+ 'jquery',
+ 'require',
+
+ './results',
+
+ './selection/single',
+ './selection/multiple',
+ './selection/placeholder',
+ './selection/allowClear',
+ './selection/search',
+ './selection/eventRelay',
+
+ './utils',
+ './translation',
+ './diacritics',
+
+ './data/select',
+ './data/array',
+ './data/ajax',
+ './data/tags',
+ './data/tokenizer',
+ './data/minimumInputLength',
+ './data/maximumInputLength',
+ './data/maximumSelectionLength',
+
+ './dropdown',
+ './dropdown/search',
+ './dropdown/hidePlaceholder',
+ './dropdown/infiniteScroll',
+ './dropdown/attachBody',
+ './dropdown/minimumResultsForSearch',
+ './dropdown/selectOnClose',
+ './dropdown/closeOnSelect',
+
+ './i18n/en'
+], function ($, require,
+
+ ResultsList,
+
+ SingleSelection, MultipleSelection, Placeholder, AllowClear,
+ SelectionSearch, EventRelay,
+
+ Utils, Translation, DIACRITICS,
+
+ SelectData, ArrayData, AjaxData, Tags, Tokenizer,
+ MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
+
+ Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+ AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
+
+ EnglishTranslation) {
+ function Defaults () {
+ this.reset();
+ }
+
+ Defaults.prototype.apply = function (options) {
+ options = $.extend(true, {}, this.defaults, options);
+
+ if (options.dataAdapter == null) {
+ if (options.ajax != null) {
+ options.dataAdapter = AjaxData;
+ } else if (options.data != null) {
+ options.dataAdapter = ArrayData;
+ } else {
+ options.dataAdapter = SelectData;
+ }
+
+ if (options.minimumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MinimumInputLength
+ );
+ }
+
+ if (options.maximumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumInputLength
+ );
+ }
+
+ if (options.maximumSelectionLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumSelectionLength
+ );
+ }
+
+ if (options.tags) {
+ options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
+ }
+
+ if (options.tokenSeparators != null || options.tokenizer != null) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Tokenizer
+ );
+ }
+
+ if (options.query != null) {
+ var Query = require(options.amdBase + 'compat/query');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Query
+ );
+ }
+
+ if (options.initSelection != null) {
+ var InitSelection = require(options.amdBase + 'compat/initSelection');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ InitSelection
+ );
+ }
+ }
+
+ if (options.resultsAdapter == null) {
+ options.resultsAdapter = ResultsList;
+
+ if (options.ajax != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ InfiniteScroll
+ );
+ }
+
+ if (options.placeholder != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ HidePlaceholder
+ );
+ }
+
+ if (options.selectOnClose) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ SelectOnClose
+ );
+ }
+ }
+
+ if (options.dropdownAdapter == null) {
+ if (options.multiple) {
+ options.dropdownAdapter = Dropdown;
+ } else {
+ var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
+
+ options.dropdownAdapter = SearchableDropdown;
+ }
+
+ if (options.minimumResultsForSearch !== 0) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ MinimumResultsForSearch
+ );
+ }
+
+ if (options.closeOnSelect) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ CloseOnSelect
+ );
+ }
+
+ if (
+ options.dropdownCssClass != null ||
+ options.dropdownCss != null ||
+ options.adaptDropdownCssClass != null
+ ) {
+ var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ DropdownCSS
+ );
+ }
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ AttachBody
+ );
+ }
+
+ if (options.selectionAdapter == null) {
+ if (options.multiple) {
+ options.selectionAdapter = MultipleSelection;
+ } else {
+ options.selectionAdapter = SingleSelection;
+ }
+
+ // Add the placeholder mixin if a placeholder was specified
+ if (options.placeholder != null) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ Placeholder
+ );
+ }
+
+ if (options.allowClear) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ AllowClear
+ );
+ }
+
+ if (options.multiple) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ SelectionSearch
+ );
+ }
+
+ if (
+ options.containerCssClass != null ||
+ options.containerCss != null ||
+ options.adaptContainerCssClass != null
+ ) {
+ var ContainerCSS = require(options.amdBase + 'compat/containerCss');
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ ContainerCSS
+ );
+ }
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ EventRelay
+ );
+ }
+
+ // If the defaults were not previously applied from an element, it is
+ // possible for the language option to have not been resolved
+ options.language = this._resolveLanguage(options.language);
+
+ // Always fall back to English since it will always be complete
+ options.language.push('en');
+
+ var uniqueLanguages = [];
+
+ for (var l = 0; l < options.language.length; l++) {
+ var language = options.language[l];
+
+ if (uniqueLanguages.indexOf(language) === -1) {
+ uniqueLanguages.push(language);
+ }
+ }
+
+ options.language = uniqueLanguages;
+
+ options.translations = this._processTranslations(
+ options.language,
+ options.debug
+ );
+
+ return options;
+ };
+
+ Defaults.prototype.reset = function () {
+ function stripDiacritics (text) {
+ // Used 'uni range + named function' from http://jsperf.com/diacritics/18
+ function match(a) {
+ return DIACRITICS[a] || a;
+ }
+
+ return text.replace(/[^\u0000-\u007E]/g, match);
+ }
+
+ function matcher (params, data) {
+ // Always return the object if there is nothing to compare
+ if ($.trim(params.term) === '') {
+ return data;
+ }
+
+ // Do a recursive check for options with children
+ if (data.children && data.children.length > 0) {
+ // Clone the data object if there are children
+ // This is required as we modify the object to remove any non-matches
+ var match = $.extend(true, {}, data);
+
+ // Check each child of the option
+ for (var c = data.children.length - 1; c >= 0; c--) {
+ var child = data.children[c];
+
+ var matches = matcher(params, child);
+
+ // If there wasn't a match, remove the object in the array
+ if (matches == null) {
+ match.children.splice(c, 1);
+ }
+ }
+
+ // If any children matched, return the new object
+ if (match.children.length > 0) {
+ return match;
+ }
+
+ // If there were no matching children, check just the plain object
+ return matcher(params, match);
+ }
+
+ var original = stripDiacritics(data.text).toUpperCase();
+ var term = stripDiacritics(params.term).toUpperCase();
+
+ // Check if the text contains the term
+ if (original.indexOf(term) > -1) {
+ return data;
+ }
+
+ // If it doesn't contain the term, don't return anything
+ return null;
+ }
+
+ this.defaults = {
+ amdBase: './',
+ amdLanguageBase: './i18n/',
+ closeOnSelect: true,
+ debug: false,
+ dropdownAutoWidth: false,
+ escapeMarkup: Utils.escapeMarkup,
+ language: {},
+ matcher: matcher,
+ minimumInputLength: 0,
+ maximumInputLength: 0,
+ maximumSelectionLength: 0,
+ minimumResultsForSearch: 0,
+ selectOnClose: false,
+ scrollAfterSelect: false,
+ sorter: function (data) {
+ return data;
+ },
+ templateResult: function (result) {
+ return result.text;
+ },
+ templateSelection: function (selection) {
+ return selection.text;
+ },
+ theme: 'default',
+ width: 'resolve'
+ };
+ };
+
+ Defaults.prototype.applyFromElement = function (options, $element) {
+ var optionLanguage = options.language;
+ var defaultLanguage = this.defaults.language;
+ var elementLanguage = $element.prop('lang');
+ var parentLanguage = $element.closest('[lang]').prop('lang');
+
+ var languages = Array.prototype.concat.call(
+ this._resolveLanguage(elementLanguage),
+ this._resolveLanguage(optionLanguage),
+ this._resolveLanguage(defaultLanguage),
+ this._resolveLanguage(parentLanguage)
+ );
+
+ options.language = languages;
+
+ return options;
+ };
+
+ Defaults.prototype._resolveLanguage = function (language) {
+ if (!language) {
+ return [];
+ }
+
+ if ($.isEmptyObject(language)) {
+ return [];
+ }
+
+ if ($.isPlainObject(language)) {
+ return [language];
+ }
+
+ var languages;
+
+ if (!$.isArray(language)) {
+ languages = [language];
+ } else {
+ languages = language;
+ }
+
+ var resolvedLanguages = [];
+
+ for (var l = 0; l < languages.length; l++) {
+ resolvedLanguages.push(languages[l]);
+
+ if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
+ // Extract the region information if it is included
+ var languageParts = languages[l].split('-');
+ var baseLanguage = languageParts[0];
+
+ resolvedLanguages.push(baseLanguage);
+ }
+ }
+
+ return resolvedLanguages;
+ };
+
+ Defaults.prototype._processTranslations = function (languages, debug) {
+ var translations = new Translation();
+
+ for (var l = 0; l < languages.length; l++) {
+ var languageData = new Translation();
+
+ var language = languages[l];
+
+ if (typeof language === 'string') {
+ try {
+ // Try to load it with the original name
+ languageData = Translation.loadPath(language);
+ } catch (e) {
+ try {
+ // If we couldn't load it, check if it wasn't the full path
+ language = this.defaults.amdLanguageBase + language;
+ languageData = Translation.loadPath(language);
+ } catch (ex) {
+ // The translation could not be loaded at all. Sometimes this is
+ // because of a configuration problem, other times this can be
+ // because of how Select2 helps load all possible translation files
+ if (debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The language file for "' + language + '" could ' +
+ 'not be automatically loaded. A fallback will be used instead.'
+ );
+ }
+ }
+ }
+ } else if ($.isPlainObject(language)) {
+ languageData = new Translation(language);
+ } else {
+ languageData = language;
+ }
+
+ translations.extend(languageData);
+ }
+
+ return translations;
+ };
+
+ Defaults.prototype.set = function (key, value) {
+ var camelKey = $.camelCase(key);
+
+ var data = {};
+ data[camelKey] = value;
+
+ var convertedData = Utils._convertData(data);
+
+ $.extend(true, this.defaults, convertedData);
+ };
+
+ var defaults = new Defaults();
+
+ return defaults;
+});
+
+S2.define('select2/options',[
+ 'require',
+ 'jquery',
+ './defaults',
+ './utils'
+], function (require, $, Defaults, Utils) {
+ function Options (options, $element) {
+ this.options = options;
+
+ if ($element != null) {
+ this.fromElement($element);
+ }
+
+ if ($element != null) {
+ this.options = Defaults.applyFromElement(this.options, $element);
+ }
+
+ this.options = Defaults.apply(this.options);
+
+ if ($element && $element.is('input')) {
+ var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+ this.options.dataAdapter = Utils.Decorate(
+ this.options.dataAdapter,
+ InputCompat
+ );
+ }
+ }
+
+ Options.prototype.fromElement = function ($e) {
+ var excludedData = ['select2'];
+
+ if (this.options.multiple == null) {
+ this.options.multiple = $e.prop('multiple');
+ }
+
+ if (this.options.disabled == null) {
+ this.options.disabled = $e.prop('disabled');
+ }
+
+ if (this.options.dir == null) {
+ if ($e.prop('dir')) {
+ this.options.dir = $e.prop('dir');
+ } else if ($e.closest('[dir]').prop('dir')) {
+ this.options.dir = $e.closest('[dir]').prop('dir');
+ } else {
+ this.options.dir = 'ltr';
+ }
+ }
+
+ $e.prop('disabled', this.options.disabled);
+ $e.prop('multiple', this.options.multiple);
+
+ if (Utils.GetData($e[0], 'select2Tags')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-select2-tags` attribute has been changed to ' +
+ 'use the `data-data` and `data-tags="true"` attributes and will be ' +
+ 'removed in future versions of Select2.'
+ );
+ }
+
+ Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
+ Utils.StoreData($e[0], 'tags', true);
+ }
+
+ if (Utils.GetData($e[0], 'ajaxUrl')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-ajax-url` attribute has been changed to ' +
+ '`data-ajax--url` and support for the old attribute will be removed' +
+ ' in future versions of Select2.'
+ );
+ }
+
+ $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
+ Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
+ }
+
+ var dataset = {};
+
+ function upperCaseLetter(_, letter) {
+ return letter.toUpperCase();
+ }
+
+ // Pre-load all of the attributes which are prefixed with `data-`
+ for (var attr = 0; attr < $e[0].attributes.length; attr++) {
+ var attributeName = $e[0].attributes[attr].name;
+ var prefix = 'data-';
+
+ if (attributeName.substr(0, prefix.length) == prefix) {
+ // Get the contents of the attribute after `data-`
+ var dataName = attributeName.substring(prefix.length);
+
+ // Get the data contents from the consistent source
+ // This is more than likely the jQuery data helper
+ var dataValue = Utils.GetData($e[0], dataName);
+
+ // camelCase the attribute name to match the spec
+ var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
+
+ // Store the data attribute contents into the dataset since
+ dataset[camelDataName] = dataValue;
+ }
+ }
+
+ // Prefer the element's `dataset` attribute if it exists
+ // jQuery 1.x does not correctly handle data attributes with multiple dashes
+ if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
+ dataset = $.extend(true, {}, $e[0].dataset, dataset);
+ }
+
+ // Prefer our internal data cache if it exists
+ var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
+
+ data = Utils._convertData(data);
+
+ for (var key in data) {
+ if ($.inArray(key, excludedData) > -1) {
+ continue;
+ }
+
+ if ($.isPlainObject(this.options[key])) {
+ $.extend(this.options[key], data[key]);
+ } else {
+ this.options[key] = data[key];
+ }
+ }
+
+ return this;
+ };
+
+ Options.prototype.get = function (key) {
+ return this.options[key];
+ };
+
+ Options.prototype.set = function (key, val) {
+ this.options[key] = val;
+ };
+
+ return Options;
+});
+
+S2.define('select2/core',[
+ 'jquery',
+ './options',
+ './utils',
+ './keys'
+], function ($, Options, Utils, KEYS) {
+ var Select2 = function ($element, options) {
+ if (Utils.GetData($element[0], 'select2') != null) {
+ Utils.GetData($element[0], 'select2').destroy();
+ }
+
+ this.$element = $element;
+
+ this.id = this._generateId($element);
+
+ options = options || {};
+
+ this.options = new Options(options, $element);
+
+ Select2.__super__.constructor.call(this);
+
+ // Set up the tabindex
+
+ var tabindex = $element.attr('tabindex') || 0;
+ Utils.StoreData($element[0], 'old-tabindex', tabindex);
+ $element.attr('tabindex', '-1');
+
+ // Set up containers and adapters
+
+ var DataAdapter = this.options.get('dataAdapter');
+ this.dataAdapter = new DataAdapter($element, this.options);
+
+ var $container = this.render();
+
+ this._placeContainer($container);
+
+ var SelectionAdapter = this.options.get('selectionAdapter');
+ this.selection = new SelectionAdapter($element, this.options);
+ this.$selection = this.selection.render();
+
+ this.selection.position(this.$selection, $container);
+
+ var DropdownAdapter = this.options.get('dropdownAdapter');
+ this.dropdown = new DropdownAdapter($element, this.options);
+ this.$dropdown = this.dropdown.render();
+
+ this.dropdown.position(this.$dropdown, $container);
+
+ var ResultsAdapter = this.options.get('resultsAdapter');
+ this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
+ this.$results = this.results.render();
+
+ this.results.position(this.$results, this.$dropdown);
+
+ // Bind events
+
+ var self = this;
+
+ // Bind the container to all of the adapters
+ this._bindAdapters();
+
+ // Register any DOM event handlers
+ this._registerDomEvents();
+
+ // Register any internal event handlers
+ this._registerDataEvents();
+ this._registerSelectionEvents();
+ this._registerDropdownEvents();
+ this._registerResultsEvents();
+ this._registerEvents();
+
+ // Set the initial state
+ this.dataAdapter.current(function (initialData) {
+ self.trigger('selection:update', {
+ data: initialData
+ });
+ });
+
+ // Hide the original select
+ $element.addClass('select2-hidden-accessible');
+ $element.attr('aria-hidden', 'true');
+
+ // Synchronize any monitored attributes
+ this._syncAttributes();
+
+ Utils.StoreData($element[0], 'select2', this);
+
+ // Ensure backwards compatibility with $element.data('select2').
+ $element.data('select2', this);
+ };
+
+ Utils.Extend(Select2, Utils.Observable);
+
+ Select2.prototype._generateId = function ($element) {
+ var id = '';
+
+ if ($element.attr('id') != null) {
+ id = $element.attr('id');
+ } else if ($element.attr('name') != null) {
+ id = $element.attr('name') + '-' + Utils.generateChars(2);
+ } else {
+ id = Utils.generateChars(4);
+ }
+
+ id = id.replace(/(:|\.|\[|\]|,)/g, '');
+ id = 'select2-' + id;
+
+ return id;
+ };
+
+ Select2.prototype._placeContainer = function ($container) {
+ $container.insertAfter(this.$element);
+
+ var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+ if (width != null) {
+ $container.css('width', width);
+ }
+ };
+
+ Select2.prototype._resolveWidth = function ($element, method) {
+ var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+ if (method == 'resolve') {
+ var styleWidth = this._resolveWidth($element, 'style');
+
+ if (styleWidth != null) {
+ return styleWidth;
+ }
+
+ return this._resolveWidth($element, 'element');
+ }
+
+ if (method == 'element') {
+ var elementWidth = $element.outerWidth(false);
+
+ if (elementWidth <= 0) {
+ return 'auto';
+ }
+
+ return elementWidth + 'px';
+ }
+
+ if (method == 'style') {
+ var style = $element.attr('style');
+
+ if (typeof(style) !== 'string') {
+ return null;
+ }
+
+ var attrs = style.split(';');
+
+ for (var i = 0, l = attrs.length; i < l; i = i + 1) {
+ var attr = attrs[i].replace(/\s/g, '');
+ var matches = attr.match(WIDTH);
+
+ if (matches !== null && matches.length >= 1) {
+ return matches[1];
+ }
+ }
+
+ return null;
+ }
+
+ if (method == 'computedstyle') {
+ var computedStyle = window.getComputedStyle($element[0]);
+
+ return computedStyle.width;
+ }
+
+ return method;
+ };
+
+ Select2.prototype._bindAdapters = function () {
+ this.dataAdapter.bind(this, this.$container);
+ this.selection.bind(this, this.$container);
+
+ this.dropdown.bind(this, this.$container);
+ this.results.bind(this, this.$container);
+ };
+
+ Select2.prototype._registerDomEvents = function () {
+ var self = this;
+
+ this.$element.on('change.select2', function () {
+ self.dataAdapter.current(function (data) {
+ self.trigger('selection:update', {
+ data: data
+ });
+ });
+ });
+
+ this.$element.on('focus.select2', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this._syncA = Utils.bind(this._syncAttributes, this);
+ this._syncS = Utils.bind(this._syncSubtree, this);
+
+ if (this.$element[0].attachEvent) {
+ this.$element[0].attachEvent('onpropertychange', this._syncA);
+ }
+
+ var observer = window.MutationObserver ||
+ window.WebKitMutationObserver ||
+ window.MozMutationObserver
+ ;
+
+ if (observer != null) {
+ this._observer = new observer(function (mutations) {
+ $.each(mutations, self._syncA);
+ $.each(mutations, self._syncS);
+ });
+ this._observer.observe(this.$element[0], {
+ attributes: true,
+ childList: true,
+ subtree: false
+ });
+ } else if (this.$element[0].addEventListener) {
+ this.$element[0].addEventListener(
+ 'DOMAttrModified',
+ self._syncA,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeInserted',
+ self._syncS,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeRemoved',
+ self._syncS,
+ false
+ );
+ }
+ };
+
+ Select2.prototype._registerDataEvents = function () {
+ var self = this;
+
+ this.dataAdapter.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerSelectionEvents = function () {
+ var self = this;
+ var nonRelayEvents = ['toggle', 'focus'];
+
+ this.selection.on('toggle', function () {
+ self.toggleDropdown();
+ });
+
+ this.selection.on('focus', function (params) {
+ self.focus(params);
+ });
+
+ this.selection.on('*', function (name, params) {
+ if ($.inArray(name, nonRelayEvents) !== -1) {
+ return;
+ }
+
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerDropdownEvents = function () {
+ var self = this;
+
+ this.dropdown.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerResultsEvents = function () {
+ var self = this;
+
+ this.results.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerEvents = function () {
+ var self = this;
+
+ this.on('open', function () {
+ self.$container.addClass('select2-container--open');
+ });
+
+ this.on('close', function () {
+ self.$container.removeClass('select2-container--open');
+ });
+
+ this.on('enable', function () {
+ self.$container.removeClass('select2-container--disabled');
+ });
+
+ this.on('disable', function () {
+ self.$container.addClass('select2-container--disabled');
+ });
+
+ this.on('blur', function () {
+ self.$container.removeClass('select2-container--focus');
+ });
+
+ this.on('query', function (params) {
+ if (!self.isOpen()) {
+ self.trigger('open', {});
+ }
+
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:all', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('query:append', function (params) {
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:append', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('keypress', function (evt) {
+ var key = evt.which;
+
+ if (self.isOpen()) {
+ if (key === KEYS.ESC || key === KEYS.TAB ||
+ (key === KEYS.UP && evt.altKey)) {
+ self.close();
+
+ evt.preventDefault();
+ } else if (key === KEYS.ENTER) {
+ self.trigger('results:select', {});
+
+ evt.preventDefault();
+ } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
+ self.trigger('results:toggle', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.UP) {
+ self.trigger('results:previous', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.DOWN) {
+ self.trigger('results:next', {});
+
+ evt.preventDefault();
+ }
+ } else {
+ if (key === KEYS.ENTER || key === KEYS.SPACE ||
+ (key === KEYS.DOWN && evt.altKey)) {
+ self.open();
+
+ evt.preventDefault();
+ }
+ }
+ });
+ };
+
+ Select2.prototype._syncAttributes = function () {
+ this.options.set('disabled', this.$element.prop('disabled'));
+
+ if (this.options.get('disabled')) {
+ if (this.isOpen()) {
+ this.close();
+ }
+
+ this.trigger('disable', {});
+ } else {
+ this.trigger('enable', {});
+ }
+ };
+
+ Select2.prototype._syncSubtree = function (evt, mutations) {
+ var changed = false;
+ var self = this;
+
+ // Ignore any mutation events raised for elements that aren't options or
+ // optgroups. This handles the case when the select element is destroyed
+ if (
+ evt && evt.target && (
+ evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
+ )
+ ) {
+ return;
+ }
+
+ if (!mutations) {
+ // If mutation events aren't supported, then we can only assume that the
+ // change affected the selections
+ changed = true;
+ } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
+ for (var n = 0; n < mutations.addedNodes.length; n++) {
+ var node = mutations.addedNodes[n];
+
+ if (node.selected) {
+ changed = true;
+ }
+ }
+ } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
+ changed = true;
+ }
+
+ // Only re-pull the data if we think there is a change
+ if (changed) {
+ this.dataAdapter.current(function (currentData) {
+ self.trigger('selection:update', {
+ data: currentData
+ });
+ });
+ }
+ };
+
+ /**
+ * Override the trigger method to automatically trigger pre-events when
+ * there are events that can be prevented.
+ */
+ Select2.prototype.trigger = function (name, args) {
+ var actualTrigger = Select2.__super__.trigger;
+ var preTriggerMap = {
+ 'open': 'opening',
+ 'close': 'closing',
+ 'select': 'selecting',
+ 'unselect': 'unselecting',
+ 'clear': 'clearing'
+ };
+
+ if (args === undefined) {
+ args = {};
+ }
+
+ if (name in preTriggerMap) {
+ var preTriggerName = preTriggerMap[name];
+ var preTriggerArgs = {
+ prevented: false,
+ name: name,
+ args: args
+ };
+
+ actualTrigger.call(this, preTriggerName, preTriggerArgs);
+
+ if (preTriggerArgs.prevented) {
+ args.prevented = true;
+
+ return;
+ }
+ }
+
+ actualTrigger.call(this, name, args);
+ };
+
+ Select2.prototype.toggleDropdown = function () {
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ if (this.isOpen()) {
+ this.close();
+ } else {
+ this.open();
+ }
+ };
+
+ Select2.prototype.open = function () {
+ if (this.isOpen()) {
+ return;
+ }
+
+ this.trigger('query', {});
+ };
+
+ Select2.prototype.close = function () {
+ if (!this.isOpen()) {
+ return;
+ }
+
+ this.trigger('close', {});
+ };
+
+ Select2.prototype.isOpen = function () {
+ return this.$container.hasClass('select2-container--open');
+ };
+
+ Select2.prototype.hasFocus = function () {
+ return this.$container.hasClass('select2-container--focus');
+ };
+
+ Select2.prototype.focus = function (data) {
+ // No need to re-trigger focus events if we are already focused
+ if (this.hasFocus()) {
+ return;
+ }
+
+ this.$container.addClass('select2-container--focus');
+ this.trigger('focus', {});
+ };
+
+ Select2.prototype.enable = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("enable")` method has been deprecated and will' +
+ ' be removed in later Select2 versions. Use $element.prop("disabled")' +
+ ' instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ args = [true];
+ }
+
+ var disabled = !args[0];
+
+ this.$element.prop('disabled', disabled);
+ };
+
+ Select2.prototype.data = function () {
+ if (this.options.get('debug') &&
+ arguments.length > 0 && window.console && console.warn) {
+ console.warn(
+ 'Select2: Data can no longer be set using `select2("data")`. You ' +
+ 'should consider setting the value instead using `$element.val()`.'
+ );
+ }
+
+ var data = [];
+
+ this.dataAdapter.current(function (currentData) {
+ data = currentData;
+ });
+
+ return data;
+ };
+
+ Select2.prototype.val = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("val")` method has been deprecated and will be' +
+ ' removed in later Select2 versions. Use $element.val() instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ return this.$element.val();
+ }
+
+ var newVal = args[0];
+
+ if ($.isArray(newVal)) {
+ newVal = $.map(newVal, function (obj) {
+ return obj.toString();
+ });
+ }
+
+ this.$element.val(newVal).trigger('change');
+ };
+
+ Select2.prototype.destroy = function () {
+ this.$container.remove();
+
+ if (this.$element[0].detachEvent) {
+ this.$element[0].detachEvent('onpropertychange', this._syncA);
+ }
+
+ if (this._observer != null) {
+ this._observer.disconnect();
+ this._observer = null;
+ } else if (this.$element[0].removeEventListener) {
+ this.$element[0]
+ .removeEventListener('DOMAttrModified', this._syncA, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeInserted', this._syncS, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeRemoved', this._syncS, false);
+ }
+
+ this._syncA = null;
+ this._syncS = null;
+
+ this.$element.off('.select2');
+ this.$element.attr('tabindex',
+ Utils.GetData(this.$element[0], 'old-tabindex'));
+
+ this.$element.removeClass('select2-hidden-accessible');
+ this.$element.attr('aria-hidden', 'false');
+ Utils.RemoveData(this.$element[0]);
+ this.$element.removeData('select2');
+
+ this.dataAdapter.destroy();
+ this.selection.destroy();
+ this.dropdown.destroy();
+ this.results.destroy();
+
+ this.dataAdapter = null;
+ this.selection = null;
+ this.dropdown = null;
+ this.results = null;
+ };
+
+ Select2.prototype.render = function () {
+ var $container = $(
+ '<span class="select2 select2-container">' +
+ '<span class="selection"></span>' +
+ '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
+ '</span>'
+ );
+
+ $container.attr('dir', this.options.get('dir'));
+
+ this.$container = $container;
+
+ this.$container.addClass('select2-container--' + this.options.get('theme'));
+
+ Utils.StoreData($container[0], 'element', this.$element);
+
+ return $container;
+ };
+
+ return Select2;
+});
+
+S2.define('jquery-mousewheel',[
+ 'jquery'
+], function ($) {
+ // Used to shim jQuery.mousewheel for non-full builds.
+ return $;
+});
+
+S2.define('jquery.select2',[
+ 'jquery',
+ 'jquery-mousewheel',
+
+ './select2/core',
+ './select2/defaults',
+ './select2/utils'
+], function ($, _, Select2, Defaults, Utils) {
+ if ($.fn.select2 == null) {
+ // All methods that should return the element
+ var thisMethods = ['open', 'close', 'destroy'];
+
+ $.fn.select2 = function (options) {
+ options = options || {};
+
+ if (typeof options === 'object') {
+ this.each(function () {
+ var instanceOptions = $.extend(true, {}, options);
+
+ var instance = new Select2($(this), instanceOptions);
+ });
+
+ return this;
+ } else if (typeof options === 'string') {
+ var ret;
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ this.each(function () {
+ var instance = Utils.GetData(this, 'select2');
+
+ if (instance == null && window.console && console.error) {
+ console.error(
+ 'The select2(\'' + options + '\') method was called on an ' +
+ 'element that is not using Select2.'
+ );
+ }
+
+ ret = instance[options].apply(instance, args);
+ });
+
+ // Check if we should be returning `this`
+ if ($.inArray(options, thisMethods) > -1) {
+ return this;
+ }
+
+ return ret;
+ } else {
+ throw new Error('Invalid arguments for Select2: ' + options);
+ }
+ };
+ }
+
+ if ($.fn.select2.defaults == null) {
+ $.fn.select2.defaults = Defaults;
+ }
+
+ return Select2;
+});
+
+ // Return the AMD loader configuration so it can be used outside of this file
+ return {
+ define: S2.define,
+ require: S2.require
+ };
+}());
+
+ // Autoload the jQuery bindings
+ // We know that all of the modules exist above this, so we're safe
+ var select2 = S2.require('jquery.select2');
+
+ // Hold the AMD module references on the jQuery function that was just loaded
+ // This allows Select2 to use the internal loader outside of this file, such
+ // as in the language files.
+ jQuery.fn.select2.amd = S2;
+
+ // Return the Select2 instance for anyone who is importing it.
+ return select2;
+}));
diff --git a/src/lib/vendor/toggle-switch.css b/src/lib/vendor/toggle-switch.css
new file mode 100644
index 0000000..1b0386e
--- /dev/null
+++ b/src/lib/vendor/toggle-switch.css
@@ -0,0 +1,310 @@
+/*
+ * CSS TOGGLE SWITCHES
+ * Unlicense
+ *
+ * IonuÈ› Colceriu - ghinda.net
+ * https://github.com/ghinda/css-toggle-switch
+ *
+ */
+/* Toggle Switches
+ */
+/* Shared
+ */
+/* Checkbox
+ */
+/* Radio Switch
+ */
+/* Hide by default
+ */
+.switch-toggle a, .switch-light span span {
+ display: none; }
+
+/* We can't test for a specific feature,
+ * so we only target browsers with support for media queries.
+ */
+@media only screen {
+ /* Checkbox switch
+ */
+ /* Radio switch
+ */
+ /* Standalone Themes */
+ /* Candy Theme
+ * Based on the "Sort Switches / Toggles (PSD)" by Ormal Clarck
+ * http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/
+ */
+ /* Android Theme
+ */
+ /* iOS Theme
+ */
+ .switch-light {
+ display: block;
+ height: 30px;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ overflow: visible;
+ padding: 0;
+ margin-left: 100px;
+ /* Position the label over all the elements, except the slide-button (<a>)
+ * Clicking anywhere on the label will change the switch-state
+ */
+ /* Don't hide the input from screen-readers and keyboard access
+ */ }
+ .switch-light * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-light a {
+ display: block;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-light label, .switch-light > span {
+ line-height: 30px;
+ vertical-align: middle; }
+ .switch-light input:focus ~ a, .switch-light input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-light label {
+ position: relative;
+ z-index: 3;
+ display: block;
+ width: 100%; }
+ .switch-light input {
+ position: absolute;
+ opacity: 0;
+ z-index: 5; }
+ .switch-light input:checked ~ a {
+ right: 0%; }
+ .switch-light > span {
+ position: absolute;
+ left: -100px;
+ width: 100%;
+ margin: 0;
+ padding-right: 100px;
+ text-align: left; }
+ .switch-light > span span {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 5;
+ display: block;
+ width: 50%;
+ margin-left: 100px;
+ text-align: center; }
+ .switch-light > span span:last-child {
+ left: 50%; }
+ .switch-light a {
+ position: absolute;
+ right: 50%;
+ top: 0;
+ z-index: 4;
+ display: block;
+ width: 50%;
+ height: 100%;
+ padding: 0; }
+ .switch-toggle {
+ display: block;
+ height: 30px;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ /* For callout panels in foundation
+ */
+ padding: 0 !important;
+ /* Generate styles for the multiple states */ }
+ .switch-toggle * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-toggle a {
+ display: block;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-toggle label, .switch-toggle > span {
+ line-height: 30px;
+ vertical-align: middle; }
+ .switch-toggle input:focus ~ a, .switch-toggle input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-toggle input {
+ position: absolute;
+ opacity: 0; }
+ .switch-toggle input + label {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 50%;
+ height: 100%;
+ margin: 0;
+ text-align: center; }
+ .switch-toggle a {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 0;
+ z-index: 1;
+ width: 50%;
+ height: 100%; }
+ .switch-toggle input:last-of-type:checked ~ a {
+ left: 50%; }
+ .switch-toggle.switch-3 label, .switch-toggle.switch-3 a {
+ width: 33.33333%; }
+ .switch-toggle.switch-3 input:checked:nth-of-type(2) ~ a {
+ left: 33.33333%; }
+ .switch-toggle.switch-3 input:checked:last-of-type ~ a {
+ left: 66.66667%; }
+ .switch-toggle.switch-4 label, .switch-toggle.switch-4 a {
+ width: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(2) ~ a {
+ left: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(3) ~ a {
+ left: 50%; }
+ .switch-toggle.switch-4 input:checked:last-of-type ~ a {
+ left: 75%; }
+ .switch-toggle.switch-5 label, .switch-toggle.switch-5 a {
+ width: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(2) ~ a {
+ left: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(3) ~ a {
+ left: 40%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(4) ~ a {
+ left: 60%; }
+ .switch-toggle.switch-5 input:checked:last-of-type ~ a {
+ left: 80%; }
+ .switch-candy {
+ background-color: #2d3035;
+ border-radius: 3px;
+ color: #fff;
+ font-weight: bold;
+ text-align: center;
+ text-shadow: 1px 1px 1px #191b1e;
+ box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 0px rgba(255, 255, 255, 0.2); }
+ .switch-candy label {
+ color: #fff;
+ -webkit-transition: color 0.2s ease-out;
+ -moz-transition: color 0.2s ease-out;
+ transition: color 0.2s ease-out; }
+ .switch-candy input:checked + label {
+ color: #333;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
+ .switch-candy a {
+ border: 1px solid #333;
+ background-color: #70c66b;
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.45); }
+ .switch-candy > span {
+ color: #333;
+ text-shadow: none; }
+ .switch-candy span {
+ color: #fff; }
+ .switch-candy.switch-candy-blue a {
+ background-color: #38a3d4; }
+ .switch-candy.switch-candy-yellow a {
+ background-color: #f5e560; }
+ .switch-android {
+ background-color: #464747;
+ border-radius: 1px;
+ color: #fff;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0;
+ /* Selected ON switch-light
+ */ }
+ .switch-android label {
+ color: #fff; }
+ .switch-android > span span {
+ opacity: 0;
+ -webkit-transition: all 0.1s;
+ -moz-transition: all 0.1s;
+ transition: all 0.1s; }
+ .switch-android > span span:first-of-type {
+ opacity: 1; }
+ .switch-android a {
+ background-color: #666;
+ border-radius: 1px;
+ box-shadow: inset rgba(255, 255, 255, 0.2) 0 1px 0, inset rgba(0, 0, 0, 0.3) 0 -1px 0; }
+ .switch-android.switch-light input:checked ~ a {
+ background-color: #0E88B1; }
+ .switch-android.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-android.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1; }
+ .switch-android.switch-toggle, .switch-android > span span {
+ font-size: 85%;
+ text-transform: uppercase; }
+ .switch-ios.switch-light {
+ color: #868686; }
+ .switch-ios.switch-light a {
+ left: 0;
+ width: 30px;
+ background-color: #fff;
+ border: 1px solid #d3d3d3;
+ border-radius: 100%;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+ box-shadow: inset 0 -3px 3px rgba(0, 0, 0, 0.025), 0 1px 4px rgba(0, 0, 0, 0.15), 0 4px 4px rgba(0, 0, 0, 0.1); }
+ .switch-ios.switch-light > span span {
+ width: 100%;
+ left: 0;
+ opacity: 0; }
+ .switch-ios.switch-light > span span:first-of-type {
+ opacity: 1;
+ padding-left: 30px; }
+ .switch-ios.switch-light > span span:last-of-type {
+ padding-right: 30px; }
+ .switch-ios.switch-light > span:before {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 100px;
+ top: 0;
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ -webkit-transition: all 0.5s ease-out;
+ -moz-transition: all 0.5s ease-out;
+ transition: all 0.5s ease-out;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-light input:checked ~ a {
+ left: 100%;
+ margin-left: -30px; }
+ .switch-ios.switch-light input:checked ~ span:before {
+ border-color: #53d76a;
+ box-shadow: inset 0 0 0 30px #53d76a; }
+ .switch-ios.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-ios.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1;
+ color: #fff; }
+ .switch-ios.switch-toggle {
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-toggle a {
+ background-color: #53d76a;
+ border-radius: 25px;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-ios.switch-toggle label {
+ color: #868686; }
+ .switch-ios input:checked + label {
+ color: #3a3a3a; } }
+
+/* Bugfix for older Webkit, including mobile Webkit. Adapted from
+ * http://css-tricks.com/webkit-sibling-bug/
+ */
+@media only screen and (-webkit-max-device-pixel-ratio: 2) and (max-device-width: 1280px) {
+ .switch-light, .switch-toggle {
+ -webkit-animation: webkitSiblingBugfix infinite 1s; } }
+
+@-webkit-keyframes webkitSiblingBugfix {
+ from {
+ -webkit-transform: translate3d(0, 0, 0); }
+
+ to {
+ -webkit-transform: translate3d(0, 0, 0); } }
diff --git a/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css
new file mode 100644
index 0000000..b35a240
--- /dev/null
+++ b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css
@@ -0,0 +1,388 @@
+/* This is the core CSS of Tooltipster */
+
+/* GENERAL STRUCTURE RULES (do not edit this section) */
+
+.tooltipster-base {
+ /* this ensures that a constrained height set by functionPosition,
+ if greater that the natural height of the tooltip, will be enforced
+ in browsers that support display:flex */
+ display: flex;
+ pointer-events: none;
+ /* this may be overriden in JS for fixed position origins */
+ position: absolute;
+}
+
+.tooltipster-box {
+ /* see .tooltipster-base. flex-shrink 1 is only necessary for IE10-
+ and flex-basis auto for IE11- (at least) */
+ flex: 1 1 auto;
+}
+
+.tooltipster-content {
+ /* prevents an overflow if the user adds padding to the div */
+ box-sizing: border-box;
+ /* these make sure we'll be able to detect any overflow */
+ max-height: 100%;
+ max-width: 100%;
+ overflow: auto;
+}
+
+.tooltipster-ruler {
+ /* these let us test the size of the tooltip without overflowing the window */
+ bottom: 0;
+ left: 0;
+ overflow: hidden;
+ position: fixed;
+ right: 0;
+ top: 0;
+ visibility: hidden;
+}
+
+/* ANIMATIONS */
+
+/* Open/close animations */
+
+/* fade */
+
+.tooltipster-fade {
+ opacity: 0;
+ -webkit-transition-property: opacity;
+ -moz-transition-property: opacity;
+ -o-transition-property: opacity;
+ -ms-transition-property: opacity;
+ transition-property: opacity;
+}
+.tooltipster-fade.tooltipster-show {
+ opacity: 1;
+}
+
+/* grow */
+
+.tooltipster-grow {
+ -webkit-transform: scale(0,0);
+ -moz-transform: scale(0,0);
+ -o-transform: scale(0,0);
+ -ms-transform: scale(0,0);
+ transform: scale(0,0);
+ -webkit-transition-property: -webkit-transform;
+ -moz-transition-property: -moz-transform;
+ -o-transition-property: -o-transform;
+ -ms-transition-property: -ms-transform;
+ transition-property: transform;
+ -webkit-backface-visibility: hidden;
+}
+.tooltipster-grow.tooltipster-show {
+ -webkit-transform: scale(1,1);
+ -moz-transform: scale(1,1);
+ -o-transform: scale(1,1);
+ -ms-transform: scale(1,1);
+ transform: scale(1,1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+
+/* swing */
+
+.tooltipster-swing {
+ opacity: 0;
+ -webkit-transform: rotateZ(4deg);
+ -moz-transform: rotateZ(4deg);
+ -o-transform: rotateZ(4deg);
+ -ms-transform: rotateZ(4deg);
+ transform: rotateZ(4deg);
+ -webkit-transition-property: -webkit-transform, opacity;
+ -moz-transition-property: -moz-transform;
+ -o-transition-property: -o-transform;
+ -ms-transition-property: -ms-transform;
+ transition-property: transform;
+}
+.tooltipster-swing.tooltipster-show {
+ opacity: 1;
+ -webkit-transform: rotateZ(0deg);
+ -moz-transform: rotateZ(0deg);
+ -o-transform: rotateZ(0deg);
+ -ms-transform: rotateZ(0deg);
+ transform: rotateZ(0deg);
+ -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -moz-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -ms-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -o-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+}
+
+/* fall */
+
+.tooltipster-fall {
+ -webkit-transition-property: top;
+ -moz-transition-property: top;
+ -o-transition-property: top;
+ -ms-transition-property: top;
+ transition-property: top;
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+.tooltipster-fall.tooltipster-initial {
+ top: 0 !important;
+}
+.tooltipster-fall.tooltipster-show {
+}
+.tooltipster-fall.tooltipster-dying {
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -o-transition-property: all;
+ -ms-transition-property: all;
+ transition-property: all;
+ top: 0 !important;
+ opacity: 0;
+}
+
+/* slide */
+
+.tooltipster-slide {
+ -webkit-transition-property: left;
+ -moz-transition-property: left;
+ -o-transition-property: left;
+ -ms-transition-property: left;
+ transition-property: left;
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+.tooltipster-slide.tooltipster-initial {
+ left: -40px !important;
+}
+.tooltipster-slide.tooltipster-show {
+}
+.tooltipster-slide.tooltipster-dying {
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -o-transition-property: all;
+ -ms-transition-property: all;
+ transition-property: all;
+ left: 0 !important;
+ opacity: 0;
+}
+
+/* Update animations */
+
+/* We use animations rather than transitions here because
+ transition durations may be specified in the style tag due to
+ animationDuration, and we try to avoid collisions and the use
+ of !important */
+
+/* fade */
+
+@keyframes tooltipster-fading {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+.tooltipster-update-fade {
+ animation: tooltipster-fading 400ms;
+}
+
+/* rotate */
+
+@keyframes tooltipster-rotating {
+ 25% {
+ transform: rotate(-2deg);
+ }
+ 75% {
+ transform: rotate(2deg);
+ }
+ 100% {
+ transform: rotate(0);
+ }
+}
+
+.tooltipster-update-rotate {
+ animation: tooltipster-rotating 600ms;
+}
+
+/* scale */
+
+@keyframes tooltipster-scaling {
+ 50% {
+ transform: scale(1.1);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+.tooltipster-update-scale {
+ animation: tooltipster-scaling 600ms;
+}
+
+/**
+ * DEFAULT STYLE OF THE SIDETIP PLUGIN
+ *
+ * All styles are "namespaced" with .tooltipster-sidetip to prevent
+ * conflicts between plugins.
+ */
+
+/* .tooltipster-box */
+
+.tooltipster-sidetip .tooltipster-box {
+ background: #565656;
+ border: 2px solid black;
+ border-radius: 4px;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-box {
+ margin-top: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-box {
+ margin-right: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-box {
+ margin-left: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-box {
+ margin-bottom: 8px;
+}
+
+/* .tooltipster-content */
+
+.tooltipster-sidetip .tooltipster-content {
+ color: white;
+ line-height: 18px;
+ padding: 6px 14px;
+}
+
+/* .tooltipster-arrow : will keep only the zone of .tooltipster-arrow-uncropped that
+corresponds to the arrow we want to display */
+
+.tooltipster-sidetip .tooltipster-arrow {
+ overflow: hidden;
+ position: absolute;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow {
+ height: 10px;
+ /* half the width, for centering */
+ margin-left: -10px;
+ top: 0;
+ width: 20px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow {
+ height: 20px;
+ margin-top: -10px;
+ right: 0;
+ /* top 0 to keep the arrow from overflowing .tooltipster-base when it has not
+ been positioned yet */
+ top: 0;
+ width: 10px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow {
+ height: 20px;
+ margin-top: -10px;
+ left: 0;
+ /* same as .tooltipster-left .tooltipster-arrow */
+ top: 0;
+ width: 10px;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow {
+ bottom: 0;
+ height: 10px;
+ margin-left: -10px;
+ width: 20px;
+}
+
+/* common rules between .tooltipster-arrow-background and .tooltipster-arrow-border */
+
+.tooltipster-sidetip .tooltipster-arrow-background, .tooltipster-sidetip .tooltipster-arrow-border {
+ height: 0;
+ position: absolute;
+ width: 0;
+}
+
+/* .tooltipster-arrow-background */
+
+.tooltipster-sidetip .tooltipster-arrow-background {
+ border: 10px solid transparent;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-background {
+ border-bottom-color: #565656;
+ left: 0;
+ top: 3px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-background {
+ border-left-color: #565656;
+ left: -3px;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-background {
+ border-right-color: #565656;
+ left: 3px;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-background {
+ border-top-color: #565656;
+ left: 0;
+ top: -3px;
+}
+
+/* .tooltipster-arrow-border */
+
+.tooltipster-sidetip .tooltipster-arrow-border {
+ border: 10px solid transparent;
+ left: 0;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-border {
+ border-bottom-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-border {
+ border-left-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-border {
+ border-right-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-border {
+ border-top-color: black;
+}
+
+/* tooltipster-arrow-uncropped */
+
+.tooltipster-sidetip .tooltipster-arrow-uncropped {
+ position: relative;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-uncropped {
+ top: -10px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-uncropped {
+ left: -10px;
+}
diff --git a/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js
new file mode 100644
index 0000000..e2250a6
--- /dev/null
+++ b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js
@@ -0,0 +1,4273 @@
+/**
+ * tooltipster http://iamceege.github.io/tooltipster/
+ * A rockin' custom tooltip jQuery plugin
+ * Developed by Caleb Jacob and Louis Ameline
+ * MIT license
+ */
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module unless amdModuleId is set
+ define(["jquery"], function (a0) {
+ return (factory(a0));
+ });
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = factory(require("jquery"));
+ } else {
+ factory(jQuery);
+ }
+}(this, function ($) {
+
+// This file will be UMDified by a build task.
+
+var defaults = {
+ animation: 'fade',
+ animationDuration: 350,
+ content: null,
+ contentAsHTML: false,
+ contentCloning: false,
+ debug: true,
+ delay: 300,
+ delayTouch: [300, 500],
+ functionInit: null,
+ functionBefore: null,
+ functionReady: null,
+ functionAfter: null,
+ functionFormat: null,
+ IEmin: 6,
+ interactive: false,
+ multiple: false,
+ // will default to document.body, or must be an element positioned at (0, 0)
+ // in the document, typically like the very top views of an app.
+ parent: null,
+ plugins: ['sideTip'],
+ repositionOnScroll: false,
+ restoration: 'none',
+ selfDestruction: true,
+ theme: [],
+ timer: 0,
+ trackerInterval: 500,
+ trackOrigin: false,
+ trackTooltip: false,
+ trigger: 'hover',
+ triggerClose: {
+ click: false,
+ mouseleave: false,
+ originClick: false,
+ scroll: false,
+ tap: false,
+ touchleave: false
+ },
+ triggerOpen: {
+ click: false,
+ mouseenter: false,
+ tap: false,
+ touchstart: false
+ },
+ updateAnimation: 'rotate',
+ zIndex: 9999999
+ },
+ // we'll avoid using the 'window' global as a good practice but npm's
+ // jquery@<2.1.0 package actually requires a 'window' global, so not sure
+ // it's useful at all
+ win = (typeof window != 'undefined') ? window : null,
+ // env will be proxied by the core for plugins to have access its properties
+ env = {
+ // detect if this device can trigger touch events. Better have a false
+ // positive (unused listeners, that's ok) than a false negative.
+ // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js
+ // http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
+ hasTouchCapability: !!(
+ win
+ && ( 'ontouchstart' in win
+ || (win.DocumentTouch && win.document instanceof win.DocumentTouch)
+ || win.navigator.maxTouchPoints
+ )
+ ),
+ hasTransitions: transitionSupport(),
+ IE: false,
+ // don't set manually, it will be updated by a build task after the manifest
+ semVer: '4.2.6',
+ window: win
+ },
+ core = function() {
+
+ // core variables
+
+ // the core emitters
+ this.__$emitterPrivate = $({});
+ this.__$emitterPublic = $({});
+ this.__instancesLatestArr = [];
+ // collects plugin constructors
+ this.__plugins = {};
+ // proxy env variables for plugins who might use them
+ this._env = env;
+ };
+
+// core methods
+core.prototype = {
+
+ /**
+ * A function to proxy the public methods of an object onto another
+ *
+ * @param {object} constructor The constructor to bridge
+ * @param {object} obj The object that will get new methods (an instance or the core)
+ * @param {string} pluginName A plugin name for the console log message
+ * @return {core}
+ * @private
+ */
+ __bridge: function(constructor, obj, pluginName) {
+
+ // if it's not already bridged
+ if (!obj[pluginName]) {
+
+ var fn = function() {};
+ fn.prototype = constructor;
+
+ var pluginInstance = new fn();
+
+ // the _init method has to exist in instance constructors but might be missing
+ // in core constructors
+ if (pluginInstance.__init) {
+ pluginInstance.__init(obj);
+ }
+
+ $.each(constructor, function(methodName, fn) {
+
+ // don't proxy "private" methods, only "protected" and public ones
+ if (methodName.indexOf('__') != 0) {
+
+ // if the method does not exist yet
+ if (!obj[methodName]) {
+
+ obj[methodName] = function() {
+ return pluginInstance[methodName].apply(pluginInstance, Array.prototype.slice.apply(arguments));
+ };
+
+ // remember to which plugin this method corresponds (several plugins may
+ // have methods of the same name, we need to be sure)
+ obj[methodName].bridged = pluginInstance;
+ }
+ else if (defaults.debug) {
+
+ console.log('The '+ methodName +' method of the '+ pluginName
+ +' plugin conflicts with another plugin or native methods');
+ }
+ }
+ });
+
+ obj[pluginName] = pluginInstance;
+ }
+
+ return this;
+ },
+
+ /**
+ * For mockup in Node env if need be, for testing purposes
+ *
+ * @return {core}
+ * @private
+ */
+ __setWindow: function(window) {
+ env.window = window;
+ return this;
+ },
+
+ /**
+ * Returns a ruler, a tool to help measure the size of a tooltip under
+ * various settings. Meant for plugins
+ *
+ * @see Ruler
+ * @return {object} A Ruler instance
+ * @protected
+ */
+ _getRuler: function($tooltip) {
+ return new Ruler($tooltip);
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _off: function() {
+ this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _on: function() {
+ this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _one: function() {
+ this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Returns (getter) or adds (setter) a plugin
+ *
+ * @param {string|object} plugin Provide a string (in the full form
+ * "namespace.name") to use as as getter, an object to use as a setter
+ * @return {object|core}
+ * @protected
+ */
+ _plugin: function(plugin) {
+
+ var self = this;
+
+ // getter
+ if (typeof plugin == 'string') {
+
+ var pluginName = plugin,
+ p = null;
+
+ // if the namespace is provided, it's easy to search
+ if (pluginName.indexOf('.') > 0) {
+ p = self.__plugins[pluginName];
+ }
+ // otherwise, return the first name that matches
+ else {
+ $.each(self.__plugins, function(i, plugin) {
+
+ if (plugin.name.substring(plugin.name.length - pluginName.length - 1) == '.'+ pluginName) {
+ p = plugin;
+ return false;
+ }
+ });
+ }
+
+ return p;
+ }
+ // setter
+ else {
+
+ // force namespaces
+ if (plugin.name.indexOf('.') < 0) {
+ throw new Error('Plugins must be namespaced');
+ }
+
+ self.__plugins[plugin.name] = plugin;
+
+ // if the plugin has core features
+ if (plugin.core) {
+
+ // bridge non-private methods onto the core to allow new core methods
+ self.__bridge(plugin.core, self, plugin.name);
+ }
+
+ return this;
+ }
+ },
+
+ /**
+ * Trigger events on the core emitters
+ *
+ * @returns {core}
+ * @protected
+ */
+ _trigger: function() {
+
+ var args = Array.prototype.slice.apply(arguments);
+
+ if (typeof args[0] == 'string') {
+ args[0] = { type: args[0] };
+ }
+
+ // note: the order of emitters matters
+ this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);
+ this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);
+
+ return this;
+ },
+
+ /**
+ * Returns instances of all tooltips in the page or an a given element
+ *
+ * @param {string|HTML object collection} selector optional Use this
+ * parameter to restrict the set of objects that will be inspected
+ * for the retrieval of instances. By default, all instances in the
+ * page are returned.
+ * @return {array} An array of instance objects
+ * @public
+ */
+ instances: function(selector) {
+
+ var instances = [],
+ sel = selector || '.tooltipstered';
+
+ $(sel).each(function() {
+
+ var $this = $(this),
+ ns = $this.data('tooltipster-ns');
+
+ if (ns) {
+
+ $.each(ns, function(i, namespace) {
+ instances.push($this.data(namespace));
+ });
+ }
+ });
+
+ return instances;
+ },
+
+ /**
+ * Returns the Tooltipster objects generated by the last initializing call
+ *
+ * @return {array} An array of instance objects
+ * @public
+ */
+ instancesLatest: function() {
+ return this.__instancesLatestArr;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_off() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ off: function() {
+ this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_on() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ on: function() {
+ this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_one() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ one: function() {
+ this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Returns all HTML elements which have one or more tooltips
+ *
+ * @param {string} selector optional Use this to restrict the results
+ * to the descendants of an element
+ * @return {array} An array of HTML elements
+ * @public
+ */
+ origins: function(selector) {
+
+ var sel = selector ?
+ selector +' ' :
+ '';
+
+ return $(sel +'.tooltipstered').toArray();
+ },
+
+ /**
+ * Change default options for all future instances
+ *
+ * @param {object} d The options that should be made defaults
+ * @return {core}
+ * @public
+ */
+ setDefaults: function(d) {
+ $.extend(defaults, d);
+ return this;
+ },
+
+ /**
+ * For users to trigger their handlers on the public emitter
+ *
+ * @returns {core}
+ * @public
+ */
+ triggerHandler: function() {
+ this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ }
+};
+
+// $.tooltipster will be used to call core methods
+$.tooltipster = new core();
+
+// the Tooltipster instance class (mind the capital T)
+$.Tooltipster = function(element, options) {
+
+ // list of instance variables
+
+ // stack of custom callbacks provided as parameters to API methods
+ this.__callbacks = {
+ close: [],
+ open: []
+ };
+ // the schedule time of DOM removal
+ this.__closingTime;
+ // this will be the user content shown in the tooltip. A capital "C" is used
+ // because there is also a method called content()
+ this.__Content;
+ // for the size tracker
+ this.__contentBcr;
+ // to disable the tooltip after destruction
+ this.__destroyed = false;
+ // we can't emit directly on the instance because if a method with the same
+ // name as the event exists, it will be called by jQuery. Se we use a plain
+ // object as emitter. This emitter is for internal use by plugins,
+ // if needed.
+ this.__$emitterPrivate = $({});
+ // this emitter is for the user to listen to events without risking to mess
+ // with our internal listeners
+ this.__$emitterPublic = $({});
+ this.__enabled = true;
+ // the reference to the gc interval
+ this.__garbageCollector;
+ // various position and size data recomputed before each repositioning
+ this.__Geometry;
+ // the tooltip position, saved after each repositioning by a plugin
+ this.__lastPosition;
+ // a unique namespace per instance
+ this.__namespace = 'tooltipster-'+ Math.round(Math.random()*1000000);
+ this.__options;
+ // will be used to support origins in scrollable areas
+ this.__$originParents;
+ this.__pointerIsOverOrigin = false;
+ // to remove themes if needed
+ this.__previousThemes = [];
+ // the state can be either: appearing, stable, disappearing, closed
+ this.__state = 'closed';
+ // timeout references
+ this.__timeouts = {
+ close: [],
+ open: null
+ };
+ // store touch events to be able to detect emulated mouse events
+ this.__touchEvents = [];
+ // the reference to the tracker interval
+ this.__tracker = null;
+ // the element to which this tooltip is associated
+ this._$origin;
+ // this will be the tooltip element (jQuery wrapped HTML element).
+ // It's the job of a plugin to create it and append it to the DOM
+ this._$tooltip;
+
+ // launch
+ this.__init(element, options);
+};
+
+$.Tooltipster.prototype = {
+
+ /**
+ * @param origin
+ * @param options
+ * @private
+ */
+ __init: function(origin, options) {
+
+ var self = this;
+
+ self._$origin = $(origin);
+ self.__options = $.extend(true, {}, defaults, options);
+
+ // some options may need to be reformatted
+ self.__optionsFormat();
+
+ // don't run on old IE if asked no to
+ if ( !env.IE
+ || env.IE >= self.__options.IEmin
+ ) {
+
+ // note: the content is null (empty) by default and can stay that
+ // way if the plugin remains initialized but not fed any content. The
+ // tooltip will just not appear.
+
+ // let's save the initial value of the title attribute for later
+ // restoration if need be.
+ var initialTitle = null;
+
+ // it will already have been saved in case of multiple tooltips
+ if (self._$origin.data('tooltipster-initialTitle') === undefined) {
+
+ initialTitle = self._$origin.attr('title');
+
+ // we do not want initialTitle to be "undefined" because
+ // of how jQuery's .data() method works
+ if (initialTitle === undefined) initialTitle = null;
+
+ self._$origin.data('tooltipster-initialTitle', initialTitle);
+ }
+
+ // If content is provided in the options, it has precedence over the
+ // title attribute.
+ // Note: an empty string is considered content, only 'null' represents
+ // the absence of content.
+ // Also, an existing title="" attribute will result in an empty string
+ // content
+ if (self.__options.content !== null) {
+ self.__contentSet(self.__options.content);
+ }
+ else {
+
+ var selector = self._$origin.attr('data-tooltip-content'),
+ $el;
+
+ if (selector){
+ $el = $(selector);
+ }
+
+ if ($el && $el[0]) {
+ self.__contentSet($el.first());
+ }
+ else {
+ self.__contentSet(initialTitle);
+ }
+ }
+
+ self._$origin
+ // strip the title off of the element to prevent the default tooltips
+ // from popping up
+ .removeAttr('title')
+ // to be able to find all instances on the page later (upon window
+ // events in particular)
+ .addClass('tooltipstered');
+
+ // set listeners on the origin
+ self.__prepareOrigin();
+
+ // set the garbage collector
+ self.__prepareGC();
+
+ // init plugins
+ $.each(self.__options.plugins, function(i, pluginName) {
+ self._plug(pluginName);
+ });
+
+ // to detect swiping
+ if (env.hasTouchCapability) {
+ $(env.window.document.body).on('touchmove.'+ self.__namespace +'-triggerOpen', function(event) {
+ self._touchRecordEvent(event);
+ });
+ }
+
+ self
+ // prepare the tooltip when it gets created. This event must
+ // be fired by a plugin
+ ._on('created', function() {
+ self.__prepareTooltip();
+ })
+ // save position information when it's sent by a plugin
+ ._on('repositioned', function(e) {
+ self.__lastPosition = e.position;
+ });
+ }
+ else {
+ self.__options.disabled = true;
+ }
+ },
+
+ /**
+ * Insert the content into the appropriate HTML element of the tooltip
+ *
+ * @returns {self}
+ * @private
+ */
+ __contentInsert: function() {
+
+ var self = this,
+ $el = self._$tooltip.find('.tooltipster-content'),
+ formattedContent = self.__Content,
+ format = function(content) {
+ formattedContent = content;
+ };
+
+ self._trigger({
+ type: 'format',
+ content: self.__Content,
+ format: format
+ });
+
+ if (self.__options.functionFormat) {
+
+ formattedContent = self.__options.functionFormat.call(
+ self,
+ self,
+ { origin: self._$origin[0] },
+ self.__Content
+ );
+ }
+
+ if (typeof formattedContent === 'string' && !self.__options.contentAsHTML) {
+ $el.text(formattedContent);
+ }
+ else {
+ $el
+ .empty()
+ .append(formattedContent);
+ }
+
+ return self;
+ },
+
+ /**
+ * Save the content, cloning it beforehand if need be
+ *
+ * @param content
+ * @returns {self}
+ * @private
+ */
+ __contentSet: function(content) {
+
+ // clone if asked. Cloning the object makes sure that each instance has its
+ // own version of the content (in case a same object were provided for several
+ // instances)
+ // reminder: typeof null === object
+ if (content instanceof $ && this.__options.contentCloning) {
+ content = content.clone(true);
+ }
+
+ this.__Content = content;
+
+ this._trigger({
+ type: 'updated',
+ content: content
+ });
+
+ return this;
+ },
+
+ /**
+ * Error message about a method call made after destruction
+ *
+ * @private
+ */
+ __destroyError: function() {
+ throw new Error('This tooltip has been destroyed and cannot execute your method call.');
+ },
+
+ /**
+ * Gather all information about dimensions and available space,
+ * called before every repositioning
+ *
+ * @private
+ * @returns {object}
+ */
+ __geometry: function() {
+
+ var self = this,
+ $target = self._$origin,
+ originIsArea = self._$origin.is('area');
+
+ // if this._$origin is a map area, the target we'll need
+ // the dimensions of is actually the image using the map,
+ // not the area itself
+ if (originIsArea) {
+
+ var mapName = self._$origin.parent().attr('name');
+
+ $target = $('img[usemap="#'+ mapName +'"]');
+ }
+
+ var bcr = $target[0].getBoundingClientRect(),
+ $document = $(env.window.document),
+ $window = $(env.window),
+ $parent = $target,
+ // some useful properties of important elements
+ geo = {
+ // available space for the tooltip, see down below
+ available: {
+ document: null,
+ window: null
+ },
+ document: {
+ size: {
+ height: $document.height(),
+ width: $document.width()
+ }
+ },
+ window: {
+ scroll: {
+ // the second ones are for IE compatibility
+ left: env.window.scrollX || env.window.document.documentElement.scrollLeft,
+ top: env.window.scrollY || env.window.document.documentElement.scrollTop
+ },
+ size: {
+ height: $window.height(),
+ width: $window.width()
+ }
+ },
+ origin: {
+ // the origin has a fixed lineage if itself or one of its
+ // ancestors has a fixed position
+ fixedLineage: false,
+ // relative to the document
+ offset: {},
+ size: {
+ height: bcr.bottom - bcr.top,
+ width: bcr.right - bcr.left
+ },
+ usemapImage: originIsArea ? $target[0] : null,
+ // relative to the window
+ windowOffset: {
+ bottom: bcr.bottom,
+ left: bcr.left,
+ right: bcr.right,
+ top: bcr.top
+ }
+ }
+ },
+ geoFixed = false;
+
+ // if the element is a map area, some properties may need
+ // to be recalculated
+ if (originIsArea) {
+
+ var shape = self._$origin.attr('shape'),
+ coords = self._$origin.attr('coords');
+
+ if (coords) {
+
+ coords = coords.split(',');
+
+ $.map(coords, function(val, i) {
+ coords[i] = parseInt(val);
+ });
+ }
+
+ // if the image itself is the area, nothing more to do
+ if (shape != 'default') {
+
+ switch(shape) {
+
+ case 'circle':
+
+ var circleCenterLeft = coords[0],
+ circleCenterTop = coords[1],
+ circleRadius = coords[2],
+ areaTopOffset = circleCenterTop - circleRadius,
+ areaLeftOffset = circleCenterLeft - circleRadius;
+
+ geo.origin.size.height = circleRadius * 2;
+ geo.origin.size.width = geo.origin.size.height;
+
+ geo.origin.windowOffset.left += areaLeftOffset;
+ geo.origin.windowOffset.top += areaTopOffset;
+
+ break;
+
+ case 'rect':
+
+ var areaLeft = coords[0],
+ areaTop = coords[1],
+ areaRight = coords[2],
+ areaBottom = coords[3];
+
+ geo.origin.size.height = areaBottom - areaTop;
+ geo.origin.size.width = areaRight - areaLeft;
+
+ geo.origin.windowOffset.left += areaLeft;
+ geo.origin.windowOffset.top += areaTop;
+
+ break;
+
+ case 'poly':
+
+ var areaSmallestX = 0,
+ areaSmallestY = 0,
+ areaGreatestX = 0,
+ areaGreatestY = 0,
+ arrayAlternate = 'even';
+
+ for (var i = 0; i < coords.length; i++) {
+
+ var areaNumber = coords[i];
+
+ if (arrayAlternate == 'even') {
+
+ if (areaNumber > areaGreatestX) {
+
+ areaGreatestX = areaNumber;
+
+ if (i === 0) {
+ areaSmallestX = areaGreatestX;
+ }
+ }
+
+ if (areaNumber < areaSmallestX) {
+ areaSmallestX = areaNumber;
+ }
+
+ arrayAlternate = 'odd';
+ }
+ else {
+ if (areaNumber > areaGreatestY) {
+
+ areaGreatestY = areaNumber;
+
+ if (i == 1) {
+ areaSmallestY = areaGreatestY;
+ }
+ }
+
+ if (areaNumber < areaSmallestY) {
+ areaSmallestY = areaNumber;
+ }
+
+ arrayAlternate = 'even';
+ }
+ }
+
+ geo.origin.size.height = areaGreatestY - areaSmallestY;
+ geo.origin.size.width = areaGreatestX - areaSmallestX;
+
+ geo.origin.windowOffset.left += areaSmallestX;
+ geo.origin.windowOffset.top += areaSmallestY;
+
+ break;
+ }
+ }
+ }
+
+ // user callback through an event
+ var edit = function(r) {
+ geo.origin.size.height = r.height,
+ geo.origin.windowOffset.left = r.left,
+ geo.origin.windowOffset.top = r.top,
+ geo.origin.size.width = r.width
+ };
+
+ self._trigger({
+ type: 'geometry',
+ edit: edit,
+ geometry: {
+ height: geo.origin.size.height,
+ left: geo.origin.windowOffset.left,
+ top: geo.origin.windowOffset.top,
+ width: geo.origin.size.width
+ }
+ });
+
+ // calculate the remaining properties with what we got
+
+ geo.origin.windowOffset.right = geo.origin.windowOffset.left + geo.origin.size.width;
+ geo.origin.windowOffset.bottom = geo.origin.windowOffset.top + geo.origin.size.height;
+
+ geo.origin.offset.left = geo.origin.windowOffset.left + geo.window.scroll.left;
+ geo.origin.offset.top = geo.origin.windowOffset.top + geo.window.scroll.top;
+ geo.origin.offset.bottom = geo.origin.offset.top + geo.origin.size.height;
+ geo.origin.offset.right = geo.origin.offset.left + geo.origin.size.width;
+
+ // the space that is available to display the tooltip relatively to the document
+ geo.available.document = {
+ bottom: {
+ height: geo.document.size.height - geo.origin.offset.bottom,
+ width: geo.document.size.width
+ },
+ left: {
+ height: geo.document.size.height,
+ width: geo.origin.offset.left
+ },
+ right: {
+ height: geo.document.size.height,
+ width: geo.document.size.width - geo.origin.offset.right
+ },
+ top: {
+ height: geo.origin.offset.top,
+ width: geo.document.size.width
+ }
+ };
+
+ // the space that is available to display the tooltip relatively to the viewport
+ // (the resulting values may be negative if the origin overflows the viewport)
+ geo.available.window = {
+ bottom: {
+ // the inner max is here to make sure the available height is no bigger
+ // than the viewport height (when the origin is off screen at the top).
+ // The outer max just makes sure that the height is not negative (when
+ // the origin overflows at the bottom).
+ height: Math.max(geo.window.size.height - Math.max(geo.origin.windowOffset.bottom, 0), 0),
+ width: geo.window.size.width
+ },
+ left: {
+ height: geo.window.size.height,
+ width: Math.max(geo.origin.windowOffset.left, 0)
+ },
+ right: {
+ height: geo.window.size.height,
+ width: Math.max(geo.window.size.width - Math.max(geo.origin.windowOffset.right, 0), 0)
+ },
+ top: {
+ height: Math.max(geo.origin.windowOffset.top, 0),
+ width: geo.window.size.width
+ }
+ };
+
+ while ($parent[0].tagName.toLowerCase() != 'html') {
+
+ if ($parent.css('position') == 'fixed') {
+ geo.origin.fixedLineage = true;
+ break;
+ }
+
+ $parent = $parent.parent();
+ }
+
+ return geo;
+ },
+
+ /**
+ * Some options may need to be formated before being used
+ *
+ * @returns {self}
+ * @private
+ */
+ __optionsFormat: function() {
+
+ if (typeof this.__options.animationDuration == 'number') {
+ this.__options.animationDuration = [this.__options.animationDuration, this.__options.animationDuration];
+ }
+
+ if (typeof this.__options.delay == 'number') {
+ this.__options.delay = [this.__options.delay, this.__options.delay];
+ }
+
+ if (typeof this.__options.delayTouch == 'number') {
+ this.__options.delayTouch = [this.__options.delayTouch, this.__options.delayTouch];
+ }
+
+ if (typeof this.__options.theme == 'string') {
+ this.__options.theme = [this.__options.theme];
+ }
+
+ // determine the future parent
+ if (this.__options.parent === null) {
+ this.__options.parent = $(env.window.document.body);
+ }
+ else if (typeof this.__options.parent == 'string') {
+ this.__options.parent = $(this.__options.parent);
+ }
+
+ if (this.__options.trigger == 'hover') {
+
+ this.__options.triggerOpen = {
+ mouseenter: true,
+ touchstart: true
+ };
+
+ this.__options.triggerClose = {
+ mouseleave: true,
+ originClick: true,
+ touchleave: true
+ };
+ }
+ else if (this.__options.trigger == 'click') {
+
+ this.__options.triggerOpen = {
+ click: true,
+ tap: true
+ };
+
+ this.__options.triggerClose = {
+ click: true,
+ tap: true
+ };
+ }
+
+ // for the plugins
+ this._trigger('options');
+
+ return this;
+ },
+
+ /**
+ * Schedules or cancels the garbage collector task
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareGC: function() {
+
+ var self = this;
+
+ // in case the selfDestruction option has been changed by a method call
+ if (self.__options.selfDestruction) {
+
+ // the GC task
+ self.__garbageCollector = setInterval(function() {
+
+ var now = new Date().getTime();
+
+ // forget the old events
+ self.__touchEvents = $.grep(self.__touchEvents, function(event, i) {
+ // 1 minute
+ return now - event.time > 60000;
+ });
+
+ // auto-destruct if the origin is gone
+ if (!bodyContains(self._$origin)) {
+
+ self.close(function(){
+ self.destroy();
+ });
+ }
+ }, 20000);
+ }
+ else {
+ clearInterval(self.__garbageCollector);
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets listeners on the origin if the open triggers require them.
+ * Unlike the listeners set at opening time, these ones
+ * remain even when the tooltip is closed. It has been made a
+ * separate method so it can be called when the triggers are
+ * changed in the options. Closing is handled in _open()
+ * because of the bindings that may be needed on the tooltip
+ * itself
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareOrigin: function() {
+
+ var self = this;
+
+ // in case we're resetting the triggers
+ self._$origin.off('.'+ self.__namespace +'-triggerOpen');
+
+ // if the device is touch capable, even if only mouse triggers
+ // are asked, we need to listen to touch events to know if the mouse
+ // events are actually emulated (so we can ignore them)
+ if (env.hasTouchCapability) {
+
+ self._$origin.on(
+ 'touchstart.'+ self.__namespace +'-triggerOpen ' +
+ 'touchend.'+ self.__namespace +'-triggerOpen ' +
+ 'touchcancel.'+ self.__namespace +'-triggerOpen',
+ function(event){
+ self._touchRecordEvent(event);
+ }
+ );
+ }
+
+ // mouse click and touch tap work the same way
+ if ( self.__options.triggerOpen.click
+ || (self.__options.triggerOpen.tap && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerOpen.click) {
+ eventNames += 'click.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerOpen.tap && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+ if (self._touchIsMeaningfulEvent(event)) {
+ self._open(event);
+ }
+ });
+ }
+
+ // mouseenter and touch start work the same way
+ if ( self.__options.triggerOpen.mouseenter
+ || (self.__options.triggerOpen.touchstart && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerOpen.mouseenter) {
+ eventNames += 'mouseenter.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerOpen.touchstart && env.hasTouchCapability) {
+ eventNames += 'touchstart.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+ self.__pointerIsOverOrigin = true;
+ self._openShortly(event);
+ }
+ });
+ }
+
+ // info for the mouseleave/touchleave close triggers when they use a delay
+ if ( self.__options.triggerClose.mouseleave
+ || (self.__options.triggerClose.touchleave && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerClose.mouseleave) {
+ eventNames += 'mouseleave.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerClose.touchleave && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerOpen touchcancel.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+
+ if (self._touchIsMeaningfulEvent(event)) {
+ self.__pointerIsOverOrigin = false;
+ }
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Do the things that need to be done only once after the tooltip
+ * HTML element it has been created. It has been made a separate
+ * method so it can be called when options are changed. Remember
+ * that the tooltip may actually exist in the DOM before it is
+ * opened, and present after it has been closed: it's the display
+ * plugin that takes care of handling it.
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareTooltip: function() {
+
+ var self = this,
+ p = self.__options.interactive ? 'auto' : '';
+
+ // this will be useful to know quickly if the tooltip is in
+ // the DOM or not
+ self._$tooltip
+ .attr('id', self.__namespace)
+ .css({
+ // pointer events
+ 'pointer-events': p,
+ zIndex: self.__options.zIndex
+ });
+
+ // themes
+ // remove the old ones and add the new ones
+ $.each(self.__previousThemes, function(i, theme) {
+ self._$tooltip.removeClass(theme);
+ });
+ $.each(self.__options.theme, function(i, theme) {
+ self._$tooltip.addClass(theme);
+ });
+
+ self.__previousThemes = $.merge([], self.__options.theme);
+
+ return self;
+ },
+
+ /**
+ * Handles the scroll on any of the parents of the origin (when the
+ * tooltip is open)
+ *
+ * @param {object} event
+ * @returns {self}
+ * @private
+ */
+ __scrollHandler: function(event) {
+
+ var self = this;
+
+ if (self.__options.triggerClose.scroll) {
+ self._close(event);
+ }
+ else {
+
+ // if the origin or tooltip have been removed: do nothing, the tracker will
+ // take care of it later
+ if (bodyContains(self._$origin) && bodyContains(self._$tooltip)) {
+
+ var geo = null;
+
+ // if the scroll happened on the window
+ if (event.target === env.window.document) {
+
+ // if the origin has a fixed lineage, window scroll will have no
+ // effect on its position nor on the position of the tooltip
+ if (!self.__Geometry.origin.fixedLineage) {
+
+ // we don't need to do anything unless repositionOnScroll is true
+ // because the tooltip will already have moved with the window
+ // (and of course with the origin)
+ if (self.__options.repositionOnScroll) {
+ self.reposition(event);
+ }
+ }
+ }
+ // if the scroll happened on another parent of the tooltip, it means
+ // that it's in a scrollable area and now needs to have its position
+ // adjusted or recomputed, depending ont the repositionOnScroll
+ // option. Also, if the origin is partly hidden due to a parent that
+ // hides its overflow, we'll just hide (not close) the tooltip.
+ else {
+
+ geo = self.__geometry();
+
+ var overflows = false;
+
+ // a fixed position origin is not affected by the overflow hiding
+ // of a parent
+ if (self._$origin.css('position') != 'fixed') {
+
+ self.__$originParents.each(function(i, el) {
+
+ var $el = $(el),
+ overflowX = $el.css('overflow-x'),
+ overflowY = $el.css('overflow-y');
+
+ if (overflowX != 'visible' || overflowY != 'visible') {
+
+ var bcr = el.getBoundingClientRect();
+
+ if (overflowX != 'visible') {
+
+ if ( geo.origin.windowOffset.left < bcr.left
+ || geo.origin.windowOffset.right > bcr.right
+ ) {
+ overflows = true;
+ return false;
+ }
+ }
+
+ if (overflowY != 'visible') {
+
+ if ( geo.origin.windowOffset.top < bcr.top
+ || geo.origin.windowOffset.bottom > bcr.bottom
+ ) {
+ overflows = true;
+ return false;
+ }
+ }
+ }
+
+ // no need to go further if fixed, for the same reason as above
+ if ($el.css('position') == 'fixed') {
+ return false;
+ }
+ });
+ }
+
+ if (overflows) {
+ self._$tooltip.css('visibility', 'hidden');
+ }
+ else {
+
+ self._$tooltip.css('visibility', 'visible');
+
+ // reposition
+ if (self.__options.repositionOnScroll) {
+ self.reposition(event);
+ }
+ // or just adjust offset
+ else {
+
+ // we have to use offset and not windowOffset because this way,
+ // only the scroll distance of the scrollable areas are taken into
+ // account (the scrolltop value of the main window must be
+ // ignored since the tooltip already moves with it)
+ var offsetLeft = geo.origin.offset.left - self.__Geometry.origin.offset.left,
+ offsetTop = geo.origin.offset.top - self.__Geometry.origin.offset.top;
+
+ // add the offset to the position initially computed by the display plugin
+ self._$tooltip.css({
+ left: self.__lastPosition.coord.left + offsetLeft,
+ top: self.__lastPosition.coord.top + offsetTop
+ });
+ }
+ }
+ }
+
+ self._trigger({
+ type: 'scroll',
+ event: event,
+ geo: geo
+ });
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Changes the state of the tooltip
+ *
+ * @param {string} state
+ * @returns {self}
+ * @private
+ */
+ __stateSet: function(state) {
+
+ this.__state = state;
+
+ this._trigger({
+ type: 'state',
+ state: state
+ });
+
+ return this;
+ },
+
+ /**
+ * Clear appearance timeouts
+ *
+ * @returns {self}
+ * @private
+ */
+ __timeoutsClear: function() {
+
+ // there is only one possible open timeout: the delayed opening
+ // when the mouseenter/touchstart open triggers are used
+ clearTimeout(this.__timeouts.open);
+ this.__timeouts.open = null;
+
+ // ... but several close timeouts: the delayed closing when the
+ // mouseleave close trigger is used and the timer option
+ $.each(this.__timeouts.close, function(i, timeout) {
+ clearTimeout(timeout);
+ });
+ this.__timeouts.close = [];
+
+ return this;
+ },
+
+ /**
+ * Start the tracker that will make checks at regular intervals
+ *
+ * @returns {self}
+ * @private
+ */
+ __trackerStart: function() {
+
+ var self = this,
+ $content = self._$tooltip.find('.tooltipster-content');
+
+ // get the initial content size
+ if (self.__options.trackTooltip) {
+ self.__contentBcr = $content[0].getBoundingClientRect();
+ }
+
+ self.__tracker = setInterval(function() {
+
+ // if the origin or tooltip elements have been removed.
+ // Note: we could destroy the instance now if the origin has
+ // been removed but we'll leave that task to our garbage collector
+ if (!bodyContains(self._$origin) || !bodyContains(self._$tooltip)) {
+ self._close();
+ }
+ // if everything is alright
+ else {
+
+ // compare the former and current positions of the origin to reposition
+ // the tooltip if need be
+ if (self.__options.trackOrigin) {
+
+ var g = self.__geometry(),
+ identical = false;
+
+ // compare size first (a change requires repositioning too)
+ if (areEqual(g.origin.size, self.__Geometry.origin.size)) {
+
+ // for elements that have a fixed lineage (see __geometry()), we track the
+ // top and left properties (relative to window)
+ if (self.__Geometry.origin.fixedLineage) {
+ if (areEqual(g.origin.windowOffset, self.__Geometry.origin.windowOffset)) {
+ identical = true;
+ }
+ }
+ // otherwise, track total offset (relative to document)
+ else {
+ if (areEqual(g.origin.offset, self.__Geometry.origin.offset)) {
+ identical = true;
+ }
+ }
+ }
+
+ if (!identical) {
+
+ // close the tooltip when using the mouseleave close trigger
+ // (see https://github.com/iamceege/tooltipster/pull/253)
+ if (self.__options.triggerClose.mouseleave) {
+ self._close();
+ }
+ else {
+ self.reposition();
+ }
+ }
+ }
+
+ if (self.__options.trackTooltip) {
+
+ var currentBcr = $content[0].getBoundingClientRect();
+
+ if ( currentBcr.height !== self.__contentBcr.height
+ || currentBcr.width !== self.__contentBcr.width
+ ) {
+ self.reposition();
+ self.__contentBcr = currentBcr;
+ }
+ }
+ }
+ }, self.__options.trackerInterval);
+
+ return self;
+ },
+
+ /**
+ * Closes the tooltip (after the closing delay)
+ *
+ * @param event
+ * @param callback
+ * @param force Set to true to override a potential refusal of the user's function
+ * @returns {self}
+ * @protected
+ */
+ _close: function(event, callback, force) {
+
+ var self = this,
+ ok = true;
+
+ self._trigger({
+ type: 'close',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ // a destroying tooltip (force == true) may not refuse to close
+ if (ok || force) {
+
+ // save the method custom callback and cancel any open method custom callbacks
+ if (callback) self.__callbacks.close.push(callback);
+ self.__callbacks.open = [];
+
+ // clear open/close timeouts
+ self.__timeoutsClear();
+
+ var finishCallbacks = function() {
+
+ // trigger any close method custom callbacks and reset them
+ $.each(self.__callbacks.close, function(i,c) {
+ c.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ });
+
+ self.__callbacks.close = [];
+ };
+
+ if (self.__state != 'closed') {
+
+ var necessary = true,
+ d = new Date(),
+ now = d.getTime(),
+ newClosingTime = now + self.__options.animationDuration[1];
+
+ // the tooltip may already already be disappearing, but if a new
+ // call to close() is made after the animationDuration was changed
+ // to 0 (for example), we ought to actually close it sooner than
+ // previously scheduled. In that case it should be noted that the
+ // browser will not adapt the animation duration to the new
+ // animationDuration that was set after the start of the closing
+ // animation.
+ // Note: the same thing could be considered at opening, but is not
+ // really useful since the tooltip is actually opened immediately
+ // upon a call to _open(). Since it would not make the opening
+ // animation finish sooner, its sole impact would be to trigger the
+ // state event and the open callbacks sooner than the actual end of
+ // the opening animation, which is not great.
+ if (self.__state == 'disappearing') {
+
+ if ( newClosingTime > self.__closingTime
+ // in case closing is actually overdue because the script
+ // execution was suspended. See #679
+ && self.__options.animationDuration[1] > 0
+ ) {
+ necessary = false;
+ }
+ }
+
+ if (necessary) {
+
+ self.__closingTime = newClosingTime;
+
+ if (self.__state != 'disappearing') {
+ self.__stateSet('disappearing');
+ }
+
+ var finish = function() {
+
+ // stop the tracker
+ clearInterval(self.__tracker);
+
+ // a "beforeClose" option has been asked several times but would
+ // probably useless since the content element is still accessible
+ // via ::content(), and because people can always use listeners
+ // inside their content to track what's going on. For the sake of
+ // simplicity, this has been denied. Bur for the rare people who
+ // really need the option (for old browsers or for the case where
+ // detaching the content is actually destructive, for file or
+ // password inputs for example), this event will do the work.
+ self._trigger({
+ type: 'closing',
+ event: event
+ });
+
+ // unbind listeners which are no longer needed
+
+ self._$tooltip
+ .off('.'+ self.__namespace +'-triggerClose')
+ .removeClass('tooltipster-dying');
+
+ // orientationchange, scroll and resize listeners
+ $(env.window).off('.'+ self.__namespace +'-triggerClose');
+
+ // scroll listeners
+ self.__$originParents.each(function(i, el) {
+ $(el).off('scroll.'+ self.__namespace +'-triggerClose');
+ });
+ // clear the array to prevent memory leaks
+ self.__$originParents = null;
+
+ $(env.window.document.body).off('.'+ self.__namespace +'-triggerClose');
+
+ self._$origin.off('.'+ self.__namespace +'-triggerClose');
+
+ self._off('dismissable');
+
+ // a plugin that would like to remove the tooltip from the
+ // DOM when closed should bind on this
+ self.__stateSet('closed');
+
+ // trigger event
+ self._trigger({
+ type: 'after',
+ event: event
+ });
+
+ // call our constructor custom callback function
+ if (self.__options.functionAfter) {
+ self.__options.functionAfter.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ }
+
+ // call our method custom callbacks functions
+ finishCallbacks();
+ };
+
+ if (env.hasTransitions) {
+
+ self._$tooltip.css({
+ '-moz-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-ms-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-o-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-webkit-animation-duration': self.__options.animationDuration[1] + 'ms',
+ 'animation-duration': self.__options.animationDuration[1] + 'ms',
+ 'transition-duration': self.__options.animationDuration[1] + 'ms'
+ });
+
+ self._$tooltip
+ // clear both potential open and close tasks
+ .clearQueue()
+ .removeClass('tooltipster-show')
+ // for transitions only
+ .addClass('tooltipster-dying');
+
+ if (self.__options.animationDuration[1] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[1]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ else {
+
+ self._$tooltip
+ .stop()
+ .fadeOut(self.__options.animationDuration[1], finish);
+ }
+ }
+ }
+ // if the tooltip is already closed, we still need to trigger
+ // the method custom callbacks
+ else {
+ finishCallbacks();
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _off: function() {
+ this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _on: function() {
+ this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _one: function() {
+ this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Opens the tooltip right away.
+ *
+ * @param event
+ * @param callback Will be called when the opening animation is over
+ * @returns {self}
+ * @protected
+ */
+ _open: function(event, callback) {
+
+ var self = this;
+
+ // if the destruction process has not begun and if this was not
+ // triggered by an unwanted emulated click event
+ if (!self.__destroying) {
+
+ // check that the origin is still in the DOM
+ if ( bodyContains(self._$origin)
+ // if the tooltip is enabled
+ && self.__enabled
+ ) {
+
+ var ok = true;
+
+ // if the tooltip is not open yet, we need to call functionBefore.
+ // otherwise we can jst go on
+ if (self.__state == 'closed') {
+
+ // trigger an event. The event.stop function allows the callback
+ // to prevent the opening of the tooltip
+ self._trigger({
+ type: 'before',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ if (ok && self.__options.functionBefore) {
+
+ // call our custom function before continuing
+ ok = self.__options.functionBefore.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ }
+ }
+
+ if (ok !== false) {
+
+ // if there is some content
+ if (self.__Content !== null) {
+
+ // save the method callback and cancel close method callbacks
+ if (callback) {
+ self.__callbacks.open.push(callback);
+ }
+ self.__callbacks.close = [];
+
+ // get rid of any appearance timeouts
+ self.__timeoutsClear();
+
+ var extraTime,
+ finish = function() {
+
+ if (self.__state != 'stable') {
+ self.__stateSet('stable');
+ }
+
+ // trigger any open method custom callbacks and reset them
+ $.each(self.__callbacks.open, function(i,c) {
+ c.call(self, self, {
+ origin: self._$origin[0],
+ tooltip: self._$tooltip[0]
+ });
+ });
+
+ self.__callbacks.open = [];
+ };
+
+ // if the tooltip is already open
+ if (self.__state !== 'closed') {
+
+ // the timer (if any) will start (or restart) right now
+ extraTime = 0;
+
+ // if it was disappearing, cancel that
+ if (self.__state === 'disappearing') {
+
+ self.__stateSet('appearing');
+
+ if (env.hasTransitions) {
+
+ self._$tooltip
+ .clearQueue()
+ .removeClass('tooltipster-dying')
+ .addClass('tooltipster-show');
+
+ if (self.__options.animationDuration[0] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[0]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ else {
+ // in case the tooltip was currently fading out, bring it back
+ // to life
+ self._$tooltip
+ .stop()
+ .fadeIn(finish);
+ }
+ }
+ // if the tooltip is already open, we still need to trigger the method
+ // custom callback
+ else if (self.__state == 'stable') {
+ finish();
+ }
+ }
+ // if the tooltip isn't already open, open it
+ else {
+
+ // a plugin must bind on this and store the tooltip in this._$tooltip
+ self.__stateSet('appearing');
+
+ // the timer (if any) will start when the tooltip has fully appeared
+ // after its transition
+ extraTime = self.__options.animationDuration[0];
+
+ // insert the content inside the tooltip
+ self.__contentInsert();
+
+ // reposition the tooltip and attach to the DOM
+ self.reposition(event, true);
+
+ // animate in the tooltip. If the display plugin wants no css
+ // animations, it may override the animation option with a
+ // dummy value that will produce no effect
+ if (env.hasTransitions) {
+
+ // note: there seems to be an issue with start animations which
+ // are randomly not played on fast devices in both Chrome and FF,
+ // couldn't find a way to solve it yet. It seems that applying
+ // the classes before appending to the DOM helps a little, but
+ // it messes up some CSS transitions. The issue almost never
+ // happens when delay[0]==0 though
+ self._$tooltip
+ .addClass('tooltipster-'+ self.__options.animation)
+ .addClass('tooltipster-initial')
+ .css({
+ '-moz-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-ms-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-o-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-webkit-animation-duration': self.__options.animationDuration[0] + 'ms',
+ 'animation-duration': self.__options.animationDuration[0] + 'ms',
+ 'transition-duration': self.__options.animationDuration[0] + 'ms'
+ });
+
+ setTimeout(
+ function() {
+
+ // a quick hover may have already triggered a mouseleave
+ if (self.__state != 'closed') {
+
+ self._$tooltip
+ .addClass('tooltipster-show')
+ .removeClass('tooltipster-initial');
+
+ if (self.__options.animationDuration[0] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[0]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ },
+ 0
+ );
+ }
+ else {
+
+ // old browsers will have to live with this
+ self._$tooltip
+ .css('display', 'none')
+ .fadeIn(self.__options.animationDuration[0], finish);
+ }
+
+ // checks if the origin is removed while the tooltip is open
+ self.__trackerStart();
+
+ // NOTE: the listeners below have a '-triggerClose' namespace
+ // because we'll remove them when the tooltip closes (unlike
+ // the '-triggerOpen' listeners). So some of them are actually
+ // not about close triggers, rather about positioning.
+
+ $(env.window)
+ // reposition on resize
+ .on('resize.'+ self.__namespace +'-triggerClose', function(e) {
+
+ var $ae = $(document.activeElement);
+
+ // reposition only if the resize event was not triggered upon the opening
+ // of a virtual keyboard due to an input field being focused within the tooltip
+ // (otherwise the repositioning would lose the focus)
+ if ( (!$ae.is('input') && !$ae.is('textarea'))
+ || !$.contains(self._$tooltip[0], $ae[0])
+ ) {
+ self.reposition(e);
+ }
+ })
+ // same as below for parents
+ .on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
+ self.__scrollHandler(e);
+ });
+
+ self.__$originParents = self._$origin.parents();
+
+ // scrolling may require the tooltip to be moved or even
+ // repositioned in some cases
+ self.__$originParents.each(function(i, parent) {
+
+ $(parent).on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
+ self.__scrollHandler(e);
+ });
+ });
+
+ if ( self.__options.triggerClose.mouseleave
+ || (self.__options.triggerClose.touchleave && env.hasTouchCapability)
+ ) {
+
+ // we use an event to allow users/plugins to control when the mouseleave/touchleave
+ // close triggers will come to action. It allows to have more triggering elements
+ // than just the origin and the tooltip for example, or to cancel/delay the closing,
+ // or to make the tooltip interactive even if it wasn't when it was open, etc.
+ self._on('dismissable', function(event) {
+
+ if (event.dismissable) {
+
+ if (event.delay) {
+
+ timeout = setTimeout(function() {
+ // event.event may be undefined
+ self._close(event.event);
+ }, event.delay);
+
+ self.__timeouts.close.push(timeout);
+ }
+ else {
+ self._close(event);
+ }
+ }
+ else {
+ clearTimeout(timeout);
+ }
+ });
+
+ // now set the listeners that will trigger 'dismissable' events
+ var $elements = self._$origin,
+ eventNamesIn = '',
+ eventNamesOut = '',
+ timeout = null;
+
+ // if we have to allow interaction, bind on the tooltip too
+ if (self.__options.interactive) {
+ $elements = $elements.add(self._$tooltip);
+ }
+
+ if (self.__options.triggerClose.mouseleave) {
+ eventNamesIn += 'mouseenter.'+ self.__namespace +'-triggerClose ';
+ eventNamesOut += 'mouseleave.'+ self.__namespace +'-triggerClose ';
+ }
+ if (self.__options.triggerClose.touchleave && env.hasTouchCapability) {
+ eventNamesIn += 'touchstart.'+ self.__namespace +'-triggerClose';
+ eventNamesOut += 'touchend.'+ self.__namespace +'-triggerClose touchcancel.'+ self.__namespace +'-triggerClose';
+ }
+
+ $elements
+ // close after some time spent outside of the elements
+ .on(eventNamesOut, function(event) {
+
+ // it's ok if the touch gesture ended up to be a swipe,
+ // it's still a "touch leave" situation
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+
+ var delay = (event.type == 'mouseleave') ?
+ self.__options.delay :
+ self.__options.delayTouch;
+
+ self._trigger({
+ delay: delay[1],
+ dismissable: true,
+ event: event,
+ type: 'dismissable'
+ });
+ }
+ })
+ // suspend the mouseleave timeout when the pointer comes back
+ // over the elements
+ .on(eventNamesIn, function(event) {
+
+ // it's also ok if the touch event is a swipe gesture
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+ self._trigger({
+ dismissable: false,
+ event: event,
+ type: 'dismissable'
+ });
+ }
+ });
+ }
+
+ // close the tooltip when the origin gets a mouse click (common behavior of
+ // native tooltips)
+ if (self.__options.triggerClose.originClick) {
+
+ self._$origin.on('click.'+ self.__namespace + '-triggerClose', function(event) {
+
+ // we could actually let a tap trigger this but this feature just
+ // does not make sense on touch devices
+ if ( !self._touchIsTouchEvent(event)
+ && !self._touchIsEmulatedEvent(event)
+ ) {
+ self._close(event);
+ }
+ });
+ }
+
+ // set the same bindings for click and touch on the body to close the tooltip
+ if ( self.__options.triggerClose.click
+ || (self.__options.triggerClose.tap && env.hasTouchCapability)
+ ) {
+
+ // don't set right away since the click/tap event which triggered this method
+ // (if it was a click/tap) is going to bubble up to the body, we don't want it
+ // to close the tooltip immediately after it opened
+ setTimeout(function() {
+
+ if (self.__state != 'closed') {
+
+ var eventNames = '',
+ $body = $(env.window.document.body);
+
+ if (self.__options.triggerClose.click) {
+ eventNames += 'click.'+ self.__namespace +'-triggerClose ';
+ }
+ if (self.__options.triggerClose.tap && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerClose';
+ }
+
+ $body.on(eventNames, function(event) {
+
+ if (self._touchIsMeaningfulEvent(event)) {
+
+ self._touchRecordEvent(event);
+
+ if (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) {
+ self._close(event);
+ }
+ }
+ });
+
+ // needed to detect and ignore swiping
+ if (self.__options.triggerClose.tap && env.hasTouchCapability) {
+
+ $body.on('touchstart.'+ self.__namespace +'-triggerClose', function(event) {
+ self._touchRecordEvent(event);
+ });
+ }
+ }
+ }, 0);
+ }
+
+ self._trigger('ready');
+
+ // call our custom callback
+ if (self.__options.functionReady) {
+ self.__options.functionReady.call(self, self, {
+ origin: self._$origin[0],
+ tooltip: self._$tooltip[0]
+ });
+ }
+ }
+
+ // if we have a timer set, let the countdown begin
+ if (self.__options.timer > 0) {
+
+ var timeout = setTimeout(function() {
+ self._close();
+ }, self.__options.timer + extraTime);
+
+ self.__timeouts.close.push(timeout);
+ }
+ }
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * When using the mouseenter/touchstart open triggers, this function will
+ * schedule the opening of the tooltip after the delay, if there is one
+ *
+ * @param event
+ * @returns {self}
+ * @protected
+ */
+ _openShortly: function(event) {
+
+ var self = this,
+ ok = true;
+
+ if (self.__state != 'stable' && self.__state != 'appearing') {
+
+ // if a timeout is not already running
+ if (!self.__timeouts.open) {
+
+ self._trigger({
+ type: 'start',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ if (ok) {
+
+ var delay = (event.type.indexOf('touch') == 0) ?
+ self.__options.delayTouch :
+ self.__options.delay;
+
+ if (delay[0]) {
+
+ self.__timeouts.open = setTimeout(function() {
+
+ self.__timeouts.open = null;
+
+ // open only if the pointer (mouse or touch) is still over the origin.
+ // The check on the "meaningful event" can only be made here, after some
+ // time has passed (to know if the touch was a swipe or not)
+ if (self.__pointerIsOverOrigin && self._touchIsMeaningfulEvent(event)) {
+
+ // signal that we go on
+ self._trigger('startend');
+
+ self._open(event);
+ }
+ else {
+ // signal that we cancel
+ self._trigger('startcancel');
+ }
+ }, delay[0]);
+ }
+ else {
+ // signal that we go on
+ self._trigger('startend');
+
+ self._open(event);
+ }
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Meant for plugins to get their options
+ *
+ * @param {string} pluginName The name of the plugin that asks for its options
+ * @param {object} defaultOptions The default options of the plugin
+ * @returns {object} The options
+ * @protected
+ */
+ _optionsExtract: function(pluginName, defaultOptions) {
+
+ var self = this,
+ options = $.extend(true, {}, defaultOptions);
+
+ // if the plugin options were isolated in a property named after the
+ // plugin, use them (prevents conflicts with other plugins)
+ var pluginOptions = self.__options[pluginName];
+
+ // if not, try to get them as regular options
+ if (!pluginOptions){
+
+ pluginOptions = {};
+
+ $.each(defaultOptions, function(optionName, value) {
+
+ var o = self.__options[optionName];
+
+ if (o !== undefined) {
+ pluginOptions[optionName] = o;
+ }
+ });
+ }
+
+ // let's merge the default options and the ones that were provided. We'd want
+ // to do a deep copy but not let jQuery merge arrays, so we'll do a shallow
+ // extend on two levels, that will be enough if options are not more than 1
+ // level deep
+ $.each(options, function(optionName, value) {
+
+ if (pluginOptions[optionName] !== undefined) {
+
+ if (( typeof value == 'object'
+ && !(value instanceof Array)
+ && value != null
+ )
+ &&
+ ( typeof pluginOptions[optionName] == 'object'
+ && !(pluginOptions[optionName] instanceof Array)
+ && pluginOptions[optionName] != null
+ )
+ ) {
+ $.extend(options[optionName], pluginOptions[optionName]);
+ }
+ else {
+ options[optionName] = pluginOptions[optionName];
+ }
+ }
+ });
+
+ return options;
+ },
+
+ /**
+ * Used at instantiation of the plugin, or afterwards by plugins that activate themselves
+ * on existing instances
+ *
+ * @param {object} pluginName
+ * @returns {self}
+ * @protected
+ */
+ _plug: function(pluginName) {
+
+ var plugin = $.tooltipster._plugin(pluginName);
+
+ if (plugin) {
+
+ // if there is a constructor for instances
+ if (plugin.instance) {
+
+ // proxy non-private methods on the instance to allow new instance methods
+ $.tooltipster.__bridge(plugin.instance, this, plugin.name);
+ }
+ }
+ else {
+ throw new Error('The "'+ pluginName +'" plugin is not defined');
+ }
+
+ return this;
+ },
+
+ /**
+ * This will return true if the event is a mouse event which was
+ * emulated by the browser after a touch event. This allows us to
+ * really dissociate mouse and touch triggers.
+ *
+ * There is a margin of error if a real mouse event is fired right
+ * after (within the delay shown below) a touch event on the same
+ * element, but hopefully it should not happen often.
+ *
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsEmulatedEvent: function(event) {
+
+ var isEmulated = false,
+ now = new Date().getTime();
+
+ for (var i = this.__touchEvents.length - 1; i >= 0; i--) {
+
+ var e = this.__touchEvents[i];
+
+ // delay, in milliseconds. It's supposed to be 300ms in
+ // most browsers (350ms on iOS) to allow a double tap but
+ // can be less (check out FastClick for more info)
+ if (now - e.time < 500) {
+
+ if (e.target === event.target) {
+ isEmulated = true;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ return isEmulated;
+ },
+
+ /**
+ * Returns false if the event was an emulated mouse event or
+ * a touch event involved in a swipe gesture.
+ *
+ * @param {object} event
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsMeaningfulEvent: function(event) {
+ return (
+ (this._touchIsTouchEvent(event) && !this._touchSwiped(event.target))
+ || (!this._touchIsTouchEvent(event) && !this._touchIsEmulatedEvent(event))
+ );
+ },
+
+ /**
+ * Checks if an event is a touch event
+ *
+ * @param {object} event
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsTouchEvent: function(event){
+ return event.type.indexOf('touch') == 0;
+ },
+
+ /**
+ * Store touch events for a while to detect swiping and emulated mouse events
+ *
+ * @param {object} event
+ * @returns {self}
+ * @protected
+ */
+ _touchRecordEvent: function(event) {
+
+ if (this._touchIsTouchEvent(event)) {
+ event.time = new Date().getTime();
+ this.__touchEvents.push(event);
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns true if a swipe happened after the last touchstart event fired on
+ * event.target.
+ *
+ * We need to differentiate a swipe from a tap before we let the event open
+ * or close the tooltip. A swipe is when a touchmove (scroll) event happens
+ * on the body between the touchstart and the touchend events of an element.
+ *
+ * @param {object} target The HTML element that may have triggered the swipe
+ * @returns {boolean}
+ * @protected
+ */
+ _touchSwiped: function(target) {
+
+ var swiped = false;
+
+ for (var i = this.__touchEvents.length - 1; i >= 0; i--) {
+
+ var e = this.__touchEvents[i];
+
+ if (e.type == 'touchmove') {
+ swiped = true;
+ break;
+ }
+ else if (
+ e.type == 'touchstart'
+ && target === e.target
+ ) {
+ break;
+ }
+ }
+
+ return swiped;
+ },
+
+ /**
+ * Triggers an event on the instance emitters
+ *
+ * @returns {self}
+ * @protected
+ */
+ _trigger: function() {
+
+ var args = Array.prototype.slice.apply(arguments);
+
+ if (typeof args[0] == 'string') {
+ args[0] = { type: args[0] };
+ }
+
+ // add properties to the event
+ args[0].instance = this;
+ args[0].origin = this._$origin ? this._$origin[0] : null;
+ args[0].tooltip = this._$tooltip ? this._$tooltip[0] : null;
+
+ // note: the order of emitters matters
+ this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);
+ $.tooltipster._trigger.apply($.tooltipster, args);
+ this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);
+
+ return this;
+ },
+
+ /**
+ * Deactivate a plugin on this instance
+ *
+ * @returns {self}
+ * @protected
+ */
+ _unplug: function(pluginName) {
+
+ var self = this;
+
+ // if the plugin has been activated on this instance
+ if (self[pluginName]) {
+
+ var plugin = $.tooltipster._plugin(pluginName);
+
+ // if there is a constructor for instances
+ if (plugin.instance) {
+
+ // unbridge
+ $.each(plugin.instance, function(methodName, fn) {
+
+ // if the method exists (privates methods do not) and comes indeed from
+ // this plugin (may be missing or come from a conflicting plugin).
+ if ( self[methodName]
+ && self[methodName].bridged === self[pluginName]
+ ) {
+ delete self[methodName];
+ }
+ });
+ }
+
+ // destroy the plugin
+ if (self[pluginName].__destroy) {
+ self[pluginName].__destroy();
+ }
+
+ // remove the reference to the plugin instance
+ delete self[pluginName];
+ }
+
+ return self;
+ },
+
+ /**
+ * @see self::_close
+ * @returns {self}
+ * @public
+ */
+ close: function(callback) {
+
+ if (!this.__destroyed) {
+ this._close(null, callback);
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Sets or gets the content of the tooltip
+ *
+ * @returns {mixed|self}
+ * @public
+ */
+ content: function(content) {
+
+ var self = this;
+
+ // getter method
+ if (content === undefined) {
+ return self.__Content;
+ }
+ // setter method
+ else {
+
+ if (!self.__destroyed) {
+
+ // change the content
+ self.__contentSet(content);
+
+ if (self.__Content !== null) {
+
+ // update the tooltip if it is open
+ if (self.__state !== 'closed') {
+
+ // reset the content in the tooltip
+ self.__contentInsert();
+
+ // reposition and resize the tooltip
+ self.reposition();
+
+ // if we want to play a little animation showing the content changed
+ if (self.__options.updateAnimation) {
+
+ if (env.hasTransitions) {
+
+ // keep the reference in the local scope
+ var animation = self.__options.updateAnimation;
+
+ self._$tooltip.addClass('tooltipster-update-'+ animation);
+
+ // remove the class after a while. The actual duration of the
+ // update animation may be shorter, it's set in the CSS rules
+ setTimeout(function() {
+
+ if (self.__state != 'closed') {
+
+ self._$tooltip.removeClass('tooltipster-update-'+ animation);
+ }
+ }, 1000);
+ }
+ else {
+ self._$tooltip.fadeTo(200, 0.5, function() {
+ if (self.__state != 'closed') {
+ self._$tooltip.fadeTo(200, 1);
+ }
+ });
+ }
+ }
+ }
+ }
+ else {
+ self._close();
+ }
+ }
+ else {
+ self.__destroyError();
+ }
+
+ return self;
+ }
+ },
+
+ /**
+ * Destroys the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ destroy: function() {
+
+ var self = this;
+
+ if (!self.__destroyed) {
+
+ if(self.__state != 'closed'){
+
+ // no closing delay
+ self.option('animationDuration', 0)
+ // force closing
+ ._close(null, null, true);
+ }
+ else {
+ // there might be an open timeout still running
+ self.__timeoutsClear();
+ }
+
+ // send event
+ self._trigger('destroy');
+
+ self.__destroyed = true;
+
+ self._$origin
+ .removeData(self.__namespace)
+ // remove the open trigger listeners
+ .off('.'+ self.__namespace +'-triggerOpen');
+
+ // remove the touch listener
+ $(env.window.document.body).off('.' + self.__namespace +'-triggerOpen');
+
+ var ns = self._$origin.data('tooltipster-ns');
+
+ // if the origin has been removed from DOM, its data may
+ // well have been destroyed in the process and there would
+ // be nothing to clean up or restore
+ if (ns) {
+
+ // if there are no more tooltips on this element
+ if (ns.length === 1) {
+
+ // optional restoration of a title attribute
+ var title = null;
+ if (self.__options.restoration == 'previous') {
+ title = self._$origin.data('tooltipster-initialTitle');
+ }
+ else if (self.__options.restoration == 'current') {
+
+ // old school technique to stringify when outerHTML is not supported
+ title = (typeof self.__Content == 'string') ?
+ self.__Content :
+ $('<div></div>').append(self.__Content).html();
+ }
+
+ if (title) {
+ self._$origin.attr('title', title);
+ }
+
+ // final cleaning
+
+ self._$origin.removeClass('tooltipstered');
+
+ self._$origin
+ .removeData('tooltipster-ns')
+ .removeData('tooltipster-initialTitle');
+ }
+ else {
+ // remove the instance namespace from the list of namespaces of
+ // tooltips present on the element
+ ns = $.grep(ns, function(el, i) {
+ return el !== self.__namespace;
+ });
+ self._$origin.data('tooltipster-ns', ns);
+ }
+ }
+
+ // last event
+ self._trigger('destroyed');
+
+ // unbind private and public event listeners
+ self._off();
+ self.off();
+
+ // remove external references, just in case
+ self.__Content = null;
+ self.__$emitterPrivate = null;
+ self.__$emitterPublic = null;
+ self.__options.parent = null;
+ self._$origin = null;
+ self._$tooltip = null;
+
+ // make sure the object is no longer referenced in there to prevent
+ // memory leaks
+ $.tooltipster.__instancesLatestArr = $.grep($.tooltipster.__instancesLatestArr, function(el, i) {
+ return self !== el;
+ });
+
+ clearInterval(self.__garbageCollector);
+ }
+ else {
+ self.__destroyError();
+ }
+
+ // we return the scope rather than true so that the call to
+ // .tooltipster('destroy') actually returns the matched elements
+ // and applies to all of them
+ return self;
+ },
+
+ /**
+ * Disables the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ disable: function() {
+
+ if (!this.__destroyed) {
+
+ // close first, in case the tooltip would not disappear on
+ // its own (no close trigger)
+ this._close();
+ this.__enabled = false;
+
+ return this;
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns the HTML element of the origin
+ *
+ * @returns {self}
+ * @public
+ */
+ elementOrigin: function() {
+
+ if (!this.__destroyed) {
+ return this._$origin[0];
+ }
+ else {
+ this.__destroyError();
+ }
+ },
+
+ /**
+ * Returns the HTML element of the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ elementTooltip: function() {
+ return this._$tooltip ? this._$tooltip[0] : null;
+ },
+
+ /**
+ * Enables the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ enable: function() {
+ this.__enabled = true;
+ return this;
+ },
+
+ /**
+ * Alias, deprecated in 4.0.0
+ *
+ * @param {function} callback
+ * @returns {self}
+ * @public
+ */
+ hide: function(callback) {
+ return this.close(callback);
+ },
+
+ /**
+ * Returns the instance
+ *
+ * @returns {self}
+ * @public
+ */
+ instance: function() {
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_off() instead)
+ *
+ * @returns {self}
+ * @public
+ */
+ off: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_on() instead)
+ *
+ * @returns {self}
+ * @public
+ */
+ on: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins
+ *
+ * @returns {self}
+ * @public
+ */
+ one: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * @see self::_open
+ * @returns {self}
+ * @public
+ */
+ open: function(callback) {
+
+ if (!this.__destroyed) {
+ this._open(null, callback);
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Get or set options. For internal use and advanced users only.
+ *
+ * @param {string} o Option name
+ * @param {mixed} val optional A new value for the option
+ * @return {mixed|self} If val is omitted, the value of the option
+ * is returned, otherwise the instance itself is returned
+ * @public
+ */
+ option: function(o, val) {
+
+ // getter
+ if (val === undefined) {
+ return this.__options[o];
+ }
+ // setter
+ else {
+
+ if (!this.__destroyed) {
+
+ // change value
+ this.__options[o] = val;
+
+ // format
+ this.__optionsFormat();
+
+ // re-prepare the triggers if needed
+ if ($.inArray(o, ['trigger', 'triggerClose', 'triggerOpen']) >= 0) {
+ this.__prepareOrigin();
+ }
+
+ if (o === 'selfDestruction') {
+ this.__prepareGC();
+ }
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ }
+ },
+
+ /**
+ * This method is in charge of setting the position and size properties of the tooltip.
+ * All the hard work is delegated to the display plugin.
+ * Note: The tooltip may be detached from the DOM at the moment the method is called
+ * but must be attached by the end of the method call.
+ *
+ * @param {object} event For internal use only. Defined if an event such as
+ * window resizing triggered the repositioning
+ * @param {boolean} tooltipIsDetached For internal use only. Set this to true if you
+ * know that the tooltip not being in the DOM is not an issue (typically when the
+ * tooltip element has just been created but has not been added to the DOM yet).
+ * @returns {self}
+ * @public
+ */
+ reposition: function(event, tooltipIsDetached) {
+
+ var self = this;
+
+ if (!self.__destroyed) {
+
+ // if the tooltip is still open and the origin is still in the DOM
+ if (self.__state != 'closed' && bodyContains(self._$origin)) {
+
+ // if the tooltip has not been removed from DOM manually (or if it
+ // has been detached on purpose)
+ if (tooltipIsDetached || bodyContains(self._$tooltip)) {
+
+ if (!tooltipIsDetached) {
+ // detach in case the tooltip overflows the window and adds
+ // scrollbars to it, so __geometry can be accurate
+ self._$tooltip.detach();
+ }
+
+ // refresh the geometry object before passing it as a helper
+ self.__Geometry = self.__geometry();
+
+ // let a plugin fo the rest
+ self._trigger({
+ type: 'reposition',
+ event: event,
+ helper: {
+ geo: self.__Geometry
+ }
+ });
+ }
+ }
+ }
+ else {
+ self.__destroyError();
+ }
+
+ return self;
+ },
+
+ /**
+ * Alias, deprecated in 4.0.0
+ *
+ * @param callback
+ * @returns {self}
+ * @public
+ */
+ show: function(callback) {
+ return this.open(callback);
+ },
+
+ /**
+ * Returns some properties about the instance
+ *
+ * @returns {object}
+ * @public
+ */
+ status: function() {
+
+ return {
+ destroyed: this.__destroyed,
+ enabled: this.__enabled,
+ open: this.__state !== 'closed',
+ state: this.__state
+ };
+ },
+
+ /**
+ * For public use only, not to be used by plugins
+ *
+ * @returns {self}
+ * @public
+ */
+ triggerHandler: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ }
+};
+
+$.fn.tooltipster = function() {
+
+ // for using in closures
+ var args = Array.prototype.slice.apply(arguments),
+ // common mistake: an HTML element can't be in several tooltips at the same time
+ contentCloningWarning = 'You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.';
+
+ // this happens with $(sel).tooltipster(...) when $(sel) does not match anything
+ if (this.length === 0) {
+
+ // still chainable
+ return this;
+ }
+ // this happens when calling $(sel).tooltipster('methodName or options')
+ // where $(sel) matches one or more elements
+ else {
+
+ // method calls
+ if (typeof args[0] === 'string') {
+
+ var v = '#*$~&';
+
+ this.each(function() {
+
+ // retrieve the namepaces of the tooltip(s) that exist on that element.
+ // We will interact with the first tooltip only.
+ var ns = $(this).data('tooltipster-ns'),
+ // self represents the instance of the first tooltipster plugin
+ // associated to the current HTML object of the loop
+ self = ns ? $(this).data(ns[0]) : null;
+
+ // if the current element holds a tooltipster instance
+ if (self) {
+
+ if (typeof self[args[0]] === 'function') {
+
+ if ( this.length > 1
+ && args[0] == 'content'
+ && ( args[1] instanceof $
+ || (typeof args[1] == 'object' && args[1] != null && args[1].tagName)
+ )
+ && !self.__options.contentCloning
+ && self.__options.debug
+ ) {
+ console.log(contentCloningWarning);
+ }
+
+ // note : args[1] and args[2] may not be defined
+ var resp = self[args[0]](args[1], args[2]);
+ }
+ else {
+ throw new Error('Unknown method "'+ args[0] +'"');
+ }
+
+ // if the function returned anything other than the instance
+ // itself (which implies chaining, except for the `instance` method)
+ if (resp !== self || args[0] === 'instance') {
+
+ v = resp;
+
+ // return false to stop .each iteration on the first element
+ // matched by the selector
+ return false;
+ }
+ }
+ else {
+ throw new Error('You called Tooltipster\'s "'+ args[0] +'" method on an uninitialized element');
+ }
+ });
+
+ return (v !== '#*$~&') ? v : this;
+ }
+ // first argument is undefined or an object: the tooltip is initializing
+ else {
+
+ // reset the array of last initialized objects
+ $.tooltipster.__instancesLatestArr = [];
+
+ // is there a defined value for the multiple option in the options object ?
+ var multipleIsSet = args[0] && args[0].multiple !== undefined,
+ // if the multiple option is set to true, or if it's not defined but
+ // set to true in the defaults
+ multiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple),
+ // same for content
+ contentIsSet = args[0] && args[0].content !== undefined,
+ content = (contentIsSet && args[0].content) || (!contentIsSet && defaults.content),
+ // same for contentCloning
+ contentCloningIsSet = args[0] && args[0].contentCloning !== undefined,
+ contentCloning =
+ (contentCloningIsSet && args[0].contentCloning)
+ || (!contentCloningIsSet && defaults.contentCloning),
+ // same for debug
+ debugIsSet = args[0] && args[0].debug !== undefined,
+ debug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug);
+
+ if ( this.length > 1
+ && ( content instanceof $
+ || (typeof content == 'object' && content != null && content.tagName)
+ )
+ && !contentCloning
+ && debug
+ ) {
+ console.log(contentCloningWarning);
+ }
+
+ // create a tooltipster instance for each element if it doesn't
+ // already have one or if the multiple option is set, and attach the
+ // object to it
+ this.each(function() {
+
+ var go = false,
+ $this = $(this),
+ ns = $this.data('tooltipster-ns'),
+ obj = null;
+
+ if (!ns) {
+ go = true;
+ }
+ else if (multiple) {
+ go = true;
+ }
+ else if (debug) {
+ console.log('Tooltipster: one or more tooltips are already attached to the element below. Ignoring.');
+ console.log(this);
+ }
+
+ if (go) {
+ obj = new $.Tooltipster(this, args[0]);
+
+ // save the reference of the new instance
+ if (!ns) ns = [];
+ ns.push(obj.__namespace);
+ $this.data('tooltipster-ns', ns);
+
+ // save the instance itself
+ $this.data(obj.__namespace, obj);
+
+ // call our constructor custom function.
+ // we do this here and not in ::init() because we wanted
+ // the object to be saved in $this.data before triggering
+ // it
+ if (obj.__options.functionInit) {
+ obj.__options.functionInit.call(obj, obj, {
+ origin: this
+ });
+ }
+
+ // and now the event, for the plugins and core emitter
+ obj._trigger('init');
+ }
+
+ $.tooltipster.__instancesLatestArr.push(obj);
+ });
+
+ return this;
+ }
+ }
+};
+
+// Utilities
+
+/**
+ * A class to check if a tooltip can fit in given dimensions
+ *
+ * @param {object} $tooltip The jQuery wrapped tooltip element, or a clone of it
+ */
+function Ruler($tooltip) {
+
+ // list of instance variables
+
+ this.$container;
+ this.constraints = null;
+ this.__$tooltip;
+
+ this.__init($tooltip);
+}
+
+Ruler.prototype = {
+
+ /**
+ * Move the tooltip into an invisible div that does not allow overflow to make
+ * size tests. Note: the tooltip may or may not be attached to the DOM at the
+ * moment this method is called, it does not matter.
+ *
+ * @param {object} $tooltip The object to test. May be just a clone of the
+ * actual tooltip.
+ * @private
+ */
+ __init: function($tooltip) {
+
+ this.__$tooltip = $tooltip;
+
+ this.__$tooltip
+ .css({
+ // for some reason we have to specify top and left 0
+ left: 0,
+ // any overflow will be ignored while measuring
+ overflow: 'hidden',
+ // positions at (0,0) without the div using 100% of the available width
+ position: 'absolute',
+ top: 0
+ })
+ // overflow must be auto during the test. We re-set this in case
+ // it were modified by the user
+ .find('.tooltipster-content')
+ .css('overflow', 'auto');
+
+ this.$container = $('<div class="tooltipster-ruler"></div>')
+ .append(this.__$tooltip)
+ .appendTo(env.window.document.body);
+ },
+
+ /**
+ * Force the browser to redraw (re-render) the tooltip immediately. This is required
+ * when you changed some CSS properties and need to make something with it
+ * immediately, without waiting for the browser to redraw at the end of instructions.
+ *
+ * @see http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes
+ * @private
+ */
+ __forceRedraw: function() {
+
+ // note: this would work but for Webkit only
+ //this.__$tooltip.close();
+ //this.__$tooltip[0].offsetHeight;
+ //this.__$tooltip.open();
+
+ // works in FF too
+ var $p = this.__$tooltip.parent();
+ this.__$tooltip.detach();
+ this.__$tooltip.appendTo($p);
+ },
+
+ /**
+ * Set maximum dimensions for the tooltip. A call to ::measure afterwards
+ * will tell us if the content overflows or if it's ok
+ *
+ * @param {int} width
+ * @param {int} height
+ * @return {Ruler}
+ * @public
+ */
+ constrain: function(width, height) {
+
+ this.constraints = {
+ width: width,
+ height: height
+ };
+
+ this.__$tooltip.css({
+ // we disable display:flex, otherwise the content would overflow without
+ // creating horizontal scrolling (which we need to detect).
+ display: 'block',
+ // reset any previous height
+ height: '',
+ // we'll check if horizontal scrolling occurs
+ overflow: 'auto',
+ // we'll set the width and see what height is generated and if there
+ // is horizontal overflow
+ width: width
+ });
+
+ return this;
+ },
+
+ /**
+ * Reset the tooltip content overflow and remove the test container
+ *
+ * @returns {Ruler}
+ * @public
+ */
+ destroy: function() {
+
+ // in case the element was not a clone
+ this.__$tooltip
+ .detach()
+ .find('.tooltipster-content')
+ .css({
+ // reset to CSS value
+ display: '',
+ overflow: ''
+ });
+
+ this.$container.remove();
+ },
+
+ /**
+ * Removes any constraints
+ *
+ * @returns {Ruler}
+ * @public
+ */
+ free: function() {
+
+ this.constraints = null;
+
+ // reset to natural size
+ this.__$tooltip.css({
+ display: '',
+ height: '',
+ overflow: 'visible',
+ width: ''
+ });
+
+ return this;
+ },
+
+ /**
+ * Returns the size of the tooltip. When constraints are applied, also returns
+ * whether the tooltip fits in the provided dimensions.
+ * The idea is to see if the new height is small enough and if the content does
+ * not overflow horizontally.
+ *
+ * @param {int} width
+ * @param {int} height
+ * @returns {object} An object with a bool `fits` property and a `size` property
+ * @public
+ */
+ measure: function() {
+
+ this.__forceRedraw();
+
+ var tooltipBcr = this.__$tooltip[0].getBoundingClientRect(),
+ result = { size: {
+ // bcr.width/height are not defined in IE8- but in this
+ // case, bcr.right/bottom will have the same value
+ // except in iOS 8+ where tooltipBcr.bottom/right are wrong
+ // after scrolling for reasons yet to be determined.
+ // tooltipBcr.top/left might not be 0, see issue #514
+ height: tooltipBcr.height || (tooltipBcr.bottom - tooltipBcr.top),
+ width: tooltipBcr.width || (tooltipBcr.right - tooltipBcr.left)
+ }};
+
+ if (this.constraints) {
+
+ // note: we used to use offsetWidth instead of boundingRectClient but
+ // it returned rounded values, causing issues with sub-pixel layouts.
+
+ // note2: noticed that the bcrWidth of text content of a div was once
+ // greater than the bcrWidth of its container by 1px, causing the final
+ // tooltip box to be too small for its content. However, evaluating
+ // their widths one against the other (below) surprisingly returned
+ // equality. Happened only once in Chrome 48, was not able to reproduce
+ // => just having fun with float position values...
+
+ var $content = this.__$tooltip.find('.tooltipster-content'),
+ height = this.__$tooltip.outerHeight(),
+ contentBcr = $content[0].getBoundingClientRect(),
+ fits = {
+ height: height <= this.constraints.height,
+ width: (
+ // this condition accounts for min-width property that
+ // may apply
+ tooltipBcr.width <= this.constraints.width
+ // the -1 is here because scrollWidth actually returns
+ // a rounded value, and may be greater than bcr.width if
+ // it was rounded up. This may cause an issue for contents
+ // which actually really overflow by 1px or so, but that
+ // should be rare. Not sure how to solve this efficiently.
+ // See http://blogs.msdn.com/b/ie/archive/2012/02/17/sub-pixel-rendering-and-the-css-object-model.aspx
+ && contentBcr.width >= $content[0].scrollWidth - 1
+ )
+ };
+
+ result.fits = fits.height && fits.width;
+ }
+
+ // old versions of IE get the width wrong for some reason and it causes
+ // the text to be broken to a new line, so we round it up. If the width
+ // is the width of the screen though, we can assume it is accurate.
+ if ( env.IE
+ && env.IE <= 11
+ && result.size.width !== env.window.document.documentElement.clientWidth
+ ) {
+ result.size.width = Math.ceil(result.size.width) + 1;
+ }
+
+ return result;
+ }
+};
+
+// quick & dirty compare function, not bijective nor multidimensional
+function areEqual(a,b) {
+ var same = true;
+ $.each(a, function(i, _) {
+ if (b[i] === undefined || a[i] !== b[i]) {
+ same = false;
+ return false;
+ }
+ });
+ return same;
+}
+
+/**
+ * A fast function to check if an element is still in the DOM. It
+ * tries to use an id as ids are indexed by the browser, or falls
+ * back to jQuery's `contains` method. May fail if two elements
+ * have the same id, but so be it
+ *
+ * @param {object} $obj A jQuery-wrapped HTML element
+ * @return {boolean}
+ */
+function bodyContains($obj) {
+ var id = $obj.attr('id'),
+ el = id ? env.window.document.getElementById(id) : null;
+ // must also check that the element with the id is the one we want
+ return el ? el === $obj[0] : $.contains(env.window.document.body, $obj[0]);
+}
+
+// detect IE versions for dirty fixes
+var uA = navigator.userAgent.toLowerCase();
+if (uA.indexOf('msie') != -1) env.IE = parseInt(uA.split('msie')[1]);
+else if (uA.toLowerCase().indexOf('trident') !== -1 && uA.indexOf(' rv:11') !== -1) env.IE = 11;
+else if (uA.toLowerCase().indexOf('edge/') != -1) env.IE = parseInt(uA.toLowerCase().split('edge/')[1]);
+
+// detecting support for CSS transitions
+function transitionSupport() {
+
+ // env.window is not defined yet when this is called
+ if (!win) return false;
+
+ var b = win.document.body || win.document.documentElement,
+ s = b.style,
+ p = 'transition',
+ v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];
+
+ if (typeof s[p] == 'string') { return true; }
+
+ p = p.charAt(0).toUpperCase() + p.substr(1);
+ for (var i=0; i<v.length; i++) {
+ if (typeof s[v[i] + p] == 'string') { return true; }
+ }
+ return false;
+}
+
+// we'll return jQuery for plugins not to have to declare it as a dependency,
+// but it's done by a build task since it should be included only once at the
+// end when we concatenate the main file with a plugin
+// sideTip is Tooltipster's default plugin.
+// This file will be UMDified by a build task.
+
+var pluginName = 'tooltipster.sideTip';
+
+$.tooltipster._plugin({
+ name: pluginName,
+ instance: {
+ /**
+ * Defaults are provided as a function for an easy override by inheritance
+ *
+ * @return {object} An object with the defaults options
+ * @private
+ */
+ __defaults: function() {
+
+ return {
+ // if the tooltip should display an arrow that points to the origin
+ arrow: true,
+ // the distance in pixels between the tooltip and the origin
+ distance: 6,
+ // allows to easily change the position of the tooltip
+ functionPosition: null,
+ maxWidth: null,
+ // used to accomodate the arrow of tooltip if there is one.
+ // First to make sure that the arrow target is not too close
+ // to the edge of the tooltip, so the arrow does not overflow
+ // the tooltip. Secondly when we reposition the tooltip to
+ // make sure that it's positioned in such a way that the arrow is
+ // still pointing at the target (and not a few pixels beyond it).
+ // It should be equal to or greater than half the width of
+ // the arrow (by width we mean the size of the side which touches
+ // the side of the tooltip).
+ minIntersection: 16,
+ minWidth: 0,
+ // deprecated in 4.0.0. Listed for _optionsExtract to pick it up
+ position: null,
+ side: 'top',
+ // set to false to position the tooltip relatively to the document rather
+ // than the window when we open it
+ viewportAware: true
+ };
+ },
+
+ /**
+ * Run once: at instantiation of the plugin
+ *
+ * @param {object} instance The tooltipster object that instantiated this plugin
+ * @private
+ */
+ __init: function(instance) {
+
+ var self = this;
+
+ // list of instance variables
+
+ self.__instance = instance;
+ self.__namespace = 'tooltipster-sideTip-'+ Math.round(Math.random()*1000000);
+ self.__previousState = 'closed';
+ self.__options;
+
+ // initial formatting
+ self.__optionsFormat();
+
+ self.__instance._on('state.'+ self.__namespace, function(event) {
+
+ if (event.state == 'closed') {
+ self.__close();
+ }
+ else if (event.state == 'appearing' && self.__previousState == 'closed') {
+ self.__create();
+ }
+
+ self.__previousState = event.state;
+ });
+
+ // reformat every time the options are changed
+ self.__instance._on('options.'+ self.__namespace, function() {
+ self.__optionsFormat();
+ });
+
+ self.__instance._on('reposition.'+ self.__namespace, function(e) {
+ self.__reposition(e.event, e.helper);
+ });
+ },
+
+ /**
+ * Called when the tooltip has closed
+ *
+ * @private
+ */
+ __close: function() {
+
+ // detach our content object first, so the next jQuery's remove()
+ // call does not unbind its event handlers
+ if (this.__instance.content() instanceof $) {
+ this.__instance.content().detach();
+ }
+
+ // remove the tooltip from the DOM
+ this.__instance._$tooltip.remove();
+ this.__instance._$tooltip = null;
+ },
+
+ /**
+ * Creates the HTML element of the tooltip.
+ *
+ * @private
+ */
+ __create: function() {
+
+ // note: we wrap with a .tooltipster-box div to be able to set a margin on it
+ // (.tooltipster-base must not have one)
+ var $html = $(
+ '<div class="tooltipster-base tooltipster-sidetip">' +
+ '<div class="tooltipster-box">' +
+ '<div class="tooltipster-content"></div>' +
+ '</div>' +
+ '<div class="tooltipster-arrow">' +
+ '<div class="tooltipster-arrow-uncropped">' +
+ '<div class="tooltipster-arrow-border"></div>' +
+ '<div class="tooltipster-arrow-background"></div>' +
+ '</div>' +
+ '</div>' +
+ '</div>'
+ );
+
+ // hide arrow if asked
+ if (!this.__options.arrow) {
+ $html
+ .find('.tooltipster-box')
+ .css('margin', 0)
+ .end()
+ .find('.tooltipster-arrow')
+ .hide();
+ }
+
+ // apply min/max width if asked
+ if (this.__options.minWidth) {
+ $html.css('min-width', this.__options.minWidth + 'px');
+ }
+ if (this.__options.maxWidth) {
+ $html.css('max-width', this.__options.maxWidth + 'px');
+ }
+
+ this.__instance._$tooltip = $html;
+
+ // tell the instance that the tooltip element has been created
+ this.__instance._trigger('created');
+ },
+
+ /**
+ * Used when the plugin is to be unplugged
+ *
+ * @private
+ */
+ __destroy: function() {
+ this.__instance._off('.'+ self.__namespace);
+ },
+
+ /**
+ * (Re)compute this.__options from the options declared to the instance
+ *
+ * @private
+ */
+ __optionsFormat: function() {
+
+ var self = this;
+
+ // get the options
+ self.__options = self.__instance._optionsExtract(pluginName, self.__defaults());
+
+ // for backward compatibility, deprecated in v4.0.0
+ if (self.__options.position) {
+ self.__options.side = self.__options.position;
+ }
+
+ // options formatting
+
+ // format distance as a four-cell array if it ain't one yet and then make
+ // it an object with top/bottom/left/right properties
+ if (typeof self.__options.distance != 'object') {
+ self.__options.distance = [self.__options.distance];
+ }
+ if (self.__options.distance.length < 4) {
+
+ if (self.__options.distance[1] === undefined) self.__options.distance[1] = self.__options.distance[0];
+ if (self.__options.distance[2] === undefined) self.__options.distance[2] = self.__options.distance[0];
+ if (self.__options.distance[3] === undefined) self.__options.distance[3] = self.__options.distance[1];
+
+ self.__options.distance = {
+ top: self.__options.distance[0],
+ right: self.__options.distance[1],
+ bottom: self.__options.distance[2],
+ left: self.__options.distance[3]
+ };
+ }
+
+ // let's transform:
+ // 'top' into ['top', 'bottom', 'right', 'left']
+ // 'right' into ['right', 'left', 'top', 'bottom']
+ // 'bottom' into ['bottom', 'top', 'right', 'left']
+ // 'left' into ['left', 'right', 'top', 'bottom']
+ if (typeof self.__options.side == 'string') {
+
+ var opposites = {
+ 'top': 'bottom',
+ 'right': 'left',
+ 'bottom': 'top',
+ 'left': 'right'
+ };
+
+ self.__options.side = [self.__options.side, opposites[self.__options.side]];
+
+ if (self.__options.side[0] == 'left' || self.__options.side[0] == 'right') {
+ self.__options.side.push('top', 'bottom');
+ }
+ else {
+ self.__options.side.push('right', 'left');
+ }
+ }
+
+ // misc
+ // disable the arrow in IE6 unless the arrow option was explicitly set to true
+ if ( $.tooltipster._env.IE === 6
+ && self.__options.arrow !== true
+ ) {
+ self.__options.arrow = false;
+ }
+ },
+
+ /**
+ * This method must compute and set the positioning properties of the
+ * tooltip (left, top, width, height, etc.). It must also make sure the
+ * tooltip is eventually appended to its parent (since the element may be
+ * detached from the DOM at the moment the method is called).
+ *
+ * We'll evaluate positioning scenarios to find which side can contain the
+ * tooltip in the best way. We'll consider things relatively to the window
+ * (unless the user asks not to), then to the document (if need be, or if the
+ * user explicitly requires the tests to run on the document). For each
+ * scenario, measures are taken, allowing us to know how well the tooltip
+ * is going to fit. After that, a sorting function will let us know what
+ * the best scenario is (we also allow the user to choose his favorite
+ * scenario by using an event).
+ *
+ * @param {object} helper An object that contains variables that plugin
+ * creators may find useful (see below)
+ * @param {object} helper.geo An object with many layout properties
+ * about objects of interest (window, document, origin). This should help
+ * plugin users compute the optimal position of the tooltip
+ * @private
+ */
+ __reposition: function(event, helper) {
+
+ var self = this,
+ finalResult,
+ // to know where to put the tooltip, we need to know on which point
+ // of the x or y axis we should center it. That coordinate is the target
+ targets = self.__targetFind(helper),
+ testResults = [];
+
+ // make sure the tooltip is detached while we make tests on a clone
+ self.__instance._$tooltip.detach();
+
+ // we could actually provide the original element to the Ruler and
+ // not a clone, but it just feels right to keep it out of the
+ // machinery.
+ var $clone = self.__instance._$tooltip.clone(),
+ // start position tests session
+ ruler = $.tooltipster._getRuler($clone),
+ satisfied = false,
+ animation = self.__instance.option('animation');
+
+ // an animation class could contain properties that distort the size
+ if (animation) {
+ $clone.removeClass('tooltipster-'+ animation);
+ }
+
+ // start evaluating scenarios
+ $.each(['window', 'document'], function(i, container) {
+
+ var takeTest = null;
+
+ // let the user decide to keep on testing or not
+ self.__instance._trigger({
+ container: container,
+ helper: helper,
+ satisfied: satisfied,
+ takeTest: function(bool) {
+ takeTest = bool;
+ },
+ results: testResults,
+ type: 'positionTest'
+ });
+
+ if ( takeTest == true
+ || ( takeTest != false
+ && satisfied == false
+ // skip the window scenarios if asked. If they are reintegrated by
+ // the callback of the positionTest event, they will have to be
+ // excluded using the callback of positionTested
+ && (container != 'window' || self.__options.viewportAware)
+ )
+ ) {
+
+ // for each allowed side
+ for (var i=0; i < self.__options.side.length; i++) {
+
+ var distance = {
+ horizontal: 0,
+ vertical: 0
+ },
+ side = self.__options.side[i];
+
+ if (side == 'top' || side == 'bottom') {
+ distance.vertical = self.__options.distance[side];
+ }
+ else {
+ distance.horizontal = self.__options.distance[side];
+ }
+
+ // this may have an effect on the size of the tooltip if there are css
+ // rules for the arrow or something else
+ self.__sideChange($clone, side);
+
+ $.each(['natural', 'constrained'], function(i, mode) {
+
+ takeTest = null;
+
+ // emit an event on the instance
+ self.__instance._trigger({
+ container: container,
+ event: event,
+ helper: helper,
+ mode: mode,
+ results: testResults,
+ satisfied: satisfied,
+ side: side,
+ takeTest: function(bool) {
+ takeTest = bool;
+ },
+ type: 'positionTest'
+ });
+
+ if ( takeTest == true
+ || ( takeTest != false
+ && satisfied == false
+ )
+ ) {
+
+ var testResult = {
+ container: container,
+ // we let the distance as an object here, it can make things a little easier
+ // during the user's calculations at positionTest/positionTested
+ distance: distance,
+ // whether the tooltip can fit in the size of the viewport (does not mean
+ // that we'll be able to make it initially entirely visible, see 'whole')
+ fits: null,
+ mode: mode,
+ outerSize: null,
+ side: side,
+ size: null,
+ target: targets[side],
+ // check if the origin has enough surface on screen for the tooltip to
+ // aim at it without overflowing the viewport (this is due to the thickness
+ // of the arrow represented by the minIntersection length).
+ // If not, the tooltip will have to be partly or entirely off screen in
+ // order to stay docked to the origin. This value will stay null when the
+ // container is the document, as it is not relevant
+ whole: null
+ };
+
+ // get the size of the tooltip with or without size constraints
+ var rulerConfigured = (mode == 'natural') ?
+ ruler.free() :
+ ruler.constrain(
+ helper.geo.available[container][side].width - distance.horizontal,
+ helper.geo.available[container][side].height - distance.vertical
+ ),
+ rulerResults = rulerConfigured.measure();
+
+ testResult.size = rulerResults.size;
+ testResult.outerSize = {
+ height: rulerResults.size.height + distance.vertical,
+ width: rulerResults.size.width + distance.horizontal
+ };
+
+ if (mode == 'natural') {
+
+ if( helper.geo.available[container][side].width >= testResult.outerSize.width
+ && helper.geo.available[container][side].height >= testResult.outerSize.height
+ ) {
+ testResult.fits = true;
+ }
+ else {
+ testResult.fits = false;
+ }
+ }
+ else {
+ testResult.fits = rulerResults.fits;
+ }
+
+ if (container == 'window') {
+
+ if (!testResult.fits) {
+ testResult.whole = false;
+ }
+ else {
+ if (side == 'top' || side == 'bottom') {
+
+ testResult.whole = (
+ helper.geo.origin.windowOffset.right >= self.__options.minIntersection
+ && helper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection
+ );
+ }
+ else {
+ testResult.whole = (
+ helper.geo.origin.windowOffset.bottom >= self.__options.minIntersection
+ && helper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection
+ );
+ }
+ }
+ }
+
+ testResults.push(testResult);
+
+ // we don't need to compute more positions if we have one fully on screen
+ if (testResult.whole) {
+ satisfied = true;
+ }
+ else {
+ // don't run the constrained test unless the natural width was greater
+ // than the available width, otherwise it's pointless as we know it
+ // wouldn't fit either
+ if ( testResult.mode == 'natural'
+ && ( testResult.fits
+ || testResult.size.width <= helper.geo.available[container][side].width
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+ });
+ }
+ }
+ });
+
+ // the user may eliminate the unwanted scenarios from testResults, but he's
+ // not supposed to alter them at this point. functionPosition and the
+ // position event serve that purpose.
+ self.__instance._trigger({
+ edit: function(r) {
+ testResults = r;
+ },
+ event: event,
+ helper: helper,
+ results: testResults,
+ type: 'positionTested'
+ });
+
+ /**
+ * Sort the scenarios to find the favorite one.
+ *
+ * The favorite scenario is when we can fully display the tooltip on screen,
+ * even if it means that the middle of the tooltip is no longer centered on
+ * the middle of the origin (when the origin is near the edge of the screen
+ * or even partly off screen). We want the tooltip on the preferred side,
+ * even if it means that we have to use a constrained size rather than a
+ * natural one (as long as it fits). When the origin is off screen at the top
+ * the tooltip will be positioned at the bottom (if allowed), if the origin
+ * is off screen on the right, it will be positioned on the left, etc.
+ * If there are no scenarios where the tooltip can fit on screen, or if the
+ * user does not want the tooltip to fit on screen (viewportAware == false),
+ * we fall back to the scenarios relative to the document.
+ *
+ * When the tooltip is bigger than the viewport in either dimension, we stop
+ * looking at the window scenarios and consider the document scenarios only,
+ * with the same logic to find on which side it would fit best.
+ *
+ * If the tooltip cannot fit the document on any side, we force it at the
+ * bottom, so at least the user can scroll to see it.
+ */
+ testResults.sort(function(a, b) {
+
+ // best if it's whole (the tooltip fits and adapts to the viewport)
+ if (a.whole && !b.whole) {
+ return -1;
+ }
+ else if (!a.whole && b.whole) {
+ return 1;
+ }
+ else if (a.whole && b.whole) {
+
+ var ai = self.__options.side.indexOf(a.side),
+ bi = self.__options.side.indexOf(b.side);
+
+ // use the user's sides fallback array
+ if (ai < bi) {
+ return -1;
+ }
+ else if (ai > bi) {
+ return 1;
+ }
+ else {
+ // will be used if the user forced the tests to continue
+ return a.mode == 'natural' ? -1 : 1;
+ }
+ }
+ else {
+
+ // better if it fits
+ if (a.fits && !b.fits) {
+ return -1;
+ }
+ else if (!a.fits && b.fits) {
+ return 1;
+ }
+ else if (a.fits && b.fits) {
+
+ var ai = self.__options.side.indexOf(a.side),
+ bi = self.__options.side.indexOf(b.side);
+
+ // use the user's sides fallback array
+ if (ai < bi) {
+ return -1;
+ }
+ else if (ai > bi) {
+ return 1;
+ }
+ else {
+ // will be used if the user forced the tests to continue
+ return a.mode == 'natural' ? -1 : 1;
+ }
+ }
+ else {
+
+ // if everything failed, this will give a preference to the case where
+ // the tooltip overflows the document at the bottom
+ if ( a.container == 'document'
+ && a.side == 'bottom'
+ && a.mode == 'natural'
+ ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ }
+ });
+
+ finalResult = testResults[0];
+
+
+ // now let's find the coordinates of the tooltip relatively to the window
+ finalResult.coord = {};
+
+ switch (finalResult.side) {
+
+ case 'left':
+ case 'right':
+ finalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2);
+ break;
+
+ case 'bottom':
+ case 'top':
+ finalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2);
+ break;
+ }
+
+ switch (finalResult.side) {
+
+ case 'left':
+ finalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width;
+ break;
+
+ case 'right':
+ finalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal;
+ break;
+
+ case 'top':
+ finalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height;
+ break;
+
+ case 'bottom':
+ finalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical;
+ break;
+ }
+
+ // if the tooltip can potentially be contained within the viewport dimensions
+ // and that we are asked to make it fit on screen
+ if (finalResult.container == 'window') {
+
+ // if the tooltip overflows the viewport, we'll move it accordingly (then it will
+ // not be centered on the middle of the origin anymore). We only move horizontally
+ // for top and bottom tooltips and vice versa.
+ if (finalResult.side == 'top' || finalResult.side == 'bottom') {
+
+ // if there is an overflow on the left
+ if (finalResult.coord.left < 0) {
+
+ // prevent the overflow unless the origin itself gets off screen (minus the
+ // margin needed to keep the arrow pointing at the target)
+ if (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) {
+ finalResult.coord.left = 0;
+ }
+ else {
+ finalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1;
+ }
+ }
+ // or an overflow on the right
+ else if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
+
+ if (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) {
+ finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
+ }
+ else {
+ finalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width;
+ }
+ }
+ }
+ else {
+
+ // overflow at the top
+ if (finalResult.coord.top < 0) {
+
+ if (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) {
+ finalResult.coord.top = 0;
+ }
+ else {
+ finalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1;
+ }
+ }
+ // or at the bottom
+ else if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) {
+
+ if (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) {
+ finalResult.coord.top = helper.geo.window.size.height - finalResult.size.height;
+ }
+ else {
+ finalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height;
+ }
+ }
+ }
+ }
+ else {
+
+ // there might be overflow here too but it's easier to handle. If there has
+ // to be an overflow, we'll make sure it's on the right side of the screen
+ // (because the browser will extend the document size if there is an overflow
+ // on the right, but not on the left). The sort function above has already
+ // made sure that a bottom document overflow is preferred to a top overflow,
+ // so we don't have to care about it.
+
+ // if there is an overflow on the right
+ if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
+
+ // this may actually create on overflow on the left but we'll fix it in a sec
+ finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
+ }
+
+ // if there is an overflow on the left
+ if (finalResult.coord.left < 0) {
+
+ // don't care if it overflows the right after that, we made our best
+ finalResult.coord.left = 0;
+ }
+ }
+
+
+ // submit the positioning proposal to the user function which may choose to change
+ // the side, size and/or the coordinates
+
+ // first, set the rules that corresponds to the proposed side: it may change
+ // the size of the tooltip, and the custom functionPosition may want to detect the
+ // size of something before making a decision. So let's make things easier for the
+ // implementor
+ self.__sideChange($clone, finalResult.side);
+
+ // add some variables to the helper
+ helper.tooltipClone = $clone[0];
+ helper.tooltipParent = self.__instance.option('parent').parent[0];
+ // move informative values to the helper
+ helper.mode = finalResult.mode;
+ helper.whole = finalResult.whole;
+ // add some variables to the helper for the functionPosition callback (these
+ // will also be added to the event fired by self.__instance._trigger but that's
+ // ok, we're just being consistent)
+ helper.origin = self.__instance._$origin[0];
+ helper.tooltip = self.__instance._$tooltip[0];
+
+ // leave only the actionable values in there for functionPosition
+ delete finalResult.container;
+ delete finalResult.fits;
+ delete finalResult.mode;
+ delete finalResult.outerSize;
+ delete finalResult.whole;
+
+ // keep only the distance on the relevant side, for clarity
+ finalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical;
+
+ // beginners may not be comfortable with the concept of editing the object
+ // passed by reference, so we provide an edit function and pass a clone
+ var finalResultClone = $.extend(true, {}, finalResult);
+
+ // emit an event on the instance
+ self.__instance._trigger({
+ edit: function(result) {
+ finalResult = result;
+ },
+ event: event,
+ helper: helper,
+ position: finalResultClone,
+ type: 'position'
+ });
+
+ if (self.__options.functionPosition) {
+
+ var result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone);
+
+ if (result) finalResult = result;
+ }
+
+ // end the positioning tests session (the user might have had a
+ // use for it during the position event, now it's over)
+ ruler.destroy();
+
+ // compute the position of the target relatively to the tooltip root
+ // element so we can place the arrow and make the needed adjustments
+ var arrowCoord,
+ maxVal;
+
+ if (finalResult.side == 'top' || finalResult.side == 'bottom') {
+
+ arrowCoord = {
+ prop: 'left',
+ val: finalResult.target - finalResult.coord.left
+ };
+ maxVal = finalResult.size.width - this.__options.minIntersection;
+ }
+ else {
+
+ arrowCoord = {
+ prop: 'top',
+ val: finalResult.target - finalResult.coord.top
+ };
+ maxVal = finalResult.size.height - this.__options.minIntersection;
+ }
+
+ // cannot lie beyond the boundaries of the tooltip, minus the
+ // arrow margin
+ if (arrowCoord.val < this.__options.minIntersection) {
+ arrowCoord.val = this.__options.minIntersection;
+ }
+ else if (arrowCoord.val > maxVal) {
+ arrowCoord.val = maxVal;
+ }
+
+ var originParentOffset;
+
+ // let's convert the window-relative coordinates into coordinates relative to the
+ // future positioned parent that the tooltip will be appended to
+ if (helper.geo.origin.fixedLineage) {
+
+ // same as windowOffset when the position is fixed
+ originParentOffset = helper.geo.origin.windowOffset;
+ }
+ else {
+
+ // this assumes that the parent of the tooltip is located at
+ // (0, 0) in the document, typically like when the parent is
+ // <body>.
+ // If we ever allow other types of parent, .tooltipster-ruler
+ // will have to be appended to the parent to inherit css style
+ // values that affect the display of the text and such.
+ originParentOffset = {
+ left: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left,
+ top: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top
+ };
+ }
+
+ finalResult.coord = {
+ left: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left),
+ top: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top)
+ };
+
+ // set position values on the original tooltip element
+
+ self.__sideChange(self.__instance._$tooltip, finalResult.side);
+
+ if (helper.geo.origin.fixedLineage) {
+ self.__instance._$tooltip
+ .css('position', 'fixed');
+ }
+ else {
+ // CSS default
+ self.__instance._$tooltip
+ .css('position', '');
+ }
+
+ self.__instance._$tooltip
+ .css({
+ left: finalResult.coord.left,
+ top: finalResult.coord.top,
+ // we need to set a size even if the tooltip is in its natural size
+ // because when the tooltip is positioned beyond the width of the body
+ // (which is by default the width of the window; it will happen when
+ // you scroll the window horizontally to get to the origin), its text
+ // content will otherwise break lines at each word to keep up with the
+ // body overflow strategy.
+ height: finalResult.size.height,
+ width: finalResult.size.width
+ })
+ .find('.tooltipster-arrow')
+ .css({
+ 'left': '',
+ 'top': ''
+ })
+ .css(arrowCoord.prop, arrowCoord.val);
+
+ // append the tooltip HTML element to its parent
+ self.__instance._$tooltip.appendTo(self.__instance.option('parent'));
+
+ self.__instance._trigger({
+ type: 'repositioned',
+ event: event,
+ position: finalResult
+ });
+ },
+
+ /**
+ * Make whatever modifications are needed when the side is changed. This has
+ * been made an independant method for easy inheritance in custom plugins based
+ * on this default plugin.
+ *
+ * @param {object} $obj
+ * @param {string} side
+ * @private
+ */
+ __sideChange: function($obj, side) {
+
+ $obj
+ .removeClass('tooltipster-bottom')
+ .removeClass('tooltipster-left')
+ .removeClass('tooltipster-right')
+ .removeClass('tooltipster-top')
+ .addClass('tooltipster-'+ side);
+ },
+
+ /**
+ * Returns the target that the tooltip should aim at for a given side.
+ * The calculated value is a distance from the edge of the window
+ * (left edge for top/bottom sides, top edge for left/right side). The
+ * tooltip will be centered on that position and the arrow will be
+ * positioned there (as much as possible).
+ *
+ * @param {object} helper
+ * @return {integer}
+ * @private
+ */
+ __targetFind: function(helper) {
+
+ var target = {},
+ rects = this.__instance._$origin[0].getClientRects();
+
+ // these lines fix a Chrome bug (issue #491)
+ if (rects.length > 1) {
+ var opacity = this.__instance._$origin.css('opacity');
+ if(opacity == 1) {
+ this.__instance._$origin.css('opacity', 0.99);
+ rects = this.__instance._$origin[0].getClientRects();
+ this.__instance._$origin.css('opacity', 1);
+ }
+ }
+
+ // by default, the target will be the middle of the origin
+ if (rects.length < 2) {
+
+ target.top = Math.floor(helper.geo.origin.windowOffset.left + (helper.geo.origin.size.width / 2));
+ target.bottom = target.top;
+
+ target.left = Math.floor(helper.geo.origin.windowOffset.top + (helper.geo.origin.size.height / 2));
+ target.right = target.left;
+ }
+ // if multiple client rects exist, the element may be text split
+ // up into multiple lines and the middle of the origin may not be
+ // best option anymore. We need to choose the best target client rect
+ else {
+
+ // top: the first
+ var targetRect = rects[0];
+ target.top = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);
+
+ // right: the middle line, rounded down in case there is an even
+ // number of lines (looks more centered => check out the
+ // demo with 4 split lines)
+ if (rects.length > 2) {
+ targetRect = rects[Math.ceil(rects.length / 2) - 1];
+ }
+ else {
+ targetRect = rects[0];
+ }
+ target.right = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);
+
+ // bottom: the last
+ targetRect = rects[rects.length - 1];
+ target.bottom = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);
+
+ // left: the middle line, rounded up
+ if (rects.length > 2) {
+ targetRect = rects[Math.ceil((rects.length + 1) / 2) - 1];
+ }
+ else {
+ targetRect = rects[rects.length - 1];
+ }
+
+ target.left = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);
+ }
+
+ return target;
+ }
+ }
+});
+
+/* a build task will add "return $;" here */
+return $;
+
+}));
diff --git a/src/lib/vendor/underscore-1.9.1.js b/src/lib/vendor/underscore-1.9.1.js
new file mode 100644
index 0000000..8219dc5
--- /dev/null
+++ b/src/lib/vendor/underscore-1.9.1.js
@@ -0,0 +1,1692 @@
+// Underscore.js 1.9.1
+// http://underscorejs.org
+// (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+
+(function() {
+
+ // Baseline setup
+ // --------------
+
+ // Establish the root object, `window` (`self`) in the browser, `global`
+ // on the server, or `this` in some virtual machines. We use `self`
+ // instead of `window` for `WebWorker` support.
+ var root = typeof self == 'object' && self.self === self && self ||
+ typeof global == 'object' && global.global === global && global ||
+ this ||
+ {};
+
+ // Save the previous value of the `_` variable.
+ var previousUnderscore = root._;
+
+ // Save bytes in the minified (but not gzipped) version:
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype;
+ var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
+
+ // Create quick reference variables for speed access to core prototypes.
+ var push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
+
+ // All **ECMAScript 5** native function implementations that we hope to use
+ // are declared here.
+ var nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeCreate = Object.create;
+
+ // Naked function reference for surrogate-prototype-swapping.
+ var Ctor = function(){};
+
+ // Create a safe reference to the Underscore object for use below.
+ var _ = function(obj) {
+ if (obj instanceof _) return obj;
+ if (!(this instanceof _)) return new _(obj);
+ this._wrapped = obj;
+ };
+
+ // Export the Underscore object for **Node.js**, with
+ // backwards-compatibility for their old module API. If we're in
+ // the browser, add `_` as a global object.
+ // (`nodeType` is checked to ensure that `module`
+ // and `exports` are not HTML elements.)
+ if (typeof exports != 'undefined' && !exports.nodeType) {
+ if (typeof module != 'undefined' && !module.nodeType && module.exports) {
+ exports = module.exports = _;
+ }
+ exports._ = _;
+ } else {
+ root._ = _;
+ }
+
+ // Current version.
+ _.VERSION = '1.9.1';
+
+ // Internal function that returns an efficient (for current engines) version
+ // of the passed-in callback, to be repeatedly applied in other Underscore
+ // functions.
+ var optimizeCb = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ // The 2-argument case is omitted because we’re not using it.
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+ var builtinIteratee;
+
+ // An internal function to generate callbacks that can be applied to each
+ // element in a collection, returning the desired result — either `identity`,
+ // an arbitrary callback, a property matcher, or a property accessor.
+ var cb = function(value, context, argCount) {
+ if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return optimizeCb(value, context, argCount);
+ if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
+ return _.property(value);
+ };
+
+ // External wrapper for our callback generator. Users may customize
+ // `_.iteratee` if they want additional predicate/iteratee shorthand styles.
+ // This abstraction hides the internal-only argCount argument.
+ _.iteratee = builtinIteratee = function(value, context) {
+ return cb(value, context, Infinity);
+ };
+
+ // Some functions take a variable number of arguments, or a few expected
+ // arguments at the beginning and then a variable number of values to operate
+ // on. This helper accumulates all remaining arguments past the function’s
+ // argument length (or an explicit `startIndex`), into an array that becomes
+ // the last argument. Similar to ES6’s "rest parameter".
+ var restArguments = function(func, startIndex) {
+ startIndex = startIndex == null ? func.length - 1 : +startIndex;
+ return function() {
+ var length = Math.max(arguments.length - startIndex, 0),
+ rest = Array(length),
+ index = 0;
+ for (; index < length; index++) {
+ rest[index] = arguments[index + startIndex];
+ }
+ switch (startIndex) {
+ case 0: return func.call(this, rest);
+ case 1: return func.call(this, arguments[0], rest);
+ case 2: return func.call(this, arguments[0], arguments[1], rest);
+ }
+ var args = Array(startIndex + 1);
+ for (index = 0; index < startIndex; index++) {
+ args[index] = arguments[index];
+ }
+ args[startIndex] = rest;
+ return func.apply(this, args);
+ };
+ };
+
+ // An internal function for creating a new object that inherits from another.
+ var baseCreate = function(prototype) {
+ if (!_.isObject(prototype)) return {};
+ if (nativeCreate) return nativeCreate(prototype);
+ Ctor.prototype = prototype;
+ var result = new Ctor;
+ Ctor.prototype = null;
+ return result;
+ };
+
+ var shallowProperty = function(key) {
+ return function(obj) {
+ return obj == null ? void 0 : obj[key];
+ };
+ };
+
+ var has = function(obj, path) {
+ return obj != null && hasOwnProperty.call(obj, path);
+ }
+
+ var deepGet = function(obj, path) {
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ if (obj == null) return void 0;
+ obj = obj[path[i]];
+ }
+ return length ? obj : void 0;
+ };
+
+ // Helper for collection methods to determine whether a collection
+ // should be iterated as an array or as an object.
+ // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
+ // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
+ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
+ var getLength = shallowProperty('length');
+ var isArrayLike = function(collection) {
+ var length = getLength(collection);
+ return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
+ };
+
+ // Collection Functions
+ // --------------------
+
+ // The cornerstone, an `each` implementation, aka `forEach`.
+ // Handles raw objects in addition to array-likes. Treats all
+ // sparse array-likes as if they were dense.
+ _.each = _.forEach = function(obj, iteratee, context) {
+ iteratee = optimizeCb(iteratee, context);
+ var i, length;
+ if (isArrayLike(obj)) {
+ for (i = 0, length = obj.length; i < length; i++) {
+ iteratee(obj[i], i, obj);
+ }
+ } else {
+ var keys = _.keys(obj);
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
+ }
+ }
+ return obj;
+ };
+
+ // Return the results of applying the iteratee to each element.
+ _.map = _.collect = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length);
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Create a reducing function iterating left or right.
+ var createReduce = function(dir) {
+ // Wrap code that reassigns argument variables in a separate function than
+ // the one that accesses `arguments.length` to avoid a perf hit. (#1991)
+ var reducer = function(obj, iteratee, memo, initial) {
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ index = dir > 0 ? 0 : length - 1;
+ if (!initial) {
+ memo = obj[keys ? keys[index] : index];
+ index += dir;
+ }
+ for (; index >= 0 && index < length; index += dir) {
+ var currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
+ }
+ return memo;
+ };
+
+ return function(obj, iteratee, memo, context) {
+ var initial = arguments.length >= 3;
+ return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
+ };
+ };
+
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
+ // or `foldl`.
+ _.reduce = _.foldl = _.inject = createReduce(1);
+
+ // The right-associative version of reduce, also known as `foldr`.
+ _.reduceRight = _.foldr = createReduce(-1);
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, predicate, context) {
+ var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;
+ var key = keyFinder(obj, predicate, context);
+ if (key !== void 0 && key !== -1) return obj[key];
+ };
+
+ // Return all the elements that pass a truth test.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, predicate, context) {
+ var results = [];
+ predicate = cb(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(cb(predicate)), context);
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Aliased as `any`.
+ _.some = _.any = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
+ };
+
+ // Determine if the array or object contains a given item (using `===`).
+ // Aliased as `includes` and `include`.
+ _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ if (typeof fromIndex != 'number' || guard) fromIndex = 0;
+ return _.indexOf(obj, item, fromIndex) >= 0;
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = restArguments(function(obj, path, args) {
+ var contextPath, func;
+ if (_.isFunction(path)) {
+ func = path;
+ } else if (_.isArray(path)) {
+ contextPath = path.slice(0, -1);
+ path = path[path.length - 1];
+ }
+ return _.map(obj, function(context) {
+ var method = func;
+ if (!method) {
+ if (contextPath && contextPath.length) {
+ context = deepGet(context, contextPath);
+ }
+ if (context == null) return void 0;
+ method = context[path];
+ }
+ return method == null ? method : method.apply(context, args);
+ });
+ });
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, _.property(key));
+ };
+
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // containing specific `key:value` pairs.
+ _.where = function(obj, attrs) {
+ return _.filter(obj, _.matcher(attrs));
+ };
+
+ // Convenience version of a common use case of `find`: getting the first object
+ // containing specific `key:value` pairs.
+ _.findWhere = function(obj, attrs) {
+ return _.find(obj, _.matcher(attrs));
+ };
+
+ // Return the maximum element (or element-based computation).
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value > result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value < result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Shuffle a collection.
+ _.shuffle = function(obj) {
+ return _.sample(obj, Infinity);
+ };
+
+ // Sample **n** random values from a collection using the modern version of the
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
+ // If **n** is not specified, returns a single random element.
+ // The internal `guard` argument allows it to work with `map`.
+ _.sample = function(obj, n, guard) {
+ if (n == null || guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ return obj[_.random(obj.length - 1)];
+ }
+ var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
+ var length = getLength(sample);
+ n = Math.max(Math.min(n, length), 0);
+ var last = length - 1;
+ for (var index = 0; index < n; index++) {
+ var rand = _.random(index, last);
+ var temp = sample[index];
+ sample[index] = sample[rand];
+ sample[rand] = temp;
+ }
+ return sample.slice(0, n);
+ };
+
+ // Sort the object's values by a criterion produced by an iteratee.
+ _.sortBy = function(obj, iteratee, context) {
+ var index = 0;
+ iteratee = cb(iteratee, context);
+ return _.pluck(_.map(obj, function(value, key, list) {
+ return {
+ value: value,
+ index: index++,
+ criteria: iteratee(value, key, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index - right.index;
+ }), 'value');
+ };
+
+ // An internal function used for aggregate "group by" operations.
+ var group = function(behavior, partition) {
+ return function(obj, iteratee, context) {
+ var result = partition ? [[], []] : {};
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
+ });
+ return result;
+ };
+ };
+
+ // Groups the object's values by a criterion. Pass either a string attribute
+ // to group by, or a function that returns the criterion.
+ _.groupBy = group(function(result, value, key) {
+ if (has(result, key)) result[key].push(value); else result[key] = [value];
+ });
+
+ // Indexes the object's values by a criterion, similar to `groupBy`, but for
+ // when you know that your index values will be unique.
+ _.indexBy = group(function(result, value, key) {
+ result[key] = value;
+ });
+
+ // Counts instances of an object that group by a certain criterion. Pass
+ // either a string attribute to count by, or a function that returns the
+ // criterion.
+ _.countBy = group(function(result, value, key) {
+ if (has(result, key)) result[key]++; else result[key] = 1;
+ });
+
+ var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
+ // Safely create a real, live array from anything iterable.
+ _.toArray = function(obj) {
+ if (!obj) return [];
+ if (_.isArray(obj)) return slice.call(obj);
+ if (_.isString(obj)) {
+ // Keep surrogate pair characters together
+ return obj.match(reStrSymbol);
+ }
+ if (isArrayLike(obj)) return _.map(obj, _.identity);
+ return _.values(obj);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ if (obj == null) return 0;
+ return isArrayLike(obj) ? obj.length : _.keys(obj).length;
+ };
+
+ // Split a collection into two arrays: one whose elements all satisfy the given
+ // predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = group(function(result, value, pass) {
+ result[pass ? 0 : 1].push(value);
+ }, true);
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head` and `take`. The **guard** check
+ // allows it to work with `_.map`.
+ _.first = _.head = _.take = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[0];
+ return _.initial(array, array.length - n);
+ };
+
+ // Returns everything but the last entry of the array. Especially useful on
+ // the arguments object. Passing **n** will return all the values in
+ // the array, excluding the last N.
+ _.initial = function(array, n, guard) {
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+ };
+
+ // Get the last element of an array. Passing **n** will return the last N
+ // values in the array.
+ _.last = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[array.length - 1];
+ return _.rest(array, Math.max(0, array.length - n));
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+ // Especially useful on the arguments object. Passing an **n** will return
+ // the rest N values in the array.
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, n == null || guard ? 1 : n);
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, Boolean);
+ };
+
+ // Internal implementation of a recursive `flatten` function.
+ var flatten = function(input, shallow, strict, output) {
+ output = output || [];
+ var idx = output.length;
+ for (var i = 0, length = getLength(input); i < length; i++) {
+ var value = input[i];
+ if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
+ // Flatten current level of array or arguments object.
+ if (shallow) {
+ var j = 0, len = value.length;
+ while (j < len) output[idx++] = value[j++];
+ } else {
+ flatten(value, shallow, strict, output);
+ idx = output.length;
+ }
+ } else if (!strict) {
+ output[idx++] = value;
+ }
+ }
+ return output;
+ };
+
+ // Flatten out an array, either recursively (by default), or just one level.
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, false);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = restArguments(function(array, otherArrays) {
+ return _.difference(array, otherArrays);
+ });
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // The faster algorithm will not work with an iteratee if the iteratee
+ // is not a one-to-one function, so providing an iteratee will disable
+ // the faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
+ isSorted = false;
+ }
+ if (iteratee != null) iteratee = cb(iteratee, context);
+ var result = [];
+ var seen = [];
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var value = array[i],
+ computed = iteratee ? iteratee(value, i, array) : value;
+ if (isSorted && !iteratee) {
+ if (!i || seen !== computed) result.push(value);
+ seen = computed;
+ } else if (iteratee) {
+ if (!_.contains(seen, computed)) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (!_.contains(result, value)) {
+ result.push(value);
+ }
+ }
+ return result;
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = restArguments(function(arrays) {
+ return _.uniq(flatten(arrays, true, true));
+ });
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays.
+ _.intersection = function(array) {
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ var j;
+ for (j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
+ };
+
+ // Take the difference between one array and a number of other arrays.
+ // Only the elements present in just the first array will remain.
+ _.difference = restArguments(function(array, rest) {
+ rest = flatten(rest, true, true);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
+ });
+
+ // Complement of _.zip. Unzip accepts an array of arrays and groups
+ // each array's elements on shared indices.
+ _.unzip = function(array) {
+ var length = array && _.max(array, getLength).length || 0;
+ var result = Array(length);
+
+ for (var index = 0; index < length; index++) {
+ result[index] = _.pluck(array, index);
+ }
+ return result;
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = restArguments(_.unzip);
+
+ // Converts lists into objects. Pass either a single array of `[key, value]`
+ // pairs, or two parallel arrays of the same length -- one of keys, and one of
+ // the corresponding values. Passing by pairs is the reverse of _.pairs.
+ _.object = function(list, values) {
+ var result = {};
+ for (var i = 0, length = getLength(list); i < length; i++) {
+ if (values) {
+ result[list[i]] = values[i];
+ } else {
+ result[list[i][0]] = list[i][1];
+ }
+ }
+ return result;
+ };
+
+ // Generator function to create the findIndex and findLastIndex functions.
+ var createPredicateIndexFinder = function(dir) {
+ return function(array, predicate, context) {
+ predicate = cb(predicate, context);
+ var length = getLength(array);
+ var index = dir > 0 ? 0 : length - 1;
+ for (; index >= 0 && index < length; index += dir) {
+ if (predicate(array[index], index, array)) return index;
+ }
+ return -1;
+ };
+ };
+
+ // Returns the first index on an array-like that passes a predicate test.
+ _.findIndex = createPredicateIndexFinder(1);
+ _.findLastIndex = createPredicateIndexFinder(-1);
+
+ // Use a comparator function to figure out the smallest index at which
+ // an object should be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iteratee, context) {
+ iteratee = cb(iteratee, context, 1);
+ var value = iteratee(obj);
+ var low = 0, high = getLength(array);
+ while (low < high) {
+ var mid = Math.floor((low + high) / 2);
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
+ }
+ return low;
+ };
+
+ // Generator function to create the indexOf and lastIndexOf functions.
+ var createIndexFinder = function(dir, predicateFind, sortedIndex) {
+ return function(array, item, idx) {
+ var i = 0, length = getLength(array);
+ if (typeof idx == 'number') {
+ if (dir > 0) {
+ i = idx >= 0 ? idx : Math.max(idx + length, i);
+ } else {
+ length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
+ }
+ } else if (sortedIndex && idx && length) {
+ idx = sortedIndex(array, item);
+ return array[idx] === item ? idx : -1;
+ }
+ if (item !== item) {
+ idx = predicateFind(slice.call(array, i, length), _.isNaN);
+ return idx >= 0 ? idx + i : -1;
+ }
+ for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
+ if (array[idx] === item) return idx;
+ }
+ return -1;
+ };
+ };
+
+ // Return the position of the first occurrence of an item in an array,
+ // or -1 if the item is not included in the array.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
+ _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (stop == null) {
+ stop = start || 0;
+ start = 0;
+ }
+ if (!step) {
+ step = stop < start ? -1 : 1;
+ }
+
+ var length = Math.max(Math.ceil((stop - start) / step), 0);
+ var range = Array(length);
+
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
+ }
+
+ return range;
+ };
+
+ // Chunk a single array into multiple arrays, each containing `count` or fewer
+ // items.
+ _.chunk = function(array, count) {
+ if (count == null || count < 1) return [];
+ var result = [];
+ var i = 0, length = array.length;
+ while (i < length) {
+ result.push(slice.call(array, i, i += count));
+ }
+ return result;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Determines whether to execute a function as a constructor
+ // or a normal function with the provided arguments.
+ var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
+ if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+ var self = baseCreate(sourceFunc.prototype);
+ var result = sourceFunc.apply(self, args);
+ if (_.isObject(result)) return result;
+ return self;
+ };
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+ // available.
+ _.bind = restArguments(function(func, context, args) {
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+ var bound = restArguments(function(callArgs) {
+ return executeBound(func, bound, context, this, args.concat(callArgs));
+ });
+ return bound;
+ });
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
+ // as a placeholder by default, allowing any combination of arguments to be
+ // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
+ _.partial = restArguments(function(func, boundArgs) {
+ var placeholder = _.partial.placeholder;
+ var bound = function() {
+ var position = 0, length = boundArgs.length;
+ var args = Array(length);
+ for (var i = 0; i < length; i++) {
+ args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
+ }
+ while (position < arguments.length) args.push(arguments[position++]);
+ return executeBound(func, bound, this, this, args);
+ };
+ return bound;
+ });
+
+ _.partial.placeholder = _;
+
+ // Bind a number of an object's methods to that object. Remaining arguments
+ // are the method names to be bound. Useful for ensuring that all callbacks
+ // defined on an object belong to it.
+ _.bindAll = restArguments(function(obj, keys) {
+ keys = flatten(keys, false, false);
+ var index = keys.length;
+ if (index < 1) throw new Error('bindAll must be passed function names');
+ while (index--) {
+ var key = keys[index];
+ obj[key] = _.bind(obj[key], obj);
+ }
+ });
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = '' + (hasher ? hasher.apply(this, arguments) : key);
+ if (!has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
+ };
+ memoize.cache = {};
+ return memoize;
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = restArguments(function(func, wait, args) {
+ return setTimeout(function() {
+ return func.apply(null, args);
+ }, wait);
+ });
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = _.partial(_.delay, _, 1);
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time. Normally, the throttled function will run
+ // as much as it can, without ever going more than once per `wait` duration;
+ // but if you'd like to disable the execution on the leading edge, pass
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
+ _.throttle = function(func, wait, options) {
+ var timeout, context, args, result;
+ var previous = 0;
+ if (!options) options = {};
+
+ var later = function() {
+ previous = options.leading === false ? 0 : _.now();
+ timeout = null;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ };
+
+ var throttled = function() {
+ var now = _.now();
+ if (!previous && options.leading === false) previous = now;
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0 || remaining > wait) {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ previous = now;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ } else if (!timeout && options.trailing !== false) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+
+ throttled.cancel = function() {
+ clearTimeout(timeout);
+ previous = 0;
+ timeout = context = args = null;
+ };
+
+ return throttled;
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds. If `immediate` is passed, trigger the function on the
+ // leading edge, instead of the trailing.
+ _.debounce = function(func, wait, immediate) {
+ var timeout, result;
+
+ var later = function(context, args) {
+ timeout = null;
+ if (args) result = func.apply(context, args);
+ };
+
+ var debounced = restArguments(function(args) {
+ if (timeout) clearTimeout(timeout);
+ if (immediate) {
+ var callNow = !timeout;
+ timeout = setTimeout(later, wait);
+ if (callNow) result = func.apply(this, args);
+ } else {
+ timeout = _.delay(later, wait, this, args);
+ }
+
+ return result;
+ });
+
+ debounced.cancel = function() {
+ clearTimeout(timeout);
+ timeout = null;
+ };
+
+ return debounced;
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+ // Returns a negated version of the passed-in predicate.
+ _.negate = function(predicate) {
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var args = arguments;
+ var start = args.length - 1;
+ return function() {
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
+ };
+ };
+
+ // Returns a function that will only be executed on and after the Nth call.
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ };
+
+ // Returns a function that will only be executed up to (but not including) the Nth call.
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ }
+ if (times <= 1) func = null;
+ return memo;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
+ _.restArguments = restArguments;
+
+ // Object Functions
+ // ----------------
+
+ // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
+ var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+ var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+
+ var collectNonEnumProps = function(obj, keys) {
+ var nonEnumIdx = nonEnumerableProps.length;
+ var constructor = obj.constructor;
+ var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
+
+ // Constructor is a special case.
+ var prop = 'constructor';
+ if (has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
+
+ while (nonEnumIdx--) {
+ prop = nonEnumerableProps[nonEnumIdx];
+ if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
+ keys.push(prop);
+ }
+ }
+ };
+
+ // Retrieve the names of an object's own properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`.
+ _.keys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ if (nativeKeys) return nativeKeys(obj);
+ var keys = [];
+ for (var key in obj) if (has(obj, key)) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve all the property names of an object.
+ _.allKeys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var values = Array(length);
+ for (var i = 0; i < length; i++) {
+ values[i] = obj[keys[i]];
+ }
+ return values;
+ };
+
+ // Returns the results of applying the iteratee to each element of the object.
+ // In contrast to _.map it returns an object.
+ _.mapObject = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = _.keys(obj),
+ length = keys.length,
+ results = {};
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys[index];
+ results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Convert an object into a list of `[key, value]` pairs.
+ // The opposite of _.object.
+ _.pairs = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var pairs = Array(length);
+ for (var i = 0; i < length; i++) {
+ pairs[i] = [keys[i], obj[keys[i]]];
+ }
+ return pairs;
+ };
+
+ // Invert the keys and values of an object. The values must be serializable.
+ _.invert = function(obj) {
+ var result = {};
+ var keys = _.keys(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ result[obj[keys[i]]] = keys[i];
+ }
+ return result;
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`.
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // An internal function for creating assigner functions.
+ var createAssigner = function(keysFunc, defaults) {
+ return function(obj) {
+ var length = arguments.length;
+ if (defaults) obj = Object(obj);
+ if (length < 2 || obj == null) return obj;
+ for (var index = 1; index < length; index++) {
+ var source = arguments[index],
+ keys = keysFunc(source),
+ l = keys.length;
+ for (var i = 0; i < l; i++) {
+ var key = keys[i];
+ if (!defaults || obj[key] === void 0) obj[key] = source[key];
+ }
+ }
+ return obj;
+ };
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = createAssigner(_.allKeys);
+
+ // Assigns a given object with all the own properties in the passed-in object(s).
+ // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+ _.extendOwn = _.assign = createAssigner(_.keys);
+
+ // Returns the first key on an object that passes a predicate test.
+ _.findKey = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = _.keys(obj), key;
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (predicate(obj[key], key, obj)) return key;
+ }
+ };
+
+ // Internal pick helper function to determine if `obj` has key `key`.
+ var keyInObj = function(value, key, obj) {
+ return key in obj;
+ };
+
+ // Return a copy of the object only containing the whitelisted properties.
+ _.pick = restArguments(function(obj, keys) {
+ var result = {}, iteratee = keys[0];
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
+ keys = _.allKeys(obj);
+ } else {
+ iteratee = keyInObj;
+ keys = flatten(keys, false, false);
+ obj = Object(obj);
+ }
+ for (var i = 0, length = keys.length; i < length; i++) {
+ var key = keys[i];
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ return result;
+ });
+
+ // Return a copy of the object without the blacklisted properties.
+ _.omit = restArguments(function(obj, keys) {
+ var iteratee = keys[0], context;
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ if (keys.length > 1) context = keys[1];
+ } else {
+ keys = _.map(flatten(keys, false, false), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
+ }
+ return _.pick(obj, iteratee, context);
+ });
+
+ // Fill in a given object with default properties.
+ _.defaults = createAssigner(_.allKeys, true);
+
+ // Creates an object that inherits from the given prototype object.
+ // If additional properties are provided then they will be added to the
+ // created object.
+ _.create = function(prototype, props) {
+ var result = baseCreate(prototype);
+ if (props) _.extendOwn(result, props);
+ return result;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Returns whether an object has a given set of `key:value` pairs.
+ _.isMatch = function(object, attrs) {
+ var keys = _.keys(attrs), length = keys.length;
+ if (object == null) return !length;
+ var obj = Object(object);
+ for (var i = 0; i < length; i++) {
+ var key = keys[i];
+ if (attrs[key] !== obj[key] || !(key in obj)) return false;
+ }
+ return true;
+ };
+
+
+ // Internal recursive comparison function for `isEqual`.
+ var eq, deepEq;
+ eq = function(a, b, aStack, bStack) {
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
+ // `null` or `undefined` only equal to itself (strict comparison).
+ if (a == null || b == null) return false;
+ // `NaN`s are equivalent, but non-reflexive.
+ if (a !== a) return b !== b;
+ // Exhaust primitive checks
+ var type = typeof a;
+ if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
+ return deepEq(a, b, aStack, bStack);
+ };
+
+ // Internal recursive comparison function for `isEqual`.
+ deepEq = function(a, b, aStack, bStack) {
+ // Unwrap any wrapped objects.
+ if (a instanceof _) a = a._wrapped;
+ if (b instanceof _) b = b._wrapped;
+ // Compare `[[Class]]` names.
+ var className = toString.call(a);
+ if (className !== toString.call(b)) return false;
+ switch (className) {
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+ case '[object RegExp]':
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return '' + a === '' + b;
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive.
+ // Object(NaN) is equivalent to NaN.
+ if (+a !== +a) return +b !== +b;
+ // An `egal` comparison is performed for other numeric values.
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a === +b;
+ case '[object Symbol]':
+ return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
+ }
+
+ var areArrays = className === '[object Array]';
+ if (!areArrays) {
+ if (typeof a != 'object' || typeof b != 'object') return false;
+
+ // Objects with different constructors are not equivalent, but `Object`s or `Array`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ && ('constructor' in a && 'constructor' in b)) {
+ return false;
+ }
+ }
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+
+ // Initializing stack of traversed objects.
+ // It's done here since we only need them for objects and arrays comparison.
+ aStack = aStack || [];
+ bStack = bStack || [];
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] === a) return bStack[length] === b;
+ }
+
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+
+ // Recursively compare objects and arrays.
+ if (areArrays) {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ length = a.length;
+ if (length !== b.length) return false;
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (length--) {
+ if (!eq(a[length], b[length], aStack, bStack)) return false;
+ }
+ } else {
+ // Deep compare objects.
+ var keys = _.keys(a), key;
+ length = keys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (_.keys(b).length !== length) return false;
+ while (length--) {
+ // Deep compare each member
+ key = keys[length];
+ if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return true;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ return eq(a, b);
+ };
+
+ // Is a given array, string, or object empty?
+ // An "empty" object has no enumerable own-properties.
+ _.isEmpty = function(obj) {
+ if (obj == null) return true;
+ if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
+ return _.keys(obj).length === 0;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) === '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet.
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) === '[object ' + name + ']';
+ };
+ });
+
+ // Define a fallback version of the method in browsers (ahem, IE < 9), where
+ // there isn't any inspectable "Arguments" type.
+ if (!_.isArguments(arguments)) {
+ _.isArguments = function(obj) {
+ return has(obj, 'callee');
+ };
+ }
+
+ // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
+ // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
+ var nodelist = root.document && root.document.childNodes;
+ if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj == 'function' || false;
+ };
+ }
+
+ // Is a given object a finite number?
+ _.isFinite = function(obj) {
+ return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj));
+ };
+
+ // Is the given value `NaN`?
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && isNaN(obj);
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Shortcut function for checking if an object has a given property directly
+ // on itself (in other words, not on a prototype).
+ _.has = function(obj, path) {
+ if (!_.isArray(path)) {
+ return has(obj, path);
+ }
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ var key = path[i];
+ if (obj == null || !hasOwnProperty.call(obj, key)) {
+ return false;
+ }
+ obj = obj[key];
+ }
+ return !!length;
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iteratees.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Predicate-generating functions. Often useful outside of Underscore.
+ _.constant = function(value) {
+ return function() {
+ return value;
+ };
+ };
+
+ _.noop = function(){};
+
+ // Creates a function that, when passed an object, will traverse that object’s
+ // properties down the given `path`, specified as an array of keys or indexes.
+ _.property = function(path) {
+ if (!_.isArray(path)) {
+ return shallowProperty(path);
+ }
+ return function(obj) {
+ return deepGet(obj, path);
+ };
+ };
+
+ // Generates a function for a given object that returns a given property.
+ _.propertyOf = function(obj) {
+ if (obj == null) {
+ return function(){};
+ }
+ return function(path) {
+ return !_.isArray(path) ? obj[path] : deepGet(obj, path);
+ };
+ };
+
+ // Returns a predicate for checking whether an object has a given set of
+ // `key:value` pairs.
+ _.matcher = _.matches = function(attrs) {
+ attrs = _.extendOwn({}, attrs);
+ return function(obj) {
+ return _.isMatch(obj, attrs);
+ };
+ };
+
+ // Run a function **n** times.
+ _.times = function(n, iteratee, context) {
+ var accum = Array(Math.max(0, n));
+ iteratee = optimizeCb(iteratee, context, 1);
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
+ return accum;
+ };
+
+ // Return a random integer between min and max (inclusive).
+ _.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1));
+ };
+
+ // A (possibly faster) way to get the current timestamp as an integer.
+ _.now = Date.now || function() {
+ return new Date().getTime();
+ };
+
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#x27;',
+ '`': '&#x60;'
+ };
+ var unescapeMap = _.invert(escapeMap);
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ var createEscaper = function(map) {
+ var escaper = function(match) {
+ return map[match];
+ };
+ // Regexes for identifying a key that needs to be escaped.
+ var source = '(?:' + _.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+ _.escape = createEscaper(escapeMap);
+ _.unescape = createEscaper(unescapeMap);
+
+ // Traverses the children of `obj` along `path`. If a child is a function, it
+ // is invoked with its parent as context. Returns the value of the final
+ // child, or `fallback` if any child is undefined.
+ _.result = function(obj, path, fallback) {
+ if (!_.isArray(path)) path = [path];
+ var length = path.length;
+ if (!length) {
+ return _.isFunction(fallback) ? fallback.call(obj) : fallback;
+ }
+ for (var i = 0; i < length; i++) {
+ var prop = obj == null ? void 0 : obj[path[i]];
+ if (prop === void 0) {
+ prop = fallback;
+ i = length; // Ensure we don't continue iterating.
+ }
+ obj = _.isFunction(prop) ? prop.call(obj) : prop;
+ }
+ return obj;
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = ++idCounter + '';
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate: /<%([\s\S]+?)%>/g,
+ interpolate: /<%=([\s\S]+?)%>/g,
+ escape: /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
+
+ var escapeChar = function(match) {
+ return '\\' + escapes[match];
+ };
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ // NB: `oldSettings` only exists for backwards compatibility.
+ _.template = function(text, settings, oldSettings) {
+ if (!settings && oldSettings) settings = oldSettings;
+ settings = _.defaults({}, settings, _.templateSettings);
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
+ index = offset + match.length;
+
+ if (escape) {
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+ } else if (interpolate) {
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+ } else if (evaluate) {
+ source += "';\n" + evaluate + "\n__p+='";
+ }
+
+ // Adobe VMs need the match returned to produce the correct offset.
+ return match;
+ });
+ source += "';\n";
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+ source = "var __t,__p='',__j=Array.prototype.join," +
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
+ source + 'return __p;\n';
+
+ var render;
+ try {
+ render = new Function(settings.variable || 'obj', '_', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ var template = function(data) {
+ return render.call(this, data, _);
+ };
+
+ // Provide the compiled source as a convenience for precompilation.
+ var argument = settings.variable || 'obj';
+ template.source = 'function(' + argument + '){\n' + source + '}';
+
+ return template;
+ };
+
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
+ _.chain = function(obj) {
+ var instance = _(obj);
+ instance._chain = true;
+ return instance;
+ };
+
+ // OOP
+ // ---------------
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+
+ // Helper function to continue chaining intermediate results.
+ var chainResult = function(instance, obj) {
+ return instance._chain ? _(obj).chain() : obj;
+ };
+
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ _.each(_.functions(obj), function(name) {
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return chainResult(this, func.apply(_, args));
+ };
+ });
+ return _;
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ var obj = this._wrapped;
+ method.apply(obj, arguments);
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+ return chainResult(this, obj);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ _.each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ return chainResult(this, method.apply(this._wrapped, arguments));
+ };
+ });
+
+ // Extracts the result from a wrapped and chained object.
+ _.prototype.value = function() {
+ return this._wrapped;
+ };
+
+ // Provide unwrapping proxy for some methods used in engine operations
+ // such as arithmetic and JSON stringification.
+ _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
+
+ _.prototype.toString = function() {
+ return String(this._wrapped);
+ };
+
+ // AMD registration happens at the end for compatibility with AMD loaders
+ // that may not enforce next-turn semantics on modules. Even though general
+ // practice for AMD registration is to be anonymous, underscore registers
+ // as a named module because, like jQuery, it is a base library that is
+ // popular enough to be bundled in a third party lib, but not be part of
+ // an AMD load request. Those cases could generate an error when an
+ // anonymous define() is called outside of a loader request.
+ if (typeof define == 'function' && define.amd) {
+ define('underscore', [], function() {
+ return _;
+ });
+ }
+}());