PageSourceSearch

https://neochair.co.kr/_wp/js/nwmatcher.js

js neochair.co.kr collected 2026-10-08 20:34:29 UTC 62,238 bytes, 1,780 lines download raw bytes

1/*
2 * Copyright (C) 2007-2016 Diego Perini
3 * All rights reserved.
4 *
5 * nwmatcher.js - A fast CSS selector engine and matcher
6 *
7 * Author: Diego Perini <diego.perini at gmail com>
8 * Version: 1.3.9beta
9 * Created: 20070722
10 * Release: 20161013
11 *
12 * License:
13 *  http://javascript.nwbox.com/NWMatcher/MIT-LICENSE
14 * Download:
15 *  http://javascript.nwbox.com/NWMatcher/nwmatcher.js
16 */
17
18(function(global, factory) {
19
20  if (typeof module == 'object' && typeof exports == 'object') {
21    module.exports = factory;
22  } else if (typeof define === 'function' && define["amd"]) {
23    define(factory);
24  } else {
25    global.NW || (global.NW = { });
26    global.NW.Dom = factory(global);
27  }
28
29})(this, function(global) {
30
31  var version = 'nwmatcher-1.3.9beta',
32
33  // processing context & root element
34  doc = global.document,
35  root = doc.documentElement,
36
37  // save utility methods references
38  slice = [ ].slice,
39
40  // persist previous parsed data
41  isSingleMatch,
42  isSingleSelect,
43
44  lastSlice,
45  lastContext,
46  lastPosition,
47
48  lastMatcher,
49  lastSelector,
50
51  lastPartsMatch,
52  lastPartsSelect,
53
54  // accepted prefix identifiers
55  // (id, class & pseudo-class)
56  prefixes = '[#.:]?',
57
58  // accepted attribute operators
59  operators = '([~*^$|!]?={1})',
60
61  // accepted whitespace characters
62  whitespace = '[\\x20\\t\\n\\r\\f]',
63
64  // 4 combinators F E, F>E, F+E, F~E
65  combinators = '\\x20|[>+~](?=[^>+~])',
66
67  // an+b format params for pseudo-classes
68  pseudoparms = '(?:[-+]?\\d*n)?[-+]?\\d*',
69
70  // skip [ ], ( ), { } brackets groups
71  skip_groups = '\\[.*\\]|\\(.*\\)|\\{.*\\}',
72
73  // any escaped char
74  any_esc_chr = '\\\\.',
75  // alpha chars & low dash
76  alphalodash = '[_a-zA-Z]',
77  // non-ascii chars (utf-8)
78  non_asc_chr = '[^\\x00-\\x9f]',
79  // escape sequences in strings
80  escaped_chr = '\\\\[^\\n\\r\\f0-9a-fA-F]',
81  // Unicode chars including trailing whitespace
82  unicode_chr = '\\\\[0-9a-fA-F]{1,6}(?:\\r\\n|' + whitespace + ')?',
83
84  // CSS quoted string values
85  quotedvalue = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"' + "|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'",
86
87  // regular expression used to skip single/nested brackets groups (round, square, curly)
88  // used to split comma groups excluding commas inside quotes '' "" or brackets () [] {}
89  reSplitGroup = /([^,\\()[\]]+|\[[^[\]]*\]|\[.*\]|\([^()]+\)|\(.*\)|\{[^{}]+\}|\{.*\}|\\.)+/g,
90
91  // regular expression to trim extra leading/trailing whitespace in selector strings
92  // whitespace is any combination of these 5 character [\x20\t\n\r\f]
93  // http://www.w3.org/TR/css3-selectors/#selector-syntax
94  reTrimSpaces = RegExp('[\\n\\r\\f]|^' + whitespace + '+|' + whitespace + '+$', 'g'),
95
96  // regular expression used in convertEscapes and unescapeIdentifier
97  reEscapedChars = /\\([0-9a-fA-F]{1,6}[\x20\t\n\r\f]?|.)|([\x22\x27])/g,
98
99  // for in excess whitespace removal
100  reWhiteSpace = /[\x20\t\n\r\f]+/g,
101
102  standardValidator, extendedValidator, reValidator,
103
104  attrcheck, attributes, attrmatcher, pseudoclass,
105
106  reOptimizeSelector, reSimpleNot, reSplitToken,
107
108  Optimize, reClass, reSimpleSelector,
109
110  // http://www.w3.org/TR/css3-syntax/#characters
111  // unicode/ISO 10646 characters \xA0 and higher
112  // NOTE: Safari 2.0.x crashes with escaped (\\)
113  // Unicode ranges in regular expressions so we
114  // use a negated character range class instead
115  // now assigned at runtime from config options
116  identifier,
117
118  // placeholder for extensions
119  extensions = '.+',
120
121  // precompiled Regular Expressions
122  Patterns = {
123    // structural pseudo-classes and child selectors
124    spseudos: /^\:(root|empty|(?:first|last|only)(?:-child|-of-type)|nth(?:-last)?(?:-child|-of-type)\(\s*(even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\))?(.*)/i,
125    // uistates + dynamic + negation pseudo-classes
126    dpseudos: /^\:(link|visited|target|active|focus|hover|checked|disabled|enabled|selected|lang\(([-\w]{2,})\)|not\(\s*(:nth(?:-last)?(?:-child|-of-type)\(\s*(?:even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\)|[^()]*)\s*\))?(.*)/i,
127    // E > F
128    children: RegExp('^' + whitespace + '*\\>' + whitespace + '*(.*)'),
129    // E + F
130    adjacent: RegExp('^' + whitespace + '*\\+' + whitespace + '*(.*)'),
131    // E ~ F
132    relative: RegExp('^' + whitespace + '*\\~' + whitespace + '*(.*)'),
133    // E F
134    ancestor: RegExp('^' + whitespace + '+(.*)'),
135    // all
136    universal: RegExp('^\\*(.*)')
137  },
138
139  Tokens = {
140    prefixes: prefixes,
141    identifier: identifier,
142    attributes: attributes
143  },
144
145  /*----------------------------- FEATURE TESTING ----------------------------*/
146
147  // detect native methods
148  isNative = (function() {
149    var re = / \w+\(/,
150    isnative = String(({ }).toString).replace(re, ' (');
151    return function(method) {
152      return method && typeof method != 'string' &&
153        isnative == String(method).replace(re, ' (');
154    };
155  })(),
156
157  // NATIVE_XXXXX true if method exist and is callable
158  // detect if DOM methods are native in browsers
159  NATIVE_FOCUS = isNative(doc.hasFocus),
160  NATIVE_QSAPI = isNative(doc.querySelector),
161  NATIVE_GEBID = isNative(doc.getElementById),
162  NATIVE_GEBTN = isNative(root.getElementsByTagName),
163  NATIVE_GEBCN = isNative(root.getElementsByClassName),
164
165  // detect native getAttribute/hasAttribute methods,
166  // frameworks extend these to elements, but it seems
167  // this does not work for XML namespaced attributes,
168  // used to check both getAttribute/hasAttribute in IE
169  NATIVE_GET_ATTRIBUTE = isNative(root.getAttribute),
170  NATIVE_HAS_ATTRIBUTE = isNative(root.hasAttribute),
171
172  // check if slice() can convert nodelist to array
173  // see http://yura.thinkweb2.com/cft/
174  NATIVE_SLICE_PROTO =
175    (function() {
176      var isBuggy = false;
177      try {
178        isBuggy = !!slice.call(doc.childNodes, 0)[0];
179      } catch(e) { }
180      return isBuggy;
181    })(),
182
183  // supports the new traversal API
184  NATIVE_TRAVERSAL_API =
185    'nextElementSibling' in root && 'previousElementSibling' in root,
186
187  // BUGGY_XXXXX true if method is feature tested and has known bugs
188  // detect buggy gEBID
189  BUGGY_GEBID = NATIVE_GEBID ?
190    (function() {
191      var isBuggy = true, x = 'x' + String(+new Date),
192        a = doc.createElementNS ? 'a' : '<a name="' + x + '">';
193      (a = doc.createElement(a)).name = x;
194      root.insertBefore(a, root.firstChild);
195      isBuggy = !!doc.getElementById(x);
196      root.removeChild(a);
197      return isBuggy;
198    })() :
199    true,
200
201  // detect IE gEBTN comment nodes bug
202  BUGGY_GEBTN = NATIVE_GEBTN ?
203    (function() {
204      var div = doc.createElement('div');
205      div.appendChild(doc.createComment(''));
206      return !!div.getElementsByTagName('*')[0];
207    })() :
208    true,
209
210  // detect Opera gEBCN second class and/or UTF8 bugs as well as Safari 3.2
211  // caching class name results and not detecting when changed,
212  // tests are based on the jQuery selector test suite
213  BUGGY_GEBCN = NATIVE_GEBCN ?
214    (function() {
215      var isBuggy, div = doc.createElement('div'), test = '\u53f0\u5317';
216
217      // Opera tests
218      div.appendChild(doc.createElement('span')).
219        setAttribute('class', test + 'abc ' + test);
220      div.appendChild(doc.createElement('span')).
221        setAttribute('class', 'x');
222
223      isBuggy = !div.getElementsByClassName(test)[0];
224
225      // Safari test
226      div.lastChild.className = test;
227      return isBuggy || div.getElementsByClassName(test).length != 2;
228    })() :
229    true,
230
231  // detect IE bug with dynamic attributes
232  BUGGY_GET_ATTRIBUTE = NATIVE_GET_ATTRIBUTE ?
233    (function() {
234      var input = doc.createElement('input');
235      input.setAttribute('value', 5);
236      return input.defaultValue != 5;
237    })() :
238    true,
239
240  // detect IE bug with non-standard boolean attributes
241  BUGGY_HAS_ATTRIBUTE = NATIVE_HAS_ATTRIBUTE ?
242    (function() {
243      var option = doc.createElement('option');
244      option.setAttribute('selected', 'selected');
245      return !option.hasAttribute('selected');
246    })() :
247    true,
248
249  // detect Safari bug with selected option elements
250  BUGGY_SELECTED =
251    (function() {
252      var select = doc.createElement('select');
253      select.appendChild(doc.createElement('option'));
254      return !select.firstChild.selected;
255    })(),
256
257  // initialized with the loading context
258  // and reset for each different context
259  BUGGY_QUIRKS_GEBCN,
260  BUGGY_QUIRKS_QSAPI,
261
262  QUIRKS_MODE,
263  XML_DOCUMENT,
264
265  // detect Opera browser
266  OPERA = typeof global.opera != 'undefined' &&
267    (/opera/i).test(({ }).toString.call(global.opera)),
268
269  // skip simple selector optimizations for Opera >= 11
270  OPERA_QSAPI = OPERA && parseFloat(global.opera.version()) >= 11,
271
272  // check Selector API implementations
273  RE_BUGGY_QSAPI = NATIVE_QSAPI ?
274    (function() {
275      var pattern = [ ], context, element,
276
277      expect = function(selector, element, n) {
278        var result = false;
279        context.appendChild(element);
280        try { result = context.querySelectorAll(selector).length == n; } catch(e) { }
281        while (context.firstChild) { context.removeChild(context.firstChild); }
282        return result;
283      };
284
285      // certain bugs can only be detected in standard documents
286      // to avoid writing a live loading document create a fake one
287      if (doc.implementation && doc.implementation.createDocument) {
288        // use a shadow document body as context
289        context = doc.implementation.createDocument('', '', null).
290          appendChild(doc.createElement('html')).
291          appendChild(doc.createElement('head')).parentNode.
292          appendChild(doc.createElement('body'));
293      } else {
294        // use an unattached div node as context
295        context = doc.createElement('div');
296      }
297
298      // fix for Safari 8.x and other engines that
299      // fail querying filtered sibling combinators
300      element = doc.createElement('div');
301      element.innerHTML = '<p id="a"></p><br>';
302      expect('p#a+*', element, 0) &&
303        pattern.push('\\w+#\\w+.*[+~]');
304
305      // ^= $= *= operators bugs with empty values (Opera 10 / IE8)
306      element = doc.createElement('p');
307      element.setAttribute('class', '');
308      expect('[class^=""]', element, 1) &&
309        pattern.push('[*^$]=[\\x20\\t\\n\\r\\f]*(?:""|' + "'')");
310
311      // :checked bug with option elements (Firefox 3.6.x)
312      // it wrongly includes 'selected' options elements
313      // HTML5 rules says selected options also match
314      element = doc.createElement('option');
315      element.setAttribute('selected', 'selected');
316      expect(':checked', element, 0) &&
317        pattern.push(':checked');
318
319      // :enabled :disabled bugs with hidden fields (Firefox 3.5)
320      // http://www.w3.org/TR/html5/links.html#selector-enabled
321      // http://www.w3.org/TR/css3-selectors/#enableddisabled
322      // not supported by IE8 Query Selector
323      element = doc.createElement('input');
324      element.setAttribute('type', 'hidden');
325      expect(':enabled', element, 0) &&
326        pattern.push(':enabled', ':disabled');
327
328      // :link bugs with hyperlinks matching (Firefox/Safari)
329      element = doc.createElement('link');
330      element.setAttribute('href', 'x');
331      expect(':link', element, 1) ||
332        pattern.push(':link');
333
334      // avoid attribute selectors for IE QSA
335      if (BUGGY_HAS_ATTRIBUTE) {
336        // IE fails in reading:
337        // - original values for input/textarea
338        // - original boolean values for controls
339        pattern.push('\\[[\\x20\\t\\n\\r\\f]*(?:checked|disabled|ismap|multiple|readonly|selected|value)');
340      }
341
342      return pattern.length ?
343        RegExp(pattern.join('|')) :
344        { 'test': function() { return false; } };
345
346    })() :
347    true,
348
349  /*----------------------------- LOOKUP OBJECTS -----------------------------*/
350
351  IE_LT_9 = typeof doc.addEventListener != 'function',
352
353  LINK_NODES = { 'a': 1, 'A': 1, 'area': 1, 'AREA': 1, 'link': 1, 'LINK': 1 },
354
355  // boolean attributes should return attribute name instead of true/false
356  ATTR_BOOLEAN = {
357    'checked': 1, 'disabled': 1, 'ismap': 1,
358    'multiple': 1, 'readonly': 1, 'selected': 1
359  },
360
361  // dynamic attributes that needs to be checked against original HTML value
362  ATTR_DEFAULT = {
363    'value': 'defaultValue',
364    'checked': 'defaultChecked',
365    'selected': 'defaultSelected'
366  },
367
368  // attributes referencing URI data values need special treatment in IE
369  ATTR_URIDATA = {
370    'action': 2, 'cite': 2, 'codebase': 2, 'data': 2, 'href': 2,
371    'longdesc': 2, 'lowsrc': 2, 'src': 2, 'usemap': 2
372  },
373
374  // HTML 5 draft specifications
375  // http://www.whatwg.org/specs/web-apps/current-work/#selectors
376  HTML_TABLE = {
377    // class attribute must be treated case-insensitive in HTML quirks mode
378    // initialized by default to Standard Mode (case-sensitive),
379    // set dynamically by the attribute resolver
380    'class': 0,
381    'accept': 1, 'accept-charset': 1, 'align': 1, 'alink': 1, 'axis': 1,
382    'bgcolor': 1, 'charset': 1, 'checked': 1, 'clear': 1, 'codetype': 1, 'color': 1,
383    'compact': 1, 'declare': 1, 'defer': 1, 'dir': 1, 'direction': 1, 'disabled': 1,
384    'enctype': 1, 'face': 1, 'frame': 1, 'hreflang': 1, 'http-equiv': 1, 'lang': 1,
385    'language': 1, 'link': 1, 'media': 1, 'method': 1, 'multiple': 1, 'nohref': 1,
386    'noresize': 1, 'noshade': 1, 'nowrap': 1, 'readonly': 1, 'rel': 1, 'rev': 1,
387    'rules': 1, 'scope': 1, 'scrolling': 1, 'selected': 1, 'shape': 1, 'target': 1,
388    'text': 1, 'type': 1, 'valign': 1, 'valuetype': 1, 'vlink': 1
389  },
390
391  // the following attributes must be treated case-insensitive in XHTML mode
392  // Niels Leenheer http://rakaz.nl/item/css_selector_bugs_case_sensitivity
393  XHTML_TABLE = {
394    'accept': 1, 'accept-charset': 1, 'alink': 1, 'axis': 1,
395    'bgcolor': 1, 'charset': 1, 'codetype': 1, 'color': 1,
396    'enctype': 1, 'face': 1, 'hreflang': 1, 'http-equiv': 1,
397    'lang': 1, 'language': 1, 'link': 1, 'media': 1, 'rel': 1,
398    'rev': 1, 'target': 1, 'text': 1, 'type': 1, 'vlink': 1
399  },
400
401  /*-------------------------- REGULAR EXPRESSIONS ---------------------------*/
402
403  // placeholder to add functionalities
404  Selectors = {
405    // as a simple example this will check
406    // for chars not in standard ascii table
407    //
408    // 'mySpecialSelector': {
409    //  'Expression': /\u0080-\uffff/,
410    //  'Callback': mySelectorCallback
411    // }
412    //
413    // 'mySelectorCallback' will be invoked
414    // only after passing all other standard
415    // checks and only if none of them worked
416  },
417
418  // attribute operators
419  Operators = {
420     '=': "n=='%m'",
421    '^=': "n.indexOf('%m')==0",
422    '*=': "n.indexOf('%m')>-1",
423    '|=': "(n+'-').indexOf('%m-')==0",
424    '~=': "(' '+n+' ').indexOf(' %m ')>-1",
425    '$=': "n.substr(n.length-'%m'.length)=='%m'"
426  },
427
428  /*------------------------------ UTIL METHODS ------------------------------*/
429
430  // concat elements to data
431  concatList =
432    function(data, elements) {
433      var i = -1, element;
434      if (!data.length && Array.slice)
435        return Array.slice(elements);
436      while ((element = elements[++i]))
437        data[data.length] = element;
438      return data;
439    },
440
441  // concat elements to data and callback
442  concatCall =
443    function(data, elements, callback) {
444      var i = -1, element;
445      while ((element = elements[++i])) {
446        if (false === callback(data[data.length] = element)) { break; }
447      }
448      return data;
449    },
450
451  // change context specific variables
452  switchContext =
453    function(from, force) {
454      var div, oldDoc = doc;
455      // save passed context
456      lastContext = from;
457      // set new context document
458      doc = from.ownerDocument || from;
459      if (force || oldDoc !== doc) {
460        // set document root
461        root = doc.documentElement;
462        // set host environment flags
463        XML_DOCUMENT = doc.createElement('DiV').nodeName == 'DiV';
464
465        // In quirks mode css class names are case insensitive.
466        // In standards mode they are case sensitive. See docs:
467        // https://developer.mozilla.org/en/Mozilla_Quirks_Mode_Behavior
468        // http://www.whatwg.org/specs/web-apps/current-work/#selectors
469        QUIRKS_MODE = !XML_DOCUMENT &&
470          typeof doc.compatMode == 'string' ?
471          doc.compatMode.indexOf('CSS') < 0 :
472          (function() {
473            var style = doc.createElement('div').style;
474            return style && (style.width = 1) && style.width == '1px';
475          })();
476
477        div = doc.createElement('div');
478        div.appendChild(doc.createElement('p')).setAttribute('class', 'xXx');
479        div.appendChild(doc.createElement('p')).setAttribute('class', 'xxx');
480
481        // GEBCN buggy in quirks mode, match count is:
482        // Firefox 3.0+ [xxx = 1, xXx = 1]
483        // Opera 10.63+ [xxx = 0, xXx = 2]
484        BUGGY_QUIRKS_GEBCN =
485          !XML_DOCUMENT && NATIVE_GEBCN && QUIRKS_MODE &&
486          (div.getElementsByClassName('xxx').length != 2 ||
487          div.getElementsByClassName('xXx').length != 2);
488
489        // QSAPI buggy in quirks mode, match count is:
490        // At least Chrome 4+, Firefox 3.5+, Opera 10.x+, Safari 4+ [xxx = 1, xXx = 2]
491        // Safari 3.2 QSA doesn't work with mixedcase in quirksmode [xxx = 1, xXx = 0]
492        // https://bugs.webkit.org/show_bug.cgi?id=19047
493        // must test the attribute selector '[class~=xxx]'
494        // before '.xXx' or the bug may not present itself
495        BUGGY_QUIRKS_QSAPI =
496          !XML_DOCUMENT && NATIVE_QSAPI && QUIRKS_MODE &&
497          (div.querySelectorAll('[class~=xxx]').length != 2 ||
498          div.querySelectorAll('.xXx').length != 2);
499
500        Config.CACHING && Dom.setCache(true, doc);
501      }
502    },
503
504  // convert single codepoint to UTF-16 encoding
505  codePointToUTF16 =
506    function(codePoint) {
507      // out of range, use replacement character
508      if (codePoint < 1 || codePoint > 0x10ffff ||
509        (codePoint > 0xd7ff && codePoint < 0xe000)) {
510        return '\\ufffd';
511      }
512      // javascript strings are UTF-16 encoded
513      if (codePoint < 0x10000) {
514        var lowHex = '000' + codePoint.toString(16);
515        return '\\u' + lowHex.substr(lowHex.length - 4);
516      }
517      // supplementary high + low surrogates
518      return '\\u' + (((codePoint - 0x10000) >> 0x0a) + 0xd800).toString(16) +
519             '\\u' + (((codePoint - 0x10000) % 0x400) + 0xdc00).toString(16);
520    },
521
522  // convert single codepoint to string
523  stringFromCodePoint =
524    function(codePoint) {
525      // out of range, use replacement character
526      if (codePoint < 1 || codePoint > 0x10ffff ||
527        (codePoint > 0xd7ff && codePoint < 0xe000)) {
528        return '\ufffd';
529      }
530      if (codePoint < 0x10000) {
531        return String.fromCharCode(codePoint);
532      }
533      return String.fromCodePoint ?
534        String.fromCodePoint(codePoint) :
535        String.fromCharCode(
536          ((codePoint - 0x10000) >> 0x0a) + 0xd800,
537          ((codePoint - 0x10000) % 0x400) + 0xdc00);
538    },
539
540  // convert escape sequence in a CSS string or identifier
541  // to javascript string with javascript escape sequences
542  convertEscapes =
543    function(str) {
544      return str.replace(reEscapedChars,
545          function(substring, p1, p2) {
546            // unescaped " or '
547            return p2 ? '\\' + p2 :
548              // javascript strings are UTF-16 encoded
549              /^[0-9a-fA-F]/.test(p1) ? codePointToUTF16(parseInt(p1, 16)) :
550              // \' \"
551              /^[\\\x22\x27]/.test(p1) ? substring :
552              // \g \h \. \# etc
553              p1;
554          }
555        );
556    },
557
558  // convert escape sequence in a CSS string or identifier
559  // to javascript string with characters representations
560  unescapeIdentifier =
561    function(str) {
562      return str.replace(reEscapedChars,
563          function(substring, p1, p2) {
564            // unescaped " or '
565            return p2 ? p2 :
566              // javascript strings are UTF-16 encoded
567              /^[0-9a-fA-F]/.test(p1) ? stringFromCodePoint(parseInt(p1, 16)) :
568              // \' \"
569              /^[\\\x22\x27]/.test(p1) ? substring :
570              // \g \h \. \# etc
571              p1;
572          }
573        );
574    },
575
576  /*------------------------------ DOM METHODS -------------------------------*/
577
578  // element by id (raw)
579  // @return reference or null
580  byIdRaw =
581    function(id, elements) {
582      var i = -1, element;
583      while ((element = elements[++i])) {
584        if (element.getAttribute('id') == id) {
585          break;
586        }
587      }
588      return element || null;
589    },
590
591  // element by id
592  // @return reference or null
593  _byId = !BUGGY_GEBID ?
594    function(id, from) {
595      id = (/\\/).test(id) ? unescapeIdentifier(id) : id;
596      return from.getElementById && from.getElementById(id) ||
597        byIdRaw(id, from.getElementsByTagName('*'));
598    } :
599    function(id, from) {
600      var element = null;
601      id = (/\\/).test(id) ? unescapeIdentifier(id) : id;
602      if (XML_DOCUMENT || from.nodeType != 9) {
603        return byIdRaw(id, from.getElementsByTagName('*'));
604      }
605      if ((element = from.getElementById(id)) &&
606        element.name == id && from.getElementsByName) {
607        return byIdRaw(id, from.getElementsByName(id));
608      }
609      return element;
610    },
611
612  // publicly exposed byId
613  // @return reference or null
614  byId =
615    function(id, from) {
616      from || (from = doc);
617      if (lastContext !== from) { switchContext(from); }
618      return _byId(id, from);
619    },
620
621  // elements by tag (raw)
622  // @return array
623  byTagRaw =
624    function(tag, from) {
625      var any = tag == '*', element = from, elements = [ ], next = element.firstChild;
626      any || (tag = tag.toUpperCase());
627      while ((element = next)) {
628        if (element.tagName > '@' && (any || element.tagName.toUpperCase() == tag)) {
629          elements[elements.length] = element;
630        }
631        if ((next = element.firstChild || element.nextSibling)) continue;
632        while (!next && (element = element.parentNode) && element !== from) {
633          next = element.nextSibling;
634        }
635      }
636      return elements;
637    },
638
639  // elements by tag
640  // @return array
641  _byTag = !BUGGY_GEBTN && NATIVE_SLICE_PROTO ?
642    function(tag, from) {
643      return XML_DOCUMENT || from.nodeType == 11 ? byTagRaw(tag, from) :
644        slice.call(from.getElementsByTagName(tag), 0);
645    } :
646    function(tag, from) {
647      var i = -1, j = i, data = [ ], element,
648        elements = XML_DOCUMENT || from.nodeType == 11 ?
649        byTagRaw(tag, from) : from.getElementsByTagName(tag);
650      if (tag == '*') {
651        while ((element = elements[++i])) {
652          if (element.nodeName > '@') {
653            data[++j] = element;
654          }
655        }
656      } else {
657        while ((element = elements[++i])) {
658          data[i] = element;
659        }
660      }
661      return data;
662    },
663
664  // publicly exposed byTag
665  // @return array
666  byTag =
667    function(tag, from) {
668      from || (from = doc);
669      if (lastContext !== from) { switchContext(from); }
670      return _byTag(tag, from);
671    },
672
673  // publicly exposed byName
674  // @return array
675  byName =
676    function(name, from) {
677      return select('[name="' + name.replace(/\\([^\\]{1})/g, '$1') + '"]', from);
678    },
679
680  // elements by class (raw)
681  // @return array
682  byClassRaw =
683    function(name, from) {
684      var i = -1, j = i, data = [ ], element, elements = _byTag('*', from), n;
685      name = ' ' + (QUIRKS_MODE ? name.toLowerCase() : name) + ' ';
686      while ((element = elements[++i])) {
687        n = XML_DOCUMENT ? element.getAttribute('class') : element.className;
688        if (n && n.length && (' ' + (QUIRKS_MODE ? n.toLowerCase() : n).
689          replace(reWhiteSpace, ' ') + ' ').indexOf(name) > -1) {
690          data[++j] = element;
691        }
692      }
693      return data;
694    },
695
696  // elements by class
697  // @return array
698  _byClass =
699    function(name, from) {
700      name = QUIRKS_MODE ? name.toLowerCase() : name;
701      name = (/\\/).test(name) ? unescapeIdentifier(name) : name;
702      return (BUGGY_GEBCN || BUGGY_QUIRKS_GEBCN || XML_DOCUMENT || !from.getElementsByClassName) ?
703        byClassRaw(name, from) : slice.call(from.getElementsByClassName(name));
704    },
705
706  // publicly exposed byClass
707  // @return array
708  byClass =
709    function(name, from) {
710      from || (from = doc);
711      if (lastContext !== from) { switchContext(from); }
712      return _byClass(name, from);
713    },
714
715  // check element is descendant of container
716  // @return boolean
717  contains = 'compareDocumentPosition' in root ?
718    function(container, element) {
719      return (container.compareDocumentPosition(element) & 16) == 16;
720    } : 'contains' in root ?
721    function(container, element) {
722      return container !== element && container.contains(element);
723    } :
724    function(container, element) {
725      while ((element = element.parentNode)) {
726        if (element === container) return true;
727      }
728      return false;
729    },
730
731  // attribute value
732  // @return string
733  getAttribute = !BUGGY_GET_ATTRIBUTE && !IE_LT_9 ?
734    function(node, attribute) {
735      return node.getAttribute(attribute);
736    } :
737    function(node, attribute) {
738      attribute = attribute.toLowerCase();
739      if (typeof node[attribute] == 'object') {
740        return node.attributes[attribute] &&
741          node.attributes[attribute].value;
742      }
743      return (
744        // 'type' can only be read by using native getAttribute
745        attribute == 'type' ? node.getAttribute(attribute) :
746        // specific URI data attributes (parameter 2 to fix IE bug)
747        ATTR_URIDATA[attribute] ? node.getAttribute(attribute, 2) :
748        // boolean attributes should return name instead of true/false
749        ATTR_BOOLEAN[attribute] ? node.getAttribute(attribute) ? attribute : 'false' :
750          (node = node.getAttributeNode(attribute)) && node.value);
751    },
752
753  // attribute presence
754  // @return boolean
755  hasAttribute = !BUGGY_HAS_ATTRIBUTE && !IE_LT_9 ?
756    function(node, attribute) {
757      return XML_DOCUMENT ?
758        !!node.getAttribute(attribute) :
759        node.hasAttribute(attribute);
760    } :
761    function(node, attribute) {
762      // read the node attribute object
763      var obj = node.getAttributeNode(attribute = attribute.toLowerCase());
764      return ATTR_DEFAULT[attribute] && attribute != 'value' ?
765        node[ATTR_DEFAULT[attribute]] : obj && obj.specified;
766    },
767
768  // check node emptyness
769  // @return boolean
770  isEmpty =
771    function(node) {
772      node = node.firstChild;
773      while (node) {
774        if (node.nodeType == 3 || node.nodeName > '@') return false;
775        node = node.nextSibling;
776      }
777      return true;
778    },
779
780  // check if element matches the :link pseudo
781  // @return boolean
782  isLink =
783    function(element) {
784      return hasAttribute(element,'href') && LINK_NODES[element.nodeName];
785    },
786
787  // child position by nodeType
788  // @return number
789  nthElement =
790    function(element, last) {
791      var count = 1, succ = last ? 'nextSibling' : 'previousSibling';
792      while ((element = element[succ])) {
793        if (element.nodeName > '@') ++count;
794      }
795      return count;
796    },
797
798  // child position by nodeName
799  // @return number
800  nthOfType =
801    function(element, last) {
802      var count = 1, succ = last ? 'nextSibling' : 'previousSibling', t
802ype = element.nodeName;
803      while ((element = element[succ])) {
804        if (element.nodeName == type) ++count;
805      }
806      return count;
807    },
808
809  /*------------------------------- DEBUGGING --------------------------------*/
810
811  // get/set (string/object) working modes
812  configure =
813    function(option) {
814      if (typeof option == 'string') { return !!Config[option]; }
815      if (typeof option != 'object') { return Config; }
816      for (var i in option) {
817        Config[i] = !!option[i];
818        if (i == 'SIMPLENOT') {
819          matchContexts = { };
820          matchResolvers = { };
821          selectContexts = { };
822          selectResolvers = { };
823          if (!Config[i]) { Config['USE_QSAPI'] = false; }
824        } else if (i == 'USE_QSAPI') {
825          Config[i] = !!option[i] && NATIVE_QSAPI;
826        }
827      }
828      setIdentifierSyntax();
829      reValidator = RegExp(Config.SIMPLENOT ?
830        standardValidator : extendedValidator);
831      return true;
832    },
833
834  // control user notifications
835  emit =
836    function(message) {
837      if (Config.VERBOSITY) { throw Error(message); }
838      if (console && console.log) {
839        console.log(message);
840      }
841    },
842
843  Config = {
844
845    // used to enable/disable caching of result sets
846    CACHING: false,
847
848    // used to enable/disable CSS escaped identifiers
849    ESCAPECHR: true,
850
851    // add non-ascii (utf-8) to the identifier syntax RE
852    NON_ASCII: true,
853
854    // switch between CSS2 and CSS3 identifier syntax RE
855    SELECTOR3: true,
856
857    // add Unicode (utf-16) to the identifier syntax RE
858    UNICODE16: true,
859
860    // by default do not add missing left/right context
861    // to selector string shortcuts like "+div" or "ul>"
862    // callable Dom.shortcuts method has to be available
863    SHORTCUTS: false,
864
865    // by default disable complex selectors nested in
866    // ':not()' pseudo-classes, as for specifications
867    SIMPLENOT: true,
868
869    // strict QSA match all non-unique IDs (false)
870    // speed & libs compat match unique ID (true)
871    UNIQUE_ID: true,
872
873    // HTML5 handling for the ":checked" pseudo-class
874    USE_HTML5: true,
875
876    // controls enabling the Query Selector API branch
877    USE_QSAPI: NATIVE_QSAPI,
878
879    // controls the engine error/warning notifications
880    VERBOSITY: true
881
882  },
883
884  /*---------------------------- COMPILER METHODS ----------------------------*/
885
886  // init REs and context
887  initialize =
888    function(doc) {
889      setIdentifierSyntax();
890      switchContext(doc, true);
891    },
892
893  // set/reset default identifier syntax
894  // based on user configuration options
895  // rebuild the validator and other REs
896  setIdentifierSyntax =
897    function() {
898
899      var syntax = '', start = Config['SELECTOR3'] ? '-{2}|' : '';
900
901      Config['NON_ASCII'] && (syntax += '|' + non_asc_chr);
902      Config['UNICODE16'] && (syntax += '|' + unicode_chr);
903      Config['ESCAPECHR'] && (syntax += '|' + escaped_chr);
904
905      syntax += (Config['UNICODE16'] || Config['ESCAPECHR']) ? '' : '|' + any_esc_chr;
906
907      identifier = '-?(?:' + start + alphalodash + syntax + ')(?:-|[0-9]|' + alphalodash + syntax + ')*';
908
909      // build attribute string
910      attrcheck = '(' + quotedvalue + '|' + identifier + ')';
911      attributes = whitespace + '*(' + identifier + ':?' + identifier + ')' +
912        whitespace + '*(?:' + operators + whitespace + '*' + attrcheck + ')?' + whitespace + '*';
913      attrmatcher = attributes.replace(attrcheck, '([\\x22\\x27]*)((?:\\\\?.)*?)\\3');
914
915      // build pseudoclass string
916      pseudoclass = '((?:' +
917        // an+b parameters or quoted string
918        pseudoparms + '|' + quotedvalue + '|' +
919        // id, class, pseudo-class selector
920        prefixes + identifier + '|' +
921        // nested HTML attribute selector
922        '\\[' + attributes + '\\]|' +
923        // nested pseudo-class selector
924        '\\(.+\\)|' + whitespace + '*|' +
925        // nested pseudos/separators
926        ',)+)';
927
928      // CSS3: syntax scanner and
929      // one pass validation only
930      // using regular expression
931      standardValidator =
932        // discard start
933        '(?=[\\x20\\t\\n\\r\\f]*[^>+~(){}<>])' +
934        // open match group
935        '(' +
936        //universal selector
937        '\\*' +
938        // id/class/tag/pseudo-class identifier
939        '|(?:' + prefixes + identifier + ')' +
940        // combinator selector
941        '|' + combinators +
942        // HTML attribute selector
943        '|\\[' + attributes + '\\]' +
944        // pseudo-classes parameters
945        '|\\(' + pseudoclass + '\\)' +
946        // dom properties selector (extension)
947        '|\\{' + extensions + '\\}' +
948        // selector group separator (comma)
949        '|(?:,|' + whitespace + '*)' +
950        // close match group
951        ')+';
952
953      // only allow simple selectors nested in ':not()' pseudo-classes
954      reSimpleNot = RegExp('^(' +
955        '(?!:not)' +
956        '(' + prefixes + identifier +
957        '|\\([^()]*\\))+' +
958        '|\\[' + attributes + '\\]' +
959        ')$');
960
961      // split last, right most, selector group token
962      reSplitToken = RegExp('(' +
963        prefixes + identifier + '|' +
964        '\\[' + attributes + '\\]|' +
965        '\\(' + pseudoclass + '\\)|' +
966        '\\\\.|[^\\x20\\t\\n\\r\\f>+~])+', 'g');
967
968      reOptimizeSelector = RegExp(identifier + '|^$');
969
970      reSimpleSelector = RegExp(
971        BUGGY_GEBTN && BUGGY_GEBCN || OPERA ?
972          '^#?' + identifier + '$' : BUGGY_GEBTN ?
973          '^[.#]?' + identifier + '$' : BUGGY_GEBCN ?
974          '^(?:\\*|#' + identifier + ')$' :
975          '^(?:\\*|[.#]?' + identifier + ')$');
976
977      // matches class selectors
978      reClass = RegExp('(?:\\[[\\x20\\t\\n\\r\\f]*class\\b|\\.' + identifier + ')');
979
980      Optimize = {
981        ID: RegExp('^\\*?#(' + identifier + ')|' + skip_groups),
982        TAG: RegExp('^(' + identifier + ')|' + skip_groups),
983        CLASS: RegExp('^\\.(' + identifier + '$)|' + skip_groups)
984      };
985
986      Patterns.id = RegExp('^#(' + identifier + ')(.*)');
987      Patterns.tagName = RegExp('^(' + identifier + ')(.*)');
988      Patterns.className = RegExp('^\\.(' + identifier + ')(.*)');
989      Patterns.attribute = RegExp('^\\[' + attrmatcher + '\\](.*)');
990
991      Tokens.identifier = identifier;
992      Tokens.attributes = attributes;
993
994      // validator for complex selectors in ':not()' pseudo-classes
995      extendedValidator = standardValidator.replace(pseudoclass, '.*');
996
997      // validator for standard selectors as default
998      reValidator = RegExp(standardValidator);
999    },
1000
1001  // code string reused to build compiled functions
1002  ACCEPT_NODE = 'r[r.length]=c[k];if(f&&false===f(c[k]))break main;else continue main;',
1003
1004  // compile a comma separated group of selector
1005  // @mode boolean true for select, false for match
1006  // return a compiled function
1007  compile =
1008    function(selector, source, mode) {
1009
1010      var parts = typeof selector == 'string' ? selector.match(reSplitGroup) : selector;
1011
1012      // ensures that source is a string
1013      typeof source == 'string' || (source = '');
1014
1015      if (parts.length == 1) {
1016        source += compileSelector(parts[0], mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode);
1017      } else {
1018        // for each selector in the group
1019        var i = -1, seen = { }, token;
1020        while ((token = parts[++i])) {
1021          token = token.replace(reTrimSpaces, '');
1022          // avoid repeating the same token
1023          // in comma separated group (p, p)
1024          if (!seen[token] && (seen[token] = true)) {
1025            source += compileSelector(token, mode ? ACCEPT_NODE : 'f&&f(k);return true;', mode);
1026          }
1027        }
1028      }
1029
1030      if (mode) {
1031        // for select method
1032        return Function('c,s,r,d,h,g,f,v',
1033          'var N,n,x=0,k=-1,e;main:while((e=c[++k])){' + source + '}return r;');
1034      } else {
1035        // for match method
1036        return Function('e,s,r,d,h,g,f,v',
1037          'var N,n,x=0,k=e;' + source + 'return false;');
1038      }
1039    },
1040
1041  // allows to cache already visited nodes
1042  FILTER =
1043    'var z=v[@]||(v[@]=[]),l=z.length-1;' +
1044    'while(l>=0&&z[l]!==e)--l;' +
1045    'if(l!==-1){break;}' +
1046    'z[z.length]=e;',
1047
1048  // compile a CSS3 string selector into ad-hoc javascript matching function
1049  // @return string (to be compiled)
1050  compileSelector =
1051    function(selector, source, mode) {
1052
1053      var a, b, n, k = 0, expr, match, result, status, test, type;
1054
1055      while (selector) {
1056
1057        k++;
1058
1059        // *** Universal selector
1060        // * match all (empty block, do not remove)
1061        if ((match = selector.match(Patterns.universal))) {
1062          // do nothing, handled in the compiler where
1063          // BUGGY_GEBTN return comment nodes (ex: IE)
1064          expr = '';
1065        }
1066
1067        // *** ID selector
1068        // #Foo Id case sensitive
1069        else if ((match = selector.match(Patterns.id))) {
1070          // document can contain conflicting elements (id/name)
1071          // prototype selector unit need this method to recover bad HTML forms
1072          match[1] = (/\\/).test(match[1]) ? convertEscapes(match[1]) : match[1];
1073          source = 'if(' + (XML_DOCUMENT ?
1074            's.getAttribute(e,"id")' :
1075            '(e.submit?s.getAttribute(e,"id"):e.id)') +
1076            '=="' + match[1] + '"' +
1077            '){' + source + '}';
1078        }
1079
1080        // *** Type selector
1081        // Foo Tag (case insensitive)
1082        else if ((match = selector.match(Patterns.tagName))) {
1083          // both tagName and nodeName properties may be upper/lower case
1084          // depending on their creation NAMESPACE in createElementNS()
1085          source = 'if(e.nodeName' + (XML_DOCUMENT ?
1086            '=="' + match[1] + '"' : '.toUpperCase()' +
1087            '=="' + match[1].toUpperCase() + '"') +
1088            '){' + source + '}';
1089        }
1090
1091        // *** Class selector
1092        // .Foo Class (case sensitive)
1093        else if ((match = selector.match(Patterns.className))) {
1094          // W3C CSS3 specs: element whose "class" attribute has been assigned a
1095          // list of whitespace-separated values, see section 6.4 Class selectors
1096          // and notes at the bottom; explicitly non-normative in this specification.
1097          match[1] = (/\\/).test(match[1]) ? convertEscapes(match[1]) : match[1];
1098          match[1] = QUIRKS_MODE ? match[1].toLowerCase() : match[1];
1099          source = 'if((n=' + (XML_DOCUMENT ?
1100            's.getAttribute(e,"class")' : 'e.className') +
1101            ')&&n.length&&(" "+' + (QUIRKS_MODE ? 'n.toLowerCase()' : 'n') +
1102            '.replace(/' + whitespace + '+/g," ")+" ").indexOf(" ' + match[1] + ' ")>-1' +
1103            '){' + source + '}';
1104        }
1105
1106        // *** Attribute selector
1107        // [attr] [attr=value] [attr="value"] [attr='value'] and !=, *=, ~=, |=, ^=, $=
1108        // case sensitivity is treated differently depending on the document type (see map)
1109        else if ((match = selector.match(Patterns.attribute))) {
1110
1111          // xml namespaced attribute ?
1112          expr = match[1].split(':');
1113          expr = expr.length == 2 ? expr[1] : expr[0] + '';
1114
1115          if (match[2] && !Operators[match[2]]) {
1116            emit('Unsupported operator in attribute selectors "' + selector + '"');
1117            return '';
1118          }
1119
1120          test = 'false';
1121
1122          // replace Operators parameter if needed
1123          if (match[2] && match[4] && (test = Operators[match[2]])) {
1124            match[4] = (/\\/).test(match[4]) ? convertEscapes(match[4]) : match[4];
1125            // case treatment depends on document
1126            HTML_TABLE['class'] = QUIRKS_MODE ? 1 : 0;
1127            type = (XML_DOCUMENT ? XHTML_TABLE : HTML_TABLE)[expr.toLowerCase()];
1128            test = test.replace(/\%m/g, type ? match[4].toLowerCase() : match[4]);
1129          } else if (match[2] == '!=' || match[2] == '=') {
1130            test = 'n' + match[2] + '=""';
1131          }
1132
1133          source = 'if(n=s.hasAttribute(e,"' + match[1] + '")){' +
1134            (match[2] ? 'n=s.getAttribute(e,"' + match[1] + '")' : '') +
1135            (type && match[2] ? '.toLowerCase();' : ';') +
1136            'if(' + (match[2] ? test : 'n') + '){' + source + '}}';
1137
1138        }
1139
1140        // *** Adjacent sibling combinator
1141        // E + F (F adiacent sibling of E)
1142        else if ((match = selector.match(Patterns.adjacent))) {
1143          source = (mode ? '' : FILTER.replace(/@/g, k)) + source;
1144          source = NATIVE_TRAVERSAL_API ?
1145            'var N' + k + '=e;while(e&&(e=e.previousElementSibling)){' + source + 'break;}e=N' + k + ';' :
1146            'var N' + k + '=e;while(e&&(e=e.previousSibling)){if(e.nodeName>"@"){' + source + 'break;}}e=N' + k + ';';
1147        }
1148
1149        // *** General sibling combinator
1150        // E ~ F (F relative sibling of E)
1151        else if ((match = selector.match(Patterns.relative))) {
1152          source = (mode ? '' : FILTER.replace(/@/g, k)) + source;
1153          source = NATIVE_TRAVERSAL_API ?
1154            ('var N' + k + '=e;e=e.parentNode.firstElementChild;' +
1155            'while(e&&e!==N' + k + '){' + source + 'e=e.nextElementSibling;}e=N' + k + ';') :
1156            ('var N' + k + '=e;e=e.parentNode.firstChild;' +
1157            'while(e&&e!==N' + k + '){if(e.nodeName>"@"){' + source + '}e=e.nextSibling;}e=N' + k + ';');
1158        }
1159
1160        // *** Child combinator
1161        // E > F (F children of E)
1162        else if ((match = selector.match(Patterns.children))) {
1163          source = (mode ? '' : FILTER.replace(/@/g, k)) + source;
1164          source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + 'break;}e=N' + k + ';';
1165        }
1166
1167        // *** Descendant combinator
1168        // E F (E ancestor of F)
1169        else if ((match = selector.match(Patterns.ancestor))) {
1170          source = (mode ? '' : FILTER.replace(/@/g, k)) + source;
1171          source = 'var N' + k + '=e;while(e&&e!==h&&e!==g&&(e=e.parentNode)){' + source + '}e=N' + k + ';';
1172        }
1173
1174        // *** Structural pseudo-classes
1175        // :root, :empty,
1176        // :first-child, :last-child, :only-child,
1177        // :first-of-type, :last-of-type, :only-of-type,
1178        // :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-of-type()
1179        else if ((match = selector.match(Patterns.spseudos)) && match[1]) {
1180
1181          switch (match[1]) {
1182            case 'root':
1183              // element root of the document
1184              if (match[3]) {
1185                source = 'if(e===h||s.contains(h,e)){' + source + '}';
1186              } else {
1187                source = 'if(e===h){' + source + '}';
1188              }
1189              break;
1190
1191            case 'empty':
1192              // element that has no children
1193              source = 'if(s.isEmpty(e)){' + source + '}';
1194              break;
1195
1196            default:
1197              if (match[1] && match[2]) {
1198                if (match[2] == 'n') {
1199                  source = 'if(e!==h){' + source + '}';
1200                  break;
1201                } else if (match[2] == 'even') {
1202                  a = 2;
1203                  b = 0;
1204                } else if (match[2] == 'odd') {
1205                  a = 2;
1206                  b = 1;
1207                } else {
1208                  // assumes correct "an+b" format, "b" before "a" to keep "n" values
1209                  b = ((n = match[2].match(/(-?\d+)$/)) ? parseInt(n[1], 10) : 0);
1210                  a = ((n = match[2].match(/(-?\d*)n/i)) ? parseInt(n[1], 10) : 0);
1211                  if (n && n[1] == '-') a = -1;
1212                }
1213
1214                // build test expression out of structural pseudo (an+b) parameters
1215                // see here: http://www.w3.org/TR/css3-selectors/#nth-child-pseudo
1216                test = a > 1 ?
1217                  (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :
1218                  'n>=' + b + '&&(n-(' + b + '))%' + a + '==0' : a < -1 ?
1219                  (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :
1220                  'n<=' + b + '&&(n-(' + b + '))%' + a + '==0' : a === 0 ?
1221                  'n==' + b : a == -1 ? 'n<=' + b : 'n>=' + b;
1222
1223                // 4 cases: 1 (nth) x 4 (child, of-type, last-child, last-of-type)
1224                source =
1225                  'if(e!==h){' +
1226                    'n=s[' + (/-of-type/i.test(match[1]) ? '"nthOfType"' : '"nthElement"') + ']' +
1227                      '(e,' + (/last/i.test(match[1]) ? 'true' : 'false') + ');' +
1228                    'if(' + test + '){' + source + '}' +
1229                  '}';
1230
1231              } else {
1232                // 6 cases: 3 (first, last, only) x 1 (child) x 2 (-of-type)
1233                a = /first/i.test(match[1]) ? 'previous' : 'next';
1234                n = /only/i.test(match[1]) ? 'previous' : 'next';
1235                b = /first|last/i.test(match[1]);
1236
1237                type = /-of-type/i.test(match[1]) ? '&&n.nodeName!=e.nodeName' : '&&n.nodeName<"@"';
1238
1239                source = 'if(e!==h){' +
1240                  ( 'n=e;while((n=n.' + a + 'Sibling)' + type + ');if(!n){' + (b ? source :
1241                    'n=e;while((n=n.' + n + 'Sibling)' + type + ');if(!n){' + source + '}') + '}' ) + '}';
1242              }
1243              break;
1244          }
1245
1246        }
1247
1248        // *** negation, user action and target pseudo-classes
1249        // *** UI element states and dynamic pseudo-classes
1250        // CSS3 :not, :checked, :enabled, :disabled, :target
1251        // CSS3 :active, :hover, :focus
1252        // CSS3 :link, :visited
1253        else if ((match = selector.match(Patterns.dpseudos)) && match[1]) {
1254
1255          switch (match[1].match(/^\w+/)[0]) {
1256            // CSS3 negation pseudo-class
1257            case 'not':
1258              // compile nested selectors, DO NOT pass the callback parameter
1259              // SIMPLENOT allow disabling complex selectors nested
1260              // in ':not()' pseudo-classes, breaks some test units
1261              expr = match[3].replace(reTrimSpaces, '');
1262
1263              if (Config.SIMPLENOT && !reSimpleNot.test(expr)) {
1264                // see above, log error but continue execution
1265                emit('Negation pseudo-class only accepts simple selectors "' + selector + '"');
1266                return '';
1267              } else {
1268                if ('compatMode' in doc) {
1269                  source = 'if(!' + compile(expr, '', false) + '(e,s,r,d,h,g)){' + source + '}';
1270                } else {
1271                  source = 'if(!s.match(e, "' + expr.replace(/\x22/g, '\\"') + '",g)){' + source +'}';
1272                }
1273              }
1274              break;
1275
1276            // CSS3 UI element states
1277            case 'checked':
1278              // for radio buttons checkboxes (HTML4) and options (HTML5)
1279              source = 'if((typeof e.form!=="undefined"&&(/^(?:radio|checkbox)$/i).test(e.type)&&e.checked)' +
1280                (Config.USE_HTML5 ? '||(/^option$/i.test(e.nodeName)&&(e.selected||e.checked))' : '') +
1281                '){' + source + '}';
1282              break;
1283            case 'disabled':
1284              // does not consider hidden input fields
1285              source = 'if(((typeof e.form!=="undefined"' +
1286                (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +
1287                ')||s.isLink(e))&&e.disabled===true){' + source + '}';
1288              break;
1289            case 'enabled':
1290              // does not consider hidden input fields
1291              source = 'if(((typeof e.form!=="undefined"' +
1292                (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +
1293                ')||s.isLink(e))&&e.disabled===false){' + source + '}';
1294              break;
1295
1296            // CSS3 lang pseudo-class
1297            case 'lang':
1298              test = '';
1299              if (match[2]) test = match[2].substr(0, 2) + '-';
1300              source = 'do{(n=e.lang||"").toLowerCase();' +
1301                'if((n==""&&h.lang=="' + match[2].toLowerCase() + '")||' +
1302                '(n&&(n=="' + match[2].toLowerCase() +
1303                '"||n.substr(0,3)=="' + test.toLowerCase() + '")))' +
1304                '{' + source + 'break;}}while((e=e.parentNode)&&e!==g);';
1305              break;
1306
1307            // CSS3 target pseudo-class
1308            case 'target':
1309              source = 'if(e.id==d.location.hash.slice(1)){' + source + '}';
1310              break;
1311
1312            // CSS3 dynamic pseudo-classes
1313            case 'link':
1314              source = 'if(s.isLink(e)&&!e.visited){' + source + '}';
1315              break;
1316            case 'visited':
1317              source = 'if(s.isLink(e)&&e.visited){' + source + '}';
1318              break;
1319
1320            // CSS3 user action pseudo-classes IE & FF3 have native support
1321            // these capabilities may be emulated by some event managers
1322            case 'active':
1323              if (XML_DOCUMENT) break;
1324              source = 'if(e===d.activeElement){' + source + '}';
1325              break;
1326            case 'hover':
1327              if (XML_DOCUMENT) break;
1328              source = 'if(e===d.hoverElement){' + source + '}';
1329              break;
1330            case 'focus':
1331              if (XML_DOCUMENT) break;
1332              source = NATIVE_FOCUS ?
1333                'if(e===d.activeElement&&d.hasFocus()&&(e.type||e.href||typeof e.tabIndex=="number")){' + source + '}' :
1334                'if(e===d.activeElement&&(e.type||e.href)){' + source + '}';
1335              break;
1336
1337            // CSS2 selected pseudo-classes, not part of current CSS3 drafts
1338            // the 'selected' property is only available for option elements
1339            case 'selected':
1340              // fix Safari selectedIndex property bug
1341              expr = BUGGY_SELECTED ? '||(n=e.parentNode)&&n.options[n.selectedIndex]===e' : '';
1342              source = 'if(/^option$/i.test(e.nodeName)&&(e.selected||e.checked' + expr + ')){' + source + '}';
1343              break;
1344
1345            default:
1346              break;
1347          }
1348
1349        }
1350
1351        else {
1352
1353          // this is where external extensions are
1354          // invoked if expressions match selectors
1355          expr = false;
1356          status = false;
1357          for (expr in Selectors) {
1358            if ((match = selector.match(Selectors[expr].Expression)) && match[1]) {
1359              result = Selectors[expr].Callback(match, source);
1360              source = result.source;
1361              status = result.status;
1362              if (status) { break; }
1363            }
1364          }
1365
1366          // if an extension fails to parse the selector
1367          // it must return a false boolean in "status"
1368          if (!status) {
1369            // log error but continue execution, don't throw real exceptions
1370            // because blocking following processes maybe is not a good idea
1371            emit('Unknown pseudo-class selector "' + selector + '"');
1372            return '';
1373          }
1374
1375          if (!expr) {
1376            // see above, log error but continue execution
1377            emit('Unknown token in selector "' + selector + '"');
1378            return '';
1379          }
1380
1381        }
1382
1383        // error if no matches found by the pattern scan
1384        if (!match) {
1385          emit('Invalid syntax in selector "' + selector + '"');
1386          return '';
1387        }
1388
1389        // ensure "match" is not null or empty since
1390        // we do not throw real DOMExceptions above
1391        selector = match && match[match.length - 1];
1392      }
1393
1394      return source;
1395    },
1396
1397  /*----------------------------- QUERY METHODS ------------------------------*/
1398
1399  // match element with selector
1400  // @return boolean
1401  match =
1402    function(element, selector, from, callback) {
1403
1404      var parts;
1405
1406      if (!(element && element.nodeType == 1)) {
1407        emit('Invalid element argument');
1408        return false;
1409      } else if (typeof selector != 'string') {
1410        emit('Invalid selector argument');
1411        return false;
1412      } else if (from && from.nodeType == 1 && !contains(from, element)) {
1413        return false;
1414      } else if (lastContext !== from) {
1415        // reset context data when it changes
1416        // and ensure context is set to a default
1417        switchContext(from || (from = element.ownerDocument));
1418      }
1419
1420      // normalize the selector string, remove [\n\r\f]
1421      // whitespace, replace codepoints 0 with '\ufffd'
1422      // trim non-relevant leading/trailing whitespaces
1423      selector = selector.
1424        replace(reTrimSpaces, '').
1425        replace(/\x00|\\$/g, '\ufffd');
1426
1427      Config.SHORTCUTS && (selector = Dom.shortcuts(selector, element, from));
1428
1429      if (lastMatcher != selector) {
1430        // process valid selector strings
1431        if ((parts = selector.match(reValidator)) && parts[0] == selector) {
1432          isSingleMatch = (parts = selector.match(reSplitGroup)).length < 2;
1433          // save passed selector
1434          lastMatcher = selector;
1435          lastPartsMatch = parts;
1436        } else {
1437          emit('The string "' + selector + '", is not a valid CSS selector');
1438          return false;
1439        }
1440      } else parts = lastPartsMatch;
1441
1442      // compile matcher resolvers if necessary
1443      if (!matchResolvers[selector] || matchContexts[selector] !== from) {
1444        matchResolvers[selector] = compile(isSingleMatch ? [selector] : parts, '', false);
1445        matchContexts[selector] = from;
1446      }
1447
1448      return matchResolvers[selector](element, Snapshot, [ ], doc, root, from, callback, { });
1449    },
1450
1451  // select only the first element
1452  // matching selector (document ordered)
1453  first =
1454    function(selector, from) {
1455      return select(selector, from, function() { return false; })[0] || null;
1456    },
1457
1458  // select elements matching selector
1459  // using new Query Selector API
1460  // or cross-browser client API
1461  // @return array
1462  select =
1463    function(selector, from, callback) {
1464
1465      var i, changed, element, elements, parts, token, original = selector;
1466
1467      if (arguments.length === 0) {
1468        emit('Not enough arguments');
1469        return [ ];
1470      } else if (typeof selector != 'string') {
1471        return [ ];
1472      } else if (from && !(/1|9|11/).test(from.nodeType)) {
1473        emit('Invalid or illegal context element');
1474        return [ ];
1475      } else if (lastContext !== from) {
1476        // reset context data when it changes
1477        // and ensure context is set to a default
1478        switchContext(from || (from = doc));
1479      }
1480
1481      if (Config.CACHING && (elements = Dom.loadResults(original, from, doc, root))) {
1482        return callback ? concatCall([ ], elements, callback) : elements;
1483      }
1484
1485      // normalize the selector string, remove [\n\r\f]
1486      // whitespace, replace codepoints 0 with '\ufffd'
1487      // trim non-relevant leading/trailing whitespaces
1488      selector = selector.
1489        replace(reTrimSpaces, '').
1490        replace(/\x00|\\$/g, '\ufffd');
1491
1492      if (!OPERA_QSAPI && reSimpleSelector.test(selector)) {
1493        switch (selector.charAt(0)) {
1494          case '#':
1495            if (Config.UNIQUE_ID) {
1496              elements = (element = _byId(selector.slice(1), from)) ? [ element ] : [ ];
1497            }
1498            break;
1499          case '.':
1500            elements = _byClass(selector.slice(1), from);
1501            break;
1502          default:
1503            elements = _byTag(selector, from);
1504            break;
1505        }
1506      }
1507
1508      else if (!XML_DOCUMENT && Config.USE_QSAPI &&
1509        !(BUGGY_QUIRKS_QSAPI && reClass.test(selector)) &&
1510        !RE_BUGGY_QSAPI.test(selector)) {
1511        try {
1512          elements = from.querySelectorAll(selector);
1513        } catch(e) { }
1514      }
1515
1516      if (elements) {
1517        elements = callback ? concatCall([ ], elements, callback) :
1518          NATIVE_SLICE_PROTO ? slice.call(elements) : concatList([ ], elements);
1519        Config.CACHING && Dom.saveResults(original, from, doc, elements);
1520        return elements;
1521      }
1522
1523      Config.SHORTCUTS && (selector = Dom.shortcuts(selector, from));
1524
1525      if ((changed = lastSelector != selector)) {
1526        // process valid selector strings
1527        if ((parts = selector.match(reValidator)) && parts[0] == selector) {
1528          isSingleSelect = (parts = selector.match(reSplitGroup)).length < 2;
1529          // save passed selector
1530          lastSelector = selector;
1531          lastPartsSelect = parts;
1532        } else {
1533          emit('The string "' + selector + '", is not a valid CSS selector');
1534          return [ ];
1535        }
1536      } else parts = lastPartsSelect;
1537
1538      // commas separators are treated sequentially to maintain order
1539      if (from.nodeType == 11) {
1540
1541        elements = byTagRaw('*', from);
1542
1543      } else if (!XML_DOCUMENT && isSingleSelect) {
1544
1545        if (changed) {
1546          // get right most selector token
1547          parts = selector.match(reSplitToken);
1548          token = parts[parts.length - 1];
1549
1550          // only last slice before :not rules
1551          lastSlice = token.split(':not');
1552          lastSlice = lastSlice[lastSlice.length - 1];
1553
1554          // position where token was found
1555          lastPosition = selector.length - token.length;
1556        }
1557
1558        // ID optimization RTL, to reduce number of elements to visit
1559        if (Config.UNIQUE_ID && (parts = lastSlice.match(Optimize.ID)) && (token = parts[1])) {
1560          if ((element = _byId(token, from))) {
1561            if (match(element, selector)) {
1562              callback && callback(element);
1563              elements = [element];
1564            } else elements = [ ];
1565          }
1566        }
1567
1568        // ID optimization LTR, to reduce selection context searches
1569        else if (Config.UNIQUE_ID && (parts = selector.match(Optimize.ID)) && (token = parts[1])) {
1570          if ((element = _byId(token, doc))) {
1571            if ('#' + token == selector) {
1572              callback && callback(element);
1573              elements = [element];
1574            } else if (/[>+~]/.test(selector)) {
1575              from = element.parentNode;
1576            } else {
1577              from = element;
1578            }
1579          } else elements = [ ];
1580        }
1581
1582        if (elements) {
1583          Config.CACHING && Dom.saveResults(original, from, doc, elements);
1584          return elements;
1585        }
1586
1587        if (!NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {
1588          if ((elements = _byTag(token, from)).length === 0) { return [ ]; }
1589          selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*');
1590        }
1591
1592        else if ((parts = lastSlice.match(Optimize.CLASS)) && (token = parts[1])) {
1593          if ((elements = _byClass(token, from)).length === 0) { return [ ]; }
1594          selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token,
1595            reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1)) ? '' : '*');
1596        }
1597
1598        else if ((parts = selector.match(Optimize.CLASS)) && (token = parts[1])) {
1599          if ((elements = _byClass(token, from)).length === 0) { return [ ]; }
1600          for (i = 0, els = [ ]; elements.length > i; ++i) {
1601            els = concatList(els, elements[i].getElementsByTagName('*'));
1602          }
1603          elements = els;
1604          selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace('.' + token,
1605            reOptimizeSelector.test(selector.charAt(selector.indexOf(token) - 1)) ? '' : '*');
1606        }
1607
1608        else if (NATIVE_GEBCN && (parts = lastSlice.match(Optimize.TAG)) && (token = parts[1])) {
1609          if ((elements = _byTag(token, from)).length === 0) { return [ ]; }
1610          selector = selector.slice(0, lastPosition) + selector.slice(lastPosition).replace(token, '*');
1611        }
1612
1613      }
1614
1615      if (!elements) {
1616        if (IE_LT_9) {
1617          elements = /^(?:applet|object)$/i.test(from.nodeName) ? from.children : byTagRaw('*', from);
1618        } else {
1619          elements = from.getElementsByTagName('*');
1620        }
1621      }
1622      // end of prefiltering pass
1623
1624      // compile selector resolver if necessary
1625      if (!selectResolvers[selector] || selectContexts[selector] !== from) {
1626        selectResolvers[selector] = compile(isSingleSelect ? [selector] : parts, '', true);
1627        selectContexts[selector] = from;
1628      }
1629
1630      elements = selectResolvers[selector](elements, Snapshot, [ ], doc, root, from, callback, { });
1631
1632      Config.CACHING && Dom.saveResults(original, from, doc, elements);
1633
1634      return elements;
1635    },
1636
1637  /*-------------------------------- STORAGE ---------------------------------*/
1638
1639  // empty function handler
1640  FN = function(x) { return x; },
1641
1642  // compiled match functions returning booleans
1643  matchContexts = { },
1644  matchResolvers = { },
1645
1646  // compiled select functions returning collections
1647  selectContexts = { },
1648  selectResolvers = { },
1649
1650  // used to pass methods to compiled functions
1651  Snapshot = {
1652
1653    // element indexing methods
1654    nthElement: nthElement,
1655    nthOfType: nthOfType,
1656
1657    // element inspection methods
1658    getAttribute: getAttribute,
1659    hasAttribute: hasAttribute,
1660
1661    // element selection methods
1662    byClass: _byClass,
1663    byName: byName,
1664    byTag: _byTag,
1665    byId: _byId,
1666
1667    // helper/check methods
1668    contains: contains,
1669    isEmpty: isEmpty,
1670    isLink: isLink,
1671
1672    // selection/matching
1673    select: select,
1674    match: match
1675  },
1676
1677  /*------------------------------- PUBLIC API -------------------------------*/
1678
1679  // code referenced by extensions
1680  Dom = {
1681
1682    ACCEPT_NODE: ACCEPT_NODE,
1683
1684    // retrieve element by id attr
1685    byId: byId,
1686
1687    // retrieve elements by tag name
1688    byTag: byTag,
1689
1690    // retrieve elements by name attr
1691    byName: byName,
1692
1693    // retrieve elements by class name
1694    byClass: byClass,
1695
1696    // read the value of the attribute
1697    // as was in the original HTML code
1698    getAttribute: getAttribute,
1699
1700    // check for the attribute presence
1701    // as was in the original HTML code
1702    hasAttribute: hasAttribute,
1703
1704    // element match selector, return boolean true/false
1705    match: match,
1706
1707    // first element match only, return element or null
1708    first: first,
1709
1710    // elements matching selector, starting from element
1711    select: select,
1712
1713    // compile selector into ad-hoc javascript resolver
1714    compile: compile,
1715
1716    // check that two elements are ancestor/descendant
1717    contains: contains,
1718
1719    // handle selector engine configuration settings
1720    configure: configure,
1721
1722    // initialize caching for each document
1723    setCache: FN,
1724
1725    // load previously collected result set
1726    loadResults: FN,
1727
1728    // save previously collected result set
1729    saveResults: FN,
1730
1731    // handle missing context in selector strings
1732    shortcuts: FN,
1733
1734    // log resolvers errors/warnings
1735    emit: emit,
1736
1737    // options enabing specific engine functionality
1738    Config: Config,
1739
1740    // pass methods references to compiled resolvers
1741    Snapshot: Snapshot,
1742
1743    // operators descriptor
1744    // for attribute operators extensions
1745    Operators: Operators,
1746
1747    // selectors descriptor
1748    // for pseudo-class selectors extensions
1749    Selectors: Selectors,
1750
1751    // export validators REs
1752    Tokens: Tokens,
1753
1754    // export version string
1755    Version: version,
1756
1757    // add or overwrite user defined operators
1758    registerOperator:
1759      function(symbol, resolver) {
1760        Operators[symbol] || (Operators[symbol] = resolver);
1761      },
1762
1763    // add selector patterns for user defined callbacks
1764    registerSelector:
1765      function(name, rexp, func) {
1766        Selectors[name] || (Selectors[name] = {
1767          Expression: rexp,
1768          Callback: func
1769        });
1770      }
1771
1772  };
1773
1774  /*---------------------------------- INIT ----------------------------------*/
1775
1776  // init context specific variables
1777  initialize(doc);
1778
1779  return Dom;
1780});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.