PageSourceSearch

https://emacenter.com/Scripts/jQueryPlugin/jQueryBbqFull.js?09251132

js emacenter.com collected 2026-10-05 22:41:27 UTC 52,640 bytes, 1,287 lines download raw bytes

1/*!
2 * jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
3 * http://benalman.com/projects/jquery-bbq-plugin/
4 * 
5 * Copyright (c) 2010 "Cowboy" Ben Alman
6 * Dual licensed under the MIT and GPL licenses.
7 * http://benalman.com/about/license/
8 */
9
10// Script: jQuery BBQ: Back Button & Query Library
11//
12// *Version: 1.3pre, Last updated: 8/26/2010*
13// 
14// Project Home - http://benalman.com/projects/jquery-bbq-plugin/
15// GitHub       - http://github.com/cowboy/jquery-bbq/
16// Source       - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
17// (Minified)   - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (2.2kb gzipped)
18// 
19// About: License
20// 
21// Copyright (c) 2010 "Cowboy" Ben Alman,
22// Dual licensed under the MIT and GPL licenses.
23// http://benalman.com/about/license/
24// 
25// About: Examples
26// 
27// These working examples, complete with fully commented code, illustrate a few
28// ways in which this plugin can be used.
29// 
30// Basic AJAX     - http://benalman.com/code/projects/jquery-bbq/examples/fragment-basic/
31// Advanced AJAX  - http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/
32// jQuery UI Tabs - http://benalman.com/code/projects/jquery-bbq/examples/fragment-jquery-ui-tabs/
33// Deparam        - http://benalman.com/code/projects/jquery-bbq/examples/deparam/
34// 
35// About: Support and Testing
36// 
37// Information about what version or versions of jQuery this plugin has been
38// tested with, what browsers it has been tested in, and where the unit tests
39// reside (so you can test it yourself).
40// 
41// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
42// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
43//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
44// Unit Tests      - http://benalman.com/code/projects/jquery-bbq/unit/
45// 
46// About: Release History
47// 
48// 1.3pre - (8/26/2010) Integrated <jQuery hashchange event> v1.3, which adds
49//         document.title and document.domain support in IE6/7, BlackBerry
50//         support, better Iframe hiding for accessibility reasons, and the new
51//         <jQuery.fn.hashchange> "shortcut" method. Added the
52//         <jQuery.param.sorted> method which reduces the possibility of
53//         extraneous hashchange event triggering. Added the
54//         <jQuery.param.fragment.ajaxCrawlable> method which can be used to
55//         enable Google "AJAX Crawlable mode."
56// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
57//         <jQuery hashchange event> in BBQ, which was the main reason for the
58//         previous release!
59// 1.2   - (2/16/2010) Integrated <jQuery hashchange event> v1.2, which fixes a
60//         Safari bug, the event can now be bound before DOM ready, and IE6/7
61//         page should no longer scroll when the event is first bound. Also
62//         added the <jQuery.param.fragment.noEscape> method, and reworked the
63//         <hashchange event (BBQ)> internal "add" method to be compatible with
64//         changes made to the jQuery 1.4.2 special events API.
65// 1.1.1 - (1/22/2010) Integrated <jQuery hashchange event> v1.1, which fixes an
66//         obscure IE8 EmulateIE7 meta tag compatibility mode bug.
67// 1.1   - (1/9/2010) Broke out the jQuery BBQ event.special <hashchange event>
68//         functionality into a separate plugin for users who want just the
69//         basic event & back button support, without all the extra awesomeness
70//         that BBQ provides. This plugin will be included as part of jQuery BBQ,
71//         but also be available separately. See <jQuery hashchange event>
72//         plugin for more information. Also added the <jQuery.bbq.removeState>
73//         method and added additional <jQuery.deparam> examples.
74// 1.0.3 - (12/2/2009) Fixed an issue in IE 6 where location.search and
75//         location.hash would report incorrectly if the hash contained the ?
76//         character. Also <jQuery.param.querystring> and <jQuery.param.fragment>
77//         will no longer parse params out of a URL that doesn't contain ? or #,
78//         respectively.
79// 1.0.2 - (10/10/2009) Fixed an issue in IE 6/7 where the hidden IFRAME caused
80//         a "This page contains both secure and nonsecure items." warning when
81//         used on an https:// page.
82// 1.0.1 - (10/7/2009) Fixed an issue in IE 8. Since both "IE7" and "IE8
83//         Compatibility View" modes erroneously report that the browser
84//         supports the native window.onhashchange event, a slightly more
85//         robust test needed to be added.
86// 1.0   - (10/2/2009) Initial release
87
88(function ($, window) {
89    '$:nomunge'; // Used by YUI compressor.
90
91    // Some convenient shortcuts.
92    var undefined,
93        aps = Array.prototype.slice,
94        decode = decodeURIComponent,
95
96        // Method / object references.
97        jq_param = $.param,
98        jq_param_sorted,
99        jq_param_fragment,
100        jq_deparam,
101        jq_deparam_fragment,
102        jq_bbq = $.bbq = $.bbq || {},
103        jq_bbq_pushState,
104        jq_bbq_getState,
105        jq_elemUrlAttr,
106        special = $.event.special,
107
108        // Reused strings.
109        str_hashchange = 'hashchange',
110        str_querystring = 'querystring',
111        str_fragment = 'fragment',
112        str_elemUrlAttr = 'elemUrlAttr',
113        str_href = 'href',
114        str_src = 'src',
115
116        // Reused RegExp.
117        re_params_querystring = /^.*\?|#.*$/g,
118        re_params_fragment,
119        re_fragment,
120        re_no_escape,
121
122        ajax_crawlable,
123        fragment_prefix,
124
125        // Used by jQuery.elemUrlAttr.
126        elemUrlAttr_cache = {};
127
128    // A few commonly used bits, broken out to help reduce minified file size.
129
130    function is_string(arg) {
131        return typeof arg === 'string';
132    };
133
134    // Why write the same function twice? Let's curry! Mmmm, curry..
135
136    function curry(func) {
137        var args = aps.call(arguments, 1);
138
139        return function () {
140            return func.apply(this, args.concat(aps.call(arguments)));
141        };
142    };
143
144    // Get location.hash (or what you'd expect location.hash to be) sans any
145    // leading #. Thanks for making this necessary, Firefox!
146    function get_fragment(url) {
147        return url.replace(re_fragment, '$2');
148    };
149
150    // Get location.search (or what you'd expect location.search to be) sans any
151    // leading #. Thanks for making this necessary, IE6!
152    function get_querystring(url) {
153        return url.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/, '$1');
154    };
155
156    // Section: Param (to string)
157    // 
158    // Method: jQuery.param.querystring
159    // 
160    // Retrieve the query string from a URL or if no arguments are passed, the
161    // current window.location.href.
162    // 
163    // Usage:
164    // 
165    // > jQuery.param.querystring( [ url ] );
166    // 
167    // Arguments:
168    // 
169    //  url - (String) A URL containing query string params to be parsed. If url
170    //    is not passed, the current window.location.href is used.
171    // 
172    // Returns:
173    // 
174    //  (String) The parsed query string, with any leading "?" removed.
175    //
176
177    // Method: jQuery.param.querystring (build url)
178    // 
179    // Merge a URL, with or without pre-existing query string params, plus any
180    // object, params string or URL containing query string params into a new URL.
181    // 
182    // Usage:
183    // 
184    // > jQuery.param.querystring( url, params [, merge_mode ] );
185    // 
186    // Arguments:
187    // 
188    //  url - (String) A valid URL for params to be merged into. This URL may
189    //    contain a query string and/or fragment (hash).
190    //  params - (String) A params string or URL containing query string params to
191    //    be merged into url.
192    //  params - (Object) A params object to be merged into url.
193    //  merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
194    //    specified, and is as-follows:
195    // 
196    //    * 0: params in the params argument will override any query string
197    //         params in url.
198    //    * 1: any query string params in url will override params in the params
199    //         argument.
200    //    * 2: params argument will completely replace any query string in url.
201    // 
202    // Returns:
203    // 
204    //  (String) A URL with a urlencoded query string in the format '?a=b&c=d&e=f'.
205
206    // Method: jQuery.param.fragment
207    // 
208    // Retrieve the fragment (hash) from a URL or if no arguments are passed, the
209    // current window.location.href.
210    // 
211    // Usage:
212    // 
213    // > jQuery.param.fragment( [ url ] );
214    // 
215    // Arguments:
216    // 
217    //  url - (String) A URL containing fragment (hash) params to be parsed. If
218    //    url is not passed, the current window.location.href is used.
219    // 
220    // Returns:
221    // 
222    //  (String) The parsed fragment (hash) string, with any leading "#" removed.
223
224    // Method: jQuery.param.fragment (build url)
225    // 
226    // Merge a URL, with or without pre-existing fragment (hash) params, plus any
227    // object, params string or URL containing fragment (hash) params into a new
228    // URL.
229    // 
230    // Usage:
231    // 
232    // > jQuery.param.fragment( url, params [, merge_mode ] );
233    // 
234    // Arguments:
235    // 
236    //  url - (String) A valid URL for params to be merged into. This URL may
237    //    contain a query string and/or fragment (hash).
238    //  params - (String) A params string or URL containing fragment (hash) params
239    //    to be merged into url.
240    //  params - (Object) A params object to be merged into url.
241    //  merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
242    //    specified, and is as-follows:
243    // 
244    //    * 0: params in the params argument will override any fragment (hash)
245    //         params in url.
246    //    * 1: any fragment (hash) params in url will override params in the
247    //         params argument.
248    //    * 2: params argument will completely replace any query string in url.
249    // 
250    // Returns:
251    // 
252    //  (String) A URL with a urlencoded fragment (hash) in the format '#a=b&c=d&e=f'.
253
254    function jq_param_sub(is_fragment, get_func, url, params, merge_mode) {
255        var result,
256            qs,
257            matches,
258            url_params,
259            hash;
260
261        if (params !== undefined) {
262            // Build URL by merging params into url string.
263
264            // matches[1] = url part that precedes params, not including trailing ?/#
265            // matches[2] = params, not including leading ?/#
266            // matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
267            matches = url.match(is_fragment ? re_fragment : /^([^#?]*)\??([^#]*)(#?.*)/);
268
269            // Get the hash if in 'querystring' mode, and it exists.
270            hash = matches[3] || '';
271
272            if (merge_mode === 2 && is_string(params)) {
273                // If merge_mode is 2 and params is a string, merge the fragment / query
274                // string into the URL wholesale, without converting it into an object.
275                qs = params.replace(is_fragment ? re_params_fragment : re_params_querystring, '');
276
277            } else {
278                // Convert relevant params in url to object.
279                url_params = jq_deparam(matches[2]);
280
281                params = is_string(params)
282
283                    // Convert passed params string into object.
284                    ? jq_deparam[is_fragment ? str_fragment : str_querystring](params)
285
286                    // Passed params object.
287                    : params;
288
289                qs = merge_mode === 2 ? params                              // passed params replace url params
290                    : merge_mode === 1 ? $.extend({}, params, url_params)  // url params override passed params
291                        : $.extend({}, url_params, params);                     // passed params override url params
292
293                // Convert params object into a sorted params string.
294                qs = jq_param_sorted(qs);
295
296                // Unescape characters specified via $.param.noEscape. Since only hash-
297                // history users have requested this feature, it's only enabled for
298                // fragment-related params strings.
299                if (is_fragment) {
300                    qs = qs.replace(re_no_escape, decode);
301                }
302            }
303
304            // Build URL from the base url, querystring and hash. In 'querystring'
305            // mode, ? is only added if a query string exists. In 'fragment' mode, #
306            // is always added.
307            result = matches[1] + (is_fragment ? fragment_prefix : qs || !matches[1] ? '?' : '') + qs + hash;
308
309        } else {
310            // If URL was passed in, parse params from URL string, otherwise parse
311            // params from window.location.href.
312            result = get_func(url !== undefined ? url : location.href);
313        }
314
315        return result;
316    };
317
318    jq_param[str_querystring] = curry(jq_param_sub, 0, get_querystring);
319    jq_param[str_fragment] = jq_param_fragment = curry(jq_param_sub, 1, get_fragment);
320
321    // Method: jQuery.param.sorted
322    // 
323    // Returns a params string equivalent to that returned by the internal
324    // jQuery.param method, but sorted, which makes it suitable for use as a
325    // cache key.
326    // 
327    // For example, in most browsers jQuery.param({z:1,a:2}) returns "z=1&a=2"
328    // and jQuery.param({a:2,z:1}) returns "a=2&z=1". Even though both the
329    // objects being serialized and the resulting params strings are equivalent,
330    // if these params strings were set into the location.hash fragment
331    // sequentially, the hashchange event would be triggered unnecessarily, since
332    // the strings are different (even though the data described by them is the
333    // same). By sorting the params string, unecessary hashchange event triggering
334    // can be avoided.
335    // 
336    // Usage:
337    // 
338    // > jQuery.param.sorted( obj [, traditional ] );
339    // 
340    // Arguments:
341    // 
342    //  obj - (Object) An object to be serialized.
343    //  traditional - (Boolean) Params deep/shallow serialization mode. See the
344    //    documentation at http://api.jquery.com/jQuery.param/ for more detail.
345    // 
346    // Returns:
347    // 
348    //  (String) A sorted params string.
349
350    jq_param.sorted = jq_param_sorted = function (a, traditional) {
351        var arr = [],
352            obj = {};
353
354        $.each(jq_param(a, traditional).split('&'), function (i, v) {
355            var key = v.replace(/(?:%5B|=).*$/, ''),
356                key_obj = obj[key];
357
358            if (!key_obj) {
359                key_obj = obj[key] = [];
360                arr.push(key);
361            }
362
363            key_obj.push(v);
364        });
365
366        return $.map(arr.sort(), function (v) {
367            return obj[v];
368        }).join('&');
369    };
370
371    // Method: jQuery.param.fragment.noEscape
372    // 
373    // Specify characters that will be left unescaped when fragments are created
374    // or merged using <jQuery.param.fragment>, or when the fragment is modified
375    // using <jQuery.bbq.pushState>. This option only applies to serialized data
376    // object fragments, and not set-as-string fragments. Does not affect the
377    // query string. Defaults to ",/" (comma, forward slash).
378    // 
379    // Note that this is considered a purely aesthetic option, and will help to
380    // create URLs that "look pretty" in the address bar or bookmarks, without
381    // affecting functionality in any way. That being said, be careful to not
382    // unescape characters that are used as delimiters or serve a special
383    // purpose, such as the "#?&=+" (octothorpe, question mark, ampersand,
384    // equals, plus) characters.
385    // 
386    // Usage:
387    // 
388    // > jQuery.param.fragment.noEscape( [ chars ] );
389    // 
390    // Arguments:
391    // 
392    //  chars - (String) The characters to not escape in the fragment. If
393    //    unspecified, defaults to empty string (escape all characters).
394    // 
395    // Returns:
396    // 
397    //  Nothing.
398
399    jq_param_fragment.noEscape = function (chars) {
400        chars = chars || '';
401        var arr = $.map(chars.split(''), encodeURIComponent);
402        re_no_escape = new RegExp(arr.join('|'), 'g');
403    };
404
vendor: 5,795 bytes, lines 405-555
405    // A sensible default. These are the characters people seem to complain about
406    // "uglifying up the URL" the most.
407    jq_param_fragment.noEscape(',/');
408
409    // Method: jQuery.param.fragment.ajaxCrawlable
410    // 
411    // TODO: DESCRIBE
412    // 
413    // Usage:
414    // 
415    // > jQuery.param.fragment.ajaxCrawlable( [ state ] );
416    // 
417    // Arguments:
418    // 
419    //  state - (Boolean) TODO: DESCRIBE
420    // 
421    // Returns:
422    // 
423    //  (Boolean) The current ajaxCrawlable state.
424
425    jq_param_fragment.ajaxCrawlable = function (state) {
426        if (state !== undefined) {
427            if (state) {
428                re_params_fragment = /^.*(?:#!|#)/;
429                re_fragment = /^([^#]*)(?:#!|#)?(.*)$/;
430                fragment_prefix = '#!';
431            } else {
432                re_params_fragment = /^.*#/;
433                re_fragment = /^([^#]*)#?(.*)$/;
434                fragment_prefix = '#';
435            }
436            ajax_crawlable = !!state;
437        }
438
439        return ajax_crawlable;
440    };
441
442    jq_param_fragment.ajaxCrawlable(0);
443
444    // Section: Deparam (from string)
445    // 
446    // Method: jQuery.deparam
447    // 
448    // Deserialize a params string into an object, optionally coercing numbers,
449    // booleans, null and undefined values; this method is the counterpart to the
450    // internal jQuery.param method.
451    // 
452    // Usage:
453    // 
454    // > jQuery.deparam( params [, coerce ] );
455    // 
456    // Arguments:
457    // 
458    //  params - (String) A params string to be parsed.
459    //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
460    //    undefined to their actual value. Defaults to false if omitted.
461    // 
462    // Returns:
463    // 
464    //  (Object) An object representing the deserialized params string.
465
466    $.deparam = jq_deparam = function (params, coerce) {
467        var obj = {},
468            coerce_types = { 'true': !0, 'false': !1, 'null': null };
469
470        // Iterate over all name=value pairs.
471        $.each(params.replace(/\+/g, ' ').split('&'), function (j, v) {
472            var param = v.split('='),
473                key = decode(param[0]),
474                val,
475                cur = obj,
476                i = 0,
477
478                // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it
479                // into its component parts.
480                keys = key.split(']['),
481                keys_last = keys.length - 1;
482
483            // If the first keys part contains [ and the last ends with ], then []
484            // are correctly balanced.
485            if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) {
486                // Remove the trailing ] from the last keys part.
487                keys[keys_last] = keys[keys_last].replace(/\]$/, '');
488
489                // Split first keys part into two parts on the [ and add them back onto
490                // the beginning of the keys array.
491                keys = keys.shift().split('[').concat(keys);
492
493                keys_last = keys.length - 1;
494            } else {
495                // Basic 'foo' style key.
496                keys_last = 0;
497            }
498
499            // Are we dealing with a name=value pair, or just a name?
500            if (param.length === 2) {
501                val = decode(param[1]);
502
503                // Coerce values.
504                if (coerce) {
505                    val = val && !isNaN(val) ? +val              // number
506                        : val === 'undefined' ? undefined         // undefined
507                            : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null
508                                : val;                                                // string
509                }
510
511                if (keys_last) {
512                    // Complex key, build deep object structure based on a few rules:
513                    // * The 'cur' pointer starts at the object top-level.
514                    // * [] = array push (n is set to array length), [n] = array if n is 
515                    //   numeric, otherwise object.
516                    // * If at the last keys part, set the value.
517                    // * For each keys part, if the current level is undefined create an
518                    //   object or array based on the type of the next keys part.
519                    // * Move the 'cur' pointer to the next level.
520                    // * Rinse & repeat.
521                    for (; i <= keys_last; i++) {
522                        key = keys[i] === '' ? cur.length : keys[i];
523                        cur = cur[key] = i < keys_last
524                            ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : [])
525                            : val;
526                    }
527
528                } else {
529                    // Simple key, even simpler rules, since only scalars and shallow
530                    // arrays are allowed.
531
532                    if ($.isArray(obj[key])) {
533                        // val is already an array, so push on the next value.
534                        obj[key].push(val);
535
536                    } else if (obj[key] !== undefined) {
537                        // val isn't an array, but since a second value has been specified,
538                        // convert val into an array.
539                        obj[key] = [obj[key], val];
540
541                    } else {
542                        // val is a scalar.
543                        obj[key] = val;
544                    }
545                }
546
547            } else if (key) {
548                // No value was defined, so set something meaningful.
549                obj[key] = coerce
550                    ? undefined
551                    : '';
552            }
553        });
554
555        return obj;
556    };
557
558    // Method: jQuery.deparam.querystring
559    // 
560    // Parse the query string from a URL or the current window.location.href,
561    // deserializing it into an object, optionally coercing numbers, booleans,
562    // null and undefined values.
563    // 
564    // Usage:
565    // 
566    // > jQuery.deparam.querystring( [ url ] [, coerce ] );
567    // 
568    // Arguments:
569    // 
570    //  url - (String) An optional params string or URL containing query string
571    //    params to be parsed. If url is omitted, the current
572    //    window.location.href is used.
573    //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
574    //    undefined to their actual value. Defaults to false if omitted.
575    // 
576    // Returns:
577    // 
578    //  (Object) An object representing the deserialized params string.
579
580    // Method: jQuery.deparam.fragment
581    // 
582    // Parse the fragment (hash) from a URL or the current window.location.href,
583    // deserializing it into an object, optionally coercing numbers, booleans,
584    // null and undefined values.
585    // 
586    // Usage:
587    // 
588    // > jQuery.deparam.fragment( [ url ] [, coerce ] );
589    // 
590    // Arguments:
591    // 
592    //  url - (String) An optional params string or URL containing fragment (hash)
593    //    params to be parsed. If url is omitted, the current window.location.href
594    //    is used.
595    //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
596    //    undefined to their actual value. Defaults to false if omitted.
597    // 
598    // Returns:
599    // 
600    //  (Object) An object representing the deserialized params string.
601
602    function jq_deparam_sub(is_fragment, url_or_params, coerce) {
603        if (url_or_params === undefined || typeof url_or_params === 'boolean') {
604            // url_or_params not specified.
605            coerce = url_or_params;
606            url_or_params = jq_param[is_fragment ? str_fragment : str_querystring]();
607        } else {
608            url_or_params = is_string(url_or_params)
609                ? url_or_params.replace(is_fragment ? re_params_fragment : re_params_querystring, '')
610                : url_or_params;
611        }
612
613        return jq_deparam(url_or_params, coerce);
614    };
615
616    jq_deparam[str_querystring] = curry(jq_deparam_sub, 0);
617    jq_deparam[str_fragment] = jq_deparam_fragment = curry(jq_deparam_sub, 1);
618
619    // Section: Element manipulation
620    // 
621    // Method: jQuery.elemUrlAttr
622    // 
623    // Get the internal "Default URL attribute per tag" list, or augment the list
624    // with additional tag-attribute pairs, in case the defaults are insufficient.
625    // 
626    // In the <jQuery.fn.querystring> and <jQuery.fn.fragment> methods, this list
627    // is used to determine which attribute contains the URL to be modified, if
628    // an "attr" param is not specified.
629    // 
630    // Default Tag-Attribute List:
631    // 
632    //  a      - href
633    //  base   - href
634    //  iframe - src
635    //  img    - src
636    //  input  - src
637    //  form   - action
638    //  link   - href
639    //  script - src
640    // 
641    // Usage:
642    // 
643    // > jQuery.elemUrlAttr( [ tag_attr ] );
644    // 
645    // Arguments:
646    // 
647    //  tag_attr - (Object) An object containing a list of tag names and their
648    //    associated default attribute names in the format { tag: 'attr', ... } to
649    //    be merged into the internal tag-attribute list.
650    // 
651    // Returns:
652    // 
653    //  (Object) An object containing all stored tag-attribute values.
654
655    // Only define function and set defaults if function doesn't already exist, as
656    // the urlInternal plugin will provide this method as well.
657    $[str_elemUrlAttr] || ($[str_elemUrlAttr] = function (obj) {
658        return $.extend(elemUrlAttr_cache, obj);
659    })({
660        a: str_href,
661        base: str_href,
662        iframe: str_src,
663        img: str_src,
664        input: str_src,
665        form: 'action',
666        link: str_href,
667        script: str_src
668    });
669
670    jq_elemUrlAttr = $[str_elemUrlAttr];
671
672    // Method: jQuery.fn.querystring
673    // 
674    // Update URL attribute in one or more elements, merging the current URL (with
675    // or without pre-existing query string params) plus any params object or
676    // string into a new URL, which is then set into that attribute. Like
677    // <jQuery.param.querystring (build url)>, but for all elements in a jQuery
678    // collection.
679    // 
680    // Usage:
681    // 
682    // > jQuery('selector').querystring( [ attr, ] params [, merge_mode ] );
683    // 
684    // Arguments:
685    // 
686    //  attr - (String) Optional name of an attribute that will contain a URL to
687    //    merge params or url into. See <jQuery.elemUrlAttr> for a list of default
688    //    attributes.
689    //  params - (Object) A params object to be merged into the URL attribute.
690    //  params - (String) A URL containing query string params, or params string
691    //    to be merged into the URL attribute.
692    //  merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
693    //    specified, and is as-follows:
694    //    
695    //    * 0: params in the params argument will override any params in attr URL.
696    //    * 1: any params in attr URL will override params in the params argument.
697    //    * 2: params argument will completely replace any query string in attr
698    //         URL.
699    // 
700    // Returns:
701    // 
702    //  (jQuery) The initial jQuery collection of elements, but with modified URL
703    //  attribute values.
704
705    // Method: jQuery.fn.fragment
706    // 
707    // Update URL attribute in one or more elements, merging the current URL (with
708    // or without pre-existing fragment/hash params) plus any params object or
709    // string into a new URL, which is then set into that attribute. Like
710    // <jQuery.param.fragment (build url)>, but for all elements in a jQuery
711    // collection.
712    // 
713    // Usage:
714    // 
715    // > jQuery('selector').fragment( [ attr, ] params [, merge_mode ] );
716    // 
717    // Arguments:
718    // 
719    //  attr - (String) Optional name of an attribute that will contain a URL to
720    //    merge params into. See <jQuery.elemUrlAttr> for a list of default
721    //    attributes.
722    //  params - (Object) A params object to be merged into the URL attribute.
723    //  params - (String) A URL containing fragment (hash) params, or params
724    //    string to be merged into the URL attribute.
725    //  merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
726    //    specified, and is as-follows:
727    //    
728    //    * 0: params in the params argument will override any params in attr URL.
729    //    * 1: any params in attr URL will override params in the params argument.
730    //    * 2: params argument will completely replace any fragment (hash) in attr
731    //         URL.
732    // 
733    // Returns:
734    // 
735    //  (jQuery) The initial jQuery collection of elements, but with modified URL
736    //  attribute values.
737
738    function jq_fn_sub(mode, force_attr, params, merge_mode) {
739        if (!is_string(params) && typeof params !== 'object') {
740            // force_attr not specified.
741            merge_mode = params;
742            params = force_attr;
743            force_attr = undefined;
744        }
745
746        return this.each(function () {
747            var that = $(this),
748
749                // Get attribute specified, or default specified via $.elemUrlAttr.
750                attr = force_attr || jq_elemUrlAttr()[(this.nodeName || '').toLowerCase()] || '',
751
752                // Get URL value.
753                url = attr && that.attr(attr) || '';
754
755            // Update attribute with new URL.
756            that.attr(attr, jq_param[mode](url, params, merge_mode));
757        });
758
759    };
760
761    $.fn[str_querystring] = curry(jq_fn_sub, str_querystring);
762    $.fn[str_fragment] = curry(jq_fn_sub, str_fragment);
763
764    // Section: History, hashchange event
765    // 
766    // Method: jQuery.bbq.pushState
767    // 
768    // Adds a 'state' into the browser history at the current position, setting
769    // location.hash and triggering any bound <hashchange event> callbacks
770    // (provided the new state is different than the previous state).
771    // 
772    // If no arguments are passed, an empty state is created, which is just a
773    // shortcut for jQuery.bbq.pushState( {}, 2 ).
774    // 
775    // Usage:
776    // 
777    // > jQuery.bbq.pushState( [ params [, merge_mode ] ] );
778    // 
779    // Arguments:
780    // 
781    //  params - (String) A serialized params string or a hash string beginning
782    //    with # to merge into location.hash.
783    //  params - (Object) A params object to merge into location.hash.
784    //  merge_mode - (Number) Merge behavior defaults to 0 if merge_mode is not
785    //    specified (unless a hash string beginning with # is specified, in which
786    //    case merge behavior defaults to 2), and is as-follows:
787    // 
788    //    * 0: params in the params argument will override any params in the
789    //         current state.
790    //    * 1: any params in the current state will override params in the params
791    //         argument.
792    //    * 2: params argument will completely replace current state.
793    // 
794    // Returns:
795    // 
796    //  Nothing.
797    // 
798    // Additional Notes:
799    // 
800    //  * Setting an empty state may cause the browser to scroll.
801    //  * Unlike the fragment and querystring methods, if a hash string beginning
802    //    with # is specified as the params agrument, merge_mode defaults to 2.
803
804    jq_bbq.pushState = jq_bbq_pushState = function (params, merge_mode) {
805        if (is_string(params) && /^#/.test(params) && merge_mode === undefined) {
806            // Params string begins with # and merge_mode not specified, so completely
807            // overwrite window.location.hash.
808            merge_mode = 2;
809        }
810
811        var has_args = params !== undefined,
812            // Merge params into window.location using $.param.fragment.
813            url = jq_param_fragment(location.href,
814                has_args ? params : {}, has_args ? merge_mode : 2);
815
816        // Set new window.location.href. Note that Safari 3 & Chrome barf on
817        // location.hash = '#' so the entire URL is set.
818        location.href = url;
819    };
820
821    // Method: jQuery.bbq.getState
822    // 
823    // Retrieves the current 'state' from the browser history, parsing
824    // location.hash for a specific key or returning an object c
824ontaining the
825    // entire state, optionally coercing numbers, booleans, null and undefined
826    // values.
827    // 
828    // Usage:
829    // 
830    // > jQuery.bbq.getState( [ key ] [, coerce ] );
831    // 
832    // Arguments:
833    // 
834    //  key - (String) An optional state key for which to return a value.
835    //  coerce - (Boolean) If true, coerces any numbers or true, false, null, and
836    //    undefined to their actual value. Defaults to false.
837    // 
838    // Returns:
839    // 
840    //  (Anything) If key is passed, returns the value corresponding with that key
841    //    in the location.hash 'state', or undefined. If not, an object
842    //    representing the entire 'state' is returned.
843
844    jq_bbq.getState = jq_bbq_getState = function (key, coerce) {
845        return key === undefined || typeof key === 'boolean'
846            ? jq_deparam_fragment(key) // 'key' really means 'coerce' here
847            : jq_deparam_fragment(coerce)[key];
848    };
849
850    // Method: jQuery.bbq.removeState
851    // 
852    // Remove one or more keys from the current browser history 'state', creating
853    // a new state, setting location.hash and triggering any bound
854    // <hashchange event> callbacks (provided the new state is different than
855    // the previous state).
856    // 
857    // If no arguments are passed, an empty state is created, which is just a
858    // shortcut for jQuery.bbq.pushState( {}, 2 ).
859    // 
860    // Usage:
861    // 
862    // > jQuery.bbq.removeState( [ key [, key ... ] ] );
863    // 
864    // Arguments:
865    // 
866    //  key - (String) One or more key values to remove from the current state,
867    //    passed as individual arguments.
868    //  key - (Array) A single array argument that contains a list of key values
869    //    to remove from the current state.
870    // 
871    // Returns:
872    // 
873    //  Nothing.
874    // 
875    // Additional Notes:
876    // 
877    //  * Setting an empty state may cause the browser to scroll.
878
879    jq_bbq.removeState = function (arr) {
880        var state = {};
881
882        // If one or more arguments is passed..
883        if (arr !== undefined) {
884
885            // Get the current state.
886            state = jq_bbq_getState();
887
888            // For each passed key, delete the corresponding property from the current
889            // state.
890            $.each($.isArray(arr) ? arr : arguments, function (i, v) {
891                delete state[v];
892            });
893        }
894
895        // Set the state, completely overriding any existing state.
896        jq_bbq_pushState(state, 2);
897    };
898
899    // Event: hashchange event (BBQ)
900    // 
901    // Usage in jQuery 1.4 and newer:
902    // 
903    // In jQuery 1.4 and newer, the event object passed into any hashchange event
904    // callback is augmented with a copy of the location.hash fragment at the time
905    // the event was triggered as its event.fragment property. In addition, the
906    // event.getState method operates on this property (instead of location.hash)
907    // which allows this fragment-as-a-state to be referenced later, even after
908    // window.location may have changed.
909    // 
910    // Note that event.fragment and event.getState are not defined according to
911    // W3C (or any other) specification, but will still be available whether or
912    // not the hashchange event exists natively in the browser, because of the
913    // utility they provide.
914    // 
915    // The event.fragment property contains the output of <jQuery.param.fragment>
916    // and the event.getState method is equivalent to the <jQuery.bbq.getState>
917    // method.
918    // 
919    // > $(window).bind( 'hashchange', function( event ) {
920    // >   var hash_str = event.fragment,
921    // >     param_obj = event.getState(),
922    // >     param_val = event.getState( 'param_name' ),
923    // >     param_val_coerced = event.getState( 'param_name', true );
924    // >   ...
925    // > });
926    // 
927    // Usage in jQuery 1.3.2:
928    // 
929    // In jQuery 1.3.2, the event object cannot to be augmented as in jQuery 1.4+,
930    // so the fragment state isn't bound to the event object and must instead be
931    // parsed using the <jQuery.param.fragment> and <jQuery.bbq.getState> methods.
932    // 
933    // >
933 $(window).bind( 'hashchange', function( event ) {
934    // >   var hash_str = $.param.fragment(),
935    // >     param_obj = $.bbq.getState(),
936    // >     param_val = $.bbq.getState( 'param_name' ),
937    // >     param_val_coerced = $.bbq.getState( 'param_name', true );
938    // >   ...
939    // > });
940    // 
941    // Additional Notes:
942    // 
943    // * Due to changes in the special events API, jQuery BBQ v1.2 or newer is
944    //   required to enable the augmented event object in jQuery 1.4.2 and newer.
945    // * See <jQuery hashchange event> for more detailed information.
946
947    special[str_hashchange] = $.extend(special[str_hashchange], {
948
949        // Augmenting the event object with the .fragment property and .getState
950        // method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
951        // work, but the event won't be augmented)
952        add: function (handleObj) {
953            var old_handler;
954
955            function new_handler(e) {
956                // e.fragment is set to the value of location.hash (with any leading #
957                // removed) at the time the event is triggered.
958                var hash = e[str_fragment] = jq_param_fragment();
959
960                // e.getState() works just like $.bbq.getState(), but uses the
961                // e.fragment property stored on the event object.
962                e.getState = function (key, coerce) {
963                    return key === undefined || typeof key === 'boolean'
964                        ? jq_deparam(hash, key) // 'key' really means 'coerce' here
965                        : jq_deparam(hash, coerce)[key];
966                };
967
968                old_handler.apply(this, arguments);
969            };
970
971            // This may seem a little complicated, but it normalizes the special event
972            // .add method between jQuery 1.4/1.4.1 and 1.4.2+
973            if ($.isFunction(handleObj)) {
974                // 1.4, 1.4.1
975                old_handler = handleObj;
976                return new_handler;
977            } else {
978                // 1.4.2+
979                old_handler = handleObj.handler;
980                handleObj.handler = new_handler;
981            }
982        }
983
984    });
985
986})(jQuery, this);
987
988/*!
989 * jQuery hashchange event - v1.3 - 7/21/2010
990 * http://benalman.com/projects/jquery-hashchange-plugin/
991 * 
992 * Copyright (c) 2010 "Cowboy" Ben Alman
993 * Dual licensed under the MIT and GPL licenses.
994 * http://benalman.com/about/license/
995 */
996
997// Script: jQuery hashchange event
998//
999// *Version: 1.3, Last updated: 7/21/2010*
1000// 
1001// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
1002// GitHub       - http://github.com/cowboy/jquery-hashchange/
1003// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
1004// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
1005// 
1006// About: License
1007// 
1008// Copyright (c) 2010 "Cowboy" Ben Alman,
1009// Dual licensed under the MIT and GPL licenses.
1010// http://benalman.com/about/license/
1011// 
1012// About: Examples
1013// 
1014// These working examples, complete with fully commented code, illustrate a few
1015// ways in which this plugin can be used.
1016// 
1017// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
1018// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
1019// 
1020// About: Support and Testing
1021// 
1022// Information about what version or versions of jQuery this plugin has been
1023// tested with, what browsers it has been tested in, and where the unit tests
1024// reside (so you can test it yourself).
1025// 
1026// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
1027// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
1028//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
1029// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
1030// 
1031// About: Known issues
1032// 
1033// While this jQuery hashchange event implementation is quite stable and
1034// robust, there are a few unfortunate browser bugs surrounding expected
1035// hashchange event-based behaviors, independent of any JavaScript
1036// window.onhashchange abstraction. See the following examples for more
1037// information:
1038// 
1039// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
1040// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
1041// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
1042// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
1043// 
1044// Also note that should a browser natively support the window.onhashchange 
1045// event, but not report that it does, the fallback polling loop will be used.
1046// 
1047// About: Release History
1048// 
1049// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
1050//         "removable" for mobile-only development. Added IE6/7 document.title
1051//         support. Attempted to make Iframe as hidden as possible by using
1052//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
1053//         support for the "shortcut" format $(window).hashchange( fn ) and
1054//         $(window).hashchange() like jQuery provides for built-in events.
1055//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
1056//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
1057//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
1058//         file to address access denied issues when setting document.domain in
1059//         IE6/7.
1060// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
1061//         from a page on another domain would cause an error in Safari 4. Also,
1062//         IE6/7 Iframe is now inserted after the body (this actually works),
1063//         which prevents the page from scrolling when the event is first bound.
1064//         Event can also now be bound before DOM ready, but it won't be usable
1065//         before then in IE6/7.
1066// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
1067//         where browser version is incorrectly reported as 8.0, despite
1068//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
1069// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
1070//         window.onhashchange functionality into a separate plugin for users
1071//         who want just the basic event & back button support, without all the
1072//         extra awesomeness that BBQ provides. This plugin will be included as
1073//         part of jQuery BBQ, but also be available separately.
1074
1075(function ($, window, undefined) {
1076    '$:nomunge'; // Used by YUI compressor.
1077
1078    // Reused string.
1079    var str_hashchange = 'hashchange',
1080
1081        // Method / object references.
1082        doc = document,
1083        fake_onhashchange,
1084        special = $.event.special,
1085
1086        // Does the browser support window.onhashchange? Note that IE8 running in
1087        // IE7 compatibility mode reports true for 'onhashchange' in window, even
1088        // though the event isn't supported, so also test document.documentMode.
1089        doc_mode = doc.documentMode,
1090        supports_onhashchange = 'on' + str_hashchange in window && (doc_mode === undefined || doc_mode > 7);
1091
1092    // Get location.hash (or what you'd expect location.hash to be) sans any
1093    // leading #. Thanks for making this necessary, Firefox!
1094    function get_fragment(url) {
1095        url = url || location.href;
1096        return '#' + url.replace(/^[^#]*#?(.*)$/, '$1');
1097    };
1098
1099    // Method: jQuery.fn.hashchange
1100    // 
1101    // Bind a handler to the window.onhashchange event or trigger all bound
1102    // window.onhashchange event handlers. This behavior is consistent with
1103    // jQuery's built-in event handlers.
1104    // 
1105    // Usage:
1106    // 
1107    // > jQuery(window).hashchange( [ handler ] );
1108    // 
1109    // Arguments:
1110    // 
1111    //  handler - (Function) Optional handler to be bound to the hashchange
1112    //    event. This is a "shortcut" for the more verbose form:
1113    //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
1114    //    all bound window.onhashchange event handlers will be triggered. This
1115    //    is a shortcut for the more verbose
1116    //    jQuery(window).trigger( 'hashchange' ). These forms are described in
1117    //    the <hashchange event> section.
1118    // 
1119    // Returns:
1120    // 
1121    //  (jQuery) The initial jQuery collection of elements.
1122
1123    // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
1124    // $(elem).hashchange() for triggering, like jQuery does for built-in events.
1125    $.fn[str_hashchange] = function (fn) {
1126        return fn ? this.bind(str_hashchange, fn) : this.trigger(str_hashchange);
1127    };
1128
1129    // Property: jQuery.fn.hashchange.delay
1130    // 
1131    // The numeric interval (in milliseconds) at which the <hashchange event>
1132    // polling loop executes. Defaults to 50.
1133
1134    // Property: jQuery.fn.hashchange.domain
1135    // 
1136    // If you're setting document.domain in your JavaScript, and you want hash
1137    // history to work in IE6/7, not only must this property be set, but you must
1138    // also set document.domain BEFORE jQuery is loaded into the page. This
1139    // property is only applicable if you are supporting IE6/7 (or IE8 operating
1140    // in "IE7 compatibility" mode).
1141    // 
1142    // In addition, the <jQuery.fn.hashchange.src> property must be set to the
1143    // path of the included "document-domain.html" file, which can be renamed or
1144    // modified if necessary (note that the document.domain specified must be the
1145    // same in both your main JavaScript as well as in this file).
1146    // 
1147    // Usage:
1148    // 
1149    // jQuery.fn.hashchange.domain = document.domain;
1150
1151    // Property: jQuery.fn.hashchange.src
1152    // 
1153    // If, for some reason, you need to specify an Iframe src file (for example,
1154    // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
1155    // do so using this property. Note that when using this property, history
1156    // won't be recorded in IE6/7 until the Iframe src file loads. This property
1157    // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
1158    // compatibility" mode).
1159    // 
1160    // Usage:
1161    // 
1162    // jQuery.fn.hashchange.src = 'path/to/file.html';
1163
1164    $.fn[str_hashchange].delay = 50;
1165    /*
1166    $.fn[ str_hashchange ].domain = null;
1167    $.fn[ str_hashchange ].src = null;
1168    */
1169
1170    // Event: hashchange event
1171    // 
1172    // Fired when location.hash changes. In browsers that support it, the native
1173    // HTML5 window.onhashchange event is used, otherwise a polling loop is
1174    // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
1175    // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
1176    // compatibility" mode), a hidden Iframe is created to allow the back button
1177    // and hash-based history to work.
1178    // 
1179    // Usage as described in <jQuery.fn.hashchange>:
1180    // 
1181    // > // Bind an event handler.
1182    // > jQuery(window).hashchange( function(e) {
1183    // >   var hash = location.hash;
1184    // >   ...
1185    // > });
1186    // > 
1187    // > // Manually trigger the event handler.
1188    // > jQuery(window).hashchange();
1189    // 
1190    // A more verbose usage that allows for event namespacing:
1191    // 
1192    // > // Bind an event handler.
1193    // > jQuery(window).bind( 'hashchange', function(e) {
1194    // >   var hash = location.hash;
1195    // >   ...
1196    // > });
1197    // > 
1198    // > // Manually trigger the event handler.
1199    // > jQuery(window).trigger( 'hashchange' );
1200    // 
1201    // Additional Notes:
1202    // 
1203    // * The polling loop and Iframe are not created until at least one handler
1204    //   is actually bound to the 'hashchange' event.
1205    // * If you need the bound handler(s) to execute immediately, in cases where
1206    //   a location.hash exists on page load, via bookmark or page refresh for
1207    //   example, use jQuery(window).hashchange() or the more verbose 
1208    //   jQuery(window).trigger( 'hashchange' ).
1209    // * The event can be bound before DOM ready, but since it won't be usable
1210    //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
1211    //   to bind it inside a DOM ready handler.
1212
1213    // Override existing $.event.special.hashchange methods (allowing this plugin
1214    // to be defined after jQuery BBQ in BBQ's source code).
1215    special[str_hashchange] = $.extend(special[str_hashchange], {
1216
1217        // Called only when the first 'hashchange' event is bound to window.
1218        setup: function () {
1219            // If window.onhashchange is supported natively, there's nothing to do..
1220            if (supports_onhashchange) { return false; }
1221
1222            // Otherwise, we need to create our own. And we don't want to call this
1223            // until the user binds to the event, just in case they never do, since it
1224            // will create a polling loop and possibly even a hidden Iframe.
1225            $(fake_onhashchange.start);
1226        },
1227
1228        // Called only when the last 'hashchange' event is unbound from window.
1229        teardown: function () {
1230            // If window.onhashchange is supported natively, there's nothing to do..
1231            if (supports_onhashchange) { return false; }
1232
1233            // Otherwise, we need to stop ours (if possible).
1234            $(fake_onhashchange.stop);
1235        }
1236
1237    });
1238
1239    // fake_onhashchange does all the work of triggering the window.onhashchange
1240    // event for browsers that don't natively support it, including creating a
1241    // polling loop to watch for hash changes and in IE 6/7 creating a hidden
1242    // Iframe to enable back and forward.
1243    fake_onhashchange = (function () {
1244        var self = {},
1245            timeout_id,
1246
1247            // Remember the initial hash so it doesn't get triggered immediately.
1248            last_hash = get_fragment(),
1249
1250            fn_retval = function (val) { return val; },
1251            history_set = fn_retval,
1252            history_get = fn_retval;
1253
1254        // Start the polling loop.
1255        self.start = function () {
1256            timeout_id || poll();
1257        };
1258
1259        // Stop the polling loop.
1260        self.stop = function () {
1261            timeout_id && clearTimeout(timeout_id);
1262            timeout_id = undefined;
1263        };
1264
1265        // This polling loop checks every $.fn.hashchange.delay milliseconds to see
1266        // if location.hash has changed, and triggers the 'hashchange' event on
1267        // window when necessary.
1268        function poll() {
1269            var hash = get_fragment(),
1270                history_hash = history_get(last_hash);
1271
1272            if (hash !== last_hash) {
1273                history_set(last_hash = hash, history_hash);
1274
1275                $(window).trigger(str_hashchange);
1276
1277            } else if (history_hash !== last_hash) {
1278                location.href = location.href.replace(/#.*/, '') + history_hash;
1279            }
1280
1281            timeout_id = setTimeout(poll, $.fn[str_hashchange].delay);
1282        };
1283
1284        return self;
1285    })();
1286
1287})(jQuery, this);

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.