/*!
 * Sizzle CSS Selector Engine v2.2.0-pre
 * http://sizzlejs.com/
 *
 * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2014-12-16
 */
(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(),
    sortOrder = function(a, b) {
      if (a === b) {
        hasDuplicate = true;
      }
      return 0;
    },
    // General-purpose constants
    MAX_NEGATIVE = 1 << 31,
    // Instance methods
    hasOwn = {}.hasOwnProperty,
    arr = [],
    pop = arr.pop,
    push_native = arr.push,
    push = arr.push,
    slice = arr.slice,
    // Use a stripped-down indexOf as it's faster than native
    // http://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

    // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
    whitespace = '[\\x20\\t\\r\\n\\f]',
    // http://www.w3.org/TR/css3-syntax/#characters
    characterEncoding = '(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+',
    // Loosely modeled on CSS identifier characters
    // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
    // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
    identifier = characterEncoding.replace('w', 'w#'),
    // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
    attributes =
      '\\[' +
      whitespace +
      '*(' +
      characterEncoding +
      ')(?:' +
      whitespace +
      // Operator (capture 2)
      '*([*^$|!~]?=)' +
      whitespace +
      // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
      '*(?:\'((?:\\\\.|[^\\\\\'])*)\'|"((?:\\\\.|[^\\\\"])*)"|(' +
      identifier +
      '))|)' +
      whitespace +
      '*\\]',
    pseudos =
      ':(' +
      characterEncoding +
      ')(?:\\((' +
      // 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 + '*'
    ),
    rattributeQuotes = new RegExp(
      '=' + whitespace + '*([^\\]\'"]*?)' + whitespace + '*\\]',
      'g'
    ),
    rpseudo = new RegExp(pseudos),
    ridentifier = new RegExp('^' + identifier + '$'),
    matchExpr = {
      ID: new RegExp('^#(' + characterEncoding + ')'),
      CLASS: new RegExp('^\\.(' + characterEncoding + ')'),
      TAG: new RegExp('^(' + characterEncoding.replace('w', 'w*') + ')'),
      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'
      ),
    },
    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 = /[+~]/,
    rescape = /'|\\/g,
    // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
    runescape = new RegExp(
      '\\\\([\\da-f]{1,6}' + whitespace + '?|(' + whitespace + ')|.)',
      'ig'
    ),
    funescape = function(_, escaped, escapedWhitespace) {
      var high = '0x' + escaped - 0x10000;
      // NaN means non-codepoint
      // Support: Firefox<24
      // Workaround erroneous numeric interpretation of +"0x"
      return high !== high || escapedWhitespace
        ? escaped
        : high < 0
          ? // BMP codepoint
            String.fromCharCode(high + 0x10000)
          : // Supplemental Plane codepoint (surrogate pair)
            String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
    },
    // Used for iframes
    // See setDocument()
    // Removing the function wrapper causes a "Permission Denied"
    // error in IE
    unloadHandler = function() {
      setDocument();
    };

  // Optimize for push.apply( _, NodeList )
  try {
    push.apply(
      (arr = slice.call(preferredDoc.childNodes)),
      preferredDoc.childNodes
    );
    // Support: Android<4.0
    // Detect silently failing push.apply
    arr[preferredDoc.childNodes.length].nodeType;
  } catch (e) {
    push = {
      apply: arr.length
        ? // Leverage slice if possible
          function(target, els) {
            push_native.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 match,
      elem,
      m,
      nodeType,
      // QSA vars
      i,
      groups,
      old,
      nid,
      newContext,
      newSelector;

    if (
      (context ? context.ownerDocument || context : preferredDoc) !== document
    ) {
      setDocument(context);
    }

    context = context || document;
    results = results || [];
    nodeType = context.nodeType;

    if (
      typeof selector !== 'string' ||
      !selector ||
      (nodeType !== 1 && nodeType !== 9 && nodeType !== 11)
    ) {
      return results;
    }

    if (!seed && documentIsHTML) {
      // Try to shortcut find operations when possible (e.g., not under DocumentFragment)
      if (nodeType !== 11 && (match = rquickExpr.exec(selector))) {
        // Speed-up: Sizzle("#ID")
        if ((m = match[1])) {
          if (nodeType === 9) {
            elem = context.getElementById(m);
            // Check parentNode to catch when Blackberry 4.6 returns
            // nodes that are no longer in the document (jQuery #6963)
            if (elem && elem.parentNode) {
              // Handle the case where IE, Opera, and Webkit return items
              // by name instead of ID
              if (elem.id === m) {
                results.push(elem);
                return results;
              }
            } else {
              return results;
            }
          } else {
            // Context is not a document
            if (
              context.ownerDocument &&
              (elem = context.ownerDocument.getElementById(m)) &&
              contains(context, elem) &&
              elem.id === m
            ) {
              results.push(elem);
              return results;
            }
          }

          // Speed-up: Sizzle("TAG")
        } else if (match[2]) {
          push.apply(results, context.getElementsByTagName(selector));
          return results;

          // Speed-up: Sizzle(".CLASS")
        } else if ((m = match[3]) && support.getElementsByClassName) {
          push.apply(results, context.getElementsByClassName(m));
          return results;
        }
      }

      // QSA path
      if (support.qsa && (!rbuggyQSA || !rbuggyQSA.test(selector))) {
        nid = old = expando;
        newContext = context;
        newSelector = nodeType !== 1 && selector;

        // qSA works strangely on Element-rooted queries
        // We can work around this by specifying an extra ID on the root
        // and working up from there (Thanks to Andrew Dupont for the technique)
        // IE 8 doesn't work on object elements
        if (nodeType === 1 && context.nodeName.toLowerCase() !== 'object') {
          groups = tokenize(selector);

          if ((old = context.getAttribute('id'))) {
            nid = old.replace(rescape, '\\$&');
          } else {
            context.setAttribute('id', nid);
          }
          nid = "[id='" + nid + "'] ";

          i = groups.length;
          while (i--) {
            groups[i] = nid + toSelector(groups[i]);
          }
          newContext =
            (rsibling.test(selector) && testContext(context.parentNode)) ||
            context;
          newSelector = groups.join(',');
        }

        if (newSelector) {
          try {
            push.apply(results, newContext.querySelectorAll(newSelector));
            return results;
          } catch (qsaError) {
          } finally {
            if (!old) {
              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 div and expects a boolean result
   */
  function assert(fn) {
    var div = document.createElement('div');

    try {
      return !!fn(div);
    } catch (e) {
      return false;
    } finally {
      // Remove from its parent by default
      if (div.parentNode) {
        div.parentNode.removeChild(div);
      }
      // release memory in IE
      div = 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 = attrs.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 &&
        (~b.sourceIndex || MAX_NEGATIVE) - (~a.sourceIndex || MAX_NEGATIVE);

    // 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 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) {
    // documentElement is verified for cases where it doesn't yet exist
    // (such as loading iframes in IE - #4833)
    var documentElement = elem && (elem.ownerDocument || elem).documentElement;
    return documentElement ? documentElement.nodeName !== 'HTML' : false;
  };

  /**
   * 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,
      parent,
      doc = node ? node.ownerDocument || node : preferredDoc;

    // If no document and documentElement is available, return
    if (doc === document || doc.nodeType !== 9 || !doc.documentElement) {
      return document;
    }

    // Set our document
    document = doc;
    docElem = doc.documentElement;
    parent = doc.defaultView;

    // Support: IE>8
    // If iframe document is assigned to "document" variable and if iframe has been reloaded,
    // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
    // IE6-8 do not support the defaultView property so parent will be undefined
    if (parent && parent !== parent.top) {
      // IE11 does not have attachEvent, so all must suffer
      if (parent.addEventListener) {
        parent.addEventListener('unload', unloadHandler, false);
      } else if (parent.attachEvent) {
        parent.attachEvent('onunload', unloadHandler);
      }
    }

    /* Support tests
	---------------------------------------------------------------------- */
    documentIsHTML = !isXML(doc);

    /* Attributes
	---------------------------------------------------------------------- */

    // Support: IE<8
    // Verify that getAttribute really returns attributes and not properties
    // (excepting IE8 booleans)
    support.attributes = assert(function(div) {
      div.className = 'i';
      return !div.getAttribute('className');
    });

    /* getElement(s)By*
	---------------------------------------------------------------------- */

    // Check if getElementsByTagName("*") returns only elements
    support.getElementsByTagName = assert(function(div) {
      div.appendChild(doc.createComment(''));
      return !div.getElementsByTagName('*').length;
    });

    // Support: IE<9
    support.getElementsByClassName = rnative.test(doc.getElementsByClassName);

    // Support: IE<10
    // Check if getElementById returns elements by name
    // The broken getElementById methods don't pick up programatically-set names,
    // so use a roundabout getElementsByName test
    support.getById = assert(function(div) {
      docElem.appendChild(div).id = expando;
      return !doc.getElementsByName || !doc.getElementsByName(expando).length;
    });

    // ID find and filter
    if (support.getById) {
      Expr.find['ID'] = function(id, context) {
        if (typeof context.getElementById !== 'undefined' && documentIsHTML) {
          var m = context.getElementById(id);
          // Check parentNode to catch when Blackberry 4.6 returns
          // nodes that are no longer in the document #6963
          return m && m.parentNode ? [m] : [];
        }
      };
      Expr.filter['ID'] = function(id) {
        var attrId = id.replace(runescape, funescape);
        return function(elem) {
          return elem.getAttribute('id') === attrId;
        };
      };
    } else {
      // Support: IE6/7
      // getElementById is not reliable as a find shortcut
      delete Expr.find['ID'];

      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;
        };
      };
    }

    // 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 (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 http://bugs.jquery.com/ticket/13378
    rbuggyQSA = [];

    if ((support.qsa = rnative.test(doc.querySelectorAll))) {
      // Build QSA regex
      // Regex strategy adopted from Diego Perini
      assert(function(div) {
        // 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
        // http://bugs.jquery.com/ticket/12359
        docElem.appendChild(div).innerHTML =
          "<a id='" +
          expando +
          "'></a>" +
          "<select id='" +
          expando +
          "-\f]' 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
        // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
        if (div.querySelectorAll("[msallowcapture^='']").length) {
          rbuggyQSA.push('[*^$]=' + whitespace + '*(?:\'\'|"")');
        }

        // Support: IE8
        // Boolean attributes and "value" are not treated correctly
        if (!div.querySelectorAll('[selected]').length) {
          rbuggyQSA.push('\\[' + whitespace + '*(?:value|' + booleans + ')');
        }

        // Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
        if (!div.querySelectorAll('[id~=' + expando + '-]').length) {
          rbuggyQSA.push('~=');
        }

        // 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 (!div.querySelectorAll(':checked').length) {
          rbuggyQSA.push(':checked');
        }

        // Support: Safari 8+, iOS 8+
        // https://bugs.webkit.org/show_bug.cgi?id=136851
        // In-page `selector#id sibing-combinator selector` fails
        if (!div.querySelectorAll('a#' + expando + '+*').length) {
          rbuggyQSA.push('.#.+[+~]');
        }
      });

      assert(function(div) {
        // Support: Windows 8 Native Apps
        // The type and name attributes are restricted during .innerHTML assignment
        var input = doc.createElement('input');
        input.setAttribute('type', 'hidden');
        div.appendChild(input).setAttribute('name', 'D');

        // Support: IE8
        // Enforce case-sensitivity of name attribute
        if (div.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 (!div.querySelectorAll(':enabled').length) {
          rbuggyQSA.push(':enabled', ':disabled');
        }

        // Opera 10-11 does not throw on post-comma invalid pseudos
        div.querySelectorAll('*,:x');
        rbuggyQSA.push(',.*:');
      });
    }

    if (
      (support.matchesSelector = rnative.test(
        (matches =
          docElem.matches ||
          docElem.webkitMatchesSelector ||
          docElem.mozMatchesSelector ||
          docElem.oMatchesSelector ||
          docElem.msMatchesSelector)
      ))
    ) {
      assert(function(div) {
        // Check to see if it's possible to do matchesSelector
        // on a disconnected node (IE 9)
        support.disconnectedMatch = matches.call(div, 'div');

        // This should fail with an exception
        // Gecko does not error, returns false instead
        matches.call(div, "[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 does not implement inclusive descendent
    // 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
          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
            if (
              a === doc ||
              (a.ownerDocument === preferredDoc && contains(preferredDoc, a))
            ) {
              return -1;
            }
            if (
              b === doc ||
              (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) {
            return a === doc
              ? -1
              : b === doc
                ? 1
                : 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
              ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0;
        };

    return doc;
  };

  Sizzle.matches = function(expr, elements) {
    return Sizzle(expr, null, null, elements);
  };

  Sizzle.matchesSelector = function(elem, expr) {
    // Set document vars if needed
    if ((elem.ownerDocument || elem) !== document) {
      setDocument(elem);
    }

    // Make sure that attribute selectors are quoted
    expr = expr.replace(rattributeQuotes, "='$1']");

    if (
      support.matchesSelector &&
      documentIsHTML &&
      (!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) {}
    }

    return Sizzle(expr, document, null, [elem]).length > 0;
  };

  Sizzle.contains = function(context, elem) {
    // Set document vars if needed
    if ((context.ownerDocument || context) !== document) {
      setDocument(context);
    }
    return contains(context, elem);
  };

  Sizzle.attr = function(elem, name) {
    // Set document vars if needed
    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.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 += '';

          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;
        };
      },

      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,
                outerCache,
                node,
                diff,
                nodeIndex,
                start,
                dir = simple !== forward ? 'nextSibling' : 'previousSibling',
                parent = elem.parentNode,
                name = ofType && elem.nodeName.toLowerCase(),
                useCache = !xml && !ofType;

              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
                  outerCache = parent[expando] || (parent[expando] = {});
                  cache = outerCache[type] || [];
                  nodeIndex = cache[0] === dirruns && cache[1];
                  diff = cache[0] === dirruns && 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) {
                      outerCache[type] = [dirruns, nodeIndex, diff];
                      break;
                    }
                  }

                  // Use previously-cached element index if available
                } else if (
                  useCache &&
                  (cache = (elem[expando] || (elem[expando] = {}))[type]) &&
                  cache[0] === dirruns
                ) {
                  diff = cache[1];

                  // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
                } else {
                  // 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) {
                        (node[expando] || (node[expando] = {}))[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 || elem.innerText || 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: function(elem) {
        return elem.disabled === false;
      },

      disabled: function(elem) {
        return elem.disabled === 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) {
          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;
        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,
      checkNonElements = base && dir === '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);
            }
          }
        }
      : // Check against all ancestor/preceding elements
        function(elem, context, xml) {
          var oldCache,
            outerCache,
            newCache = [dirruns, doneName];

          // We can't set arbitrary data on XML nodes, so they don't benefit from dir 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] = {});
                if (
                  (oldCache = outerCache[dir]) &&
                  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
                  outerCache[dir] = newCache;

                  // A match means we're done; a fail means we have to keep checking
                  if ((newCache[2] = matcher(elem, context, xml))) {
                    return true;
                  }
                }
              }
            }
          }
        };
  }

  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) {
          outermostContext = context !== document && context;
        }

        // Add elements passing elementMatchers directly to results
        // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
        // 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;
            while ((matcher = elementMatchers[j++])) {
              if (matcher(elem, context, 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);
            }
          }
        }

        // Apply set filters to unmatched elements
        matchedCount += i;
        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 no seed and only one group
    if (match.length === 1) {
      // Take a shortcut and set the context if the root selector is an ID
      tokens = match[0] = match[0].slice(0);
      if (
        tokens.length > 2 &&
        (token = tokens[0]).type === 'ID' &&
        support.getById &&
        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,
      (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(div1) {
    // Should return 1, but returns 4 (following)
    return div1.compareDocumentPosition(document.createElement('div')) & 1;
  });

  // Support: IE<8
  // Prevent attribute/property "interpolation"
  // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
  if (
    !assert(function(div) {
      div.innerHTML = "<a href='#'></a>";
      return div.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(div) {
      div.innerHTML = '<input/>';
      div.firstChild.setAttribute('value', '');
      return div.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(div) {
      return div.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;
      }
    });
  }

  // EXPOSE
  if (typeof define === 'function' && define.amd) {
    define(function() {
      return Sizzle;
    });
    // Sizzle requires that there be a global window in Common-JS like environments
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = Sizzle;
  } else {
    window.Sizzle = Sizzle;
  }
  // EXPOSE
})(window);
