PageSourceSearch

https://dannybarnes.com/sites/default/files/advagg_js/js__efPyaa_4…Hqd-5bR7urtS1fVgGhD06DUpAUM2swu4UJURJ9cM.js

js dannybarnes.com collected 2026-09-26 11:16:51 UTC 35,290 bytes, 921 lines download raw bytes

1/* Source and licensing information for the line(s) below can be found at https://dannybarnes.com/misc/jquery-extend-3.4.0.js. */
2(function(e){var n=e.fn.jquery.split('.'),t=parseInt(n[0]),i=parseInt(n[1]),r=parseInt(n[2]),f=(r.toString()!==n[2]);if((t>3)||(t===3&&i>4)||(t===3&&i===4&&r>0)||(t===3&&i===4&&r===0&&!f)){return};e.extend=e.fn.extend=function(){var o,r,f,t,s,a,n=arguments[0]||{},i=1,l=arguments.length,u=!1;if(typeof n==='boolean'){u=n;n=arguments[i]||{};i++};if(typeof n!=='object'&&!e.isFunction(n)){n={}};if(i===l){n=this;i--};for(;i<l;i++){if((o=arguments[i])!=null){for(r in o){t=o[r];if(r==='__proto__'||n===t){continue};if(u&&t&&(e.isPlainObject(t)||(s=e.isArray(t)))){f=n[r];if(s&&!e.isArray(f)){a=[]}
3else if(!s&&!e.isPlainObject(f)){a={}}
4else{a=f};s=!1;n[r]=e.extend(u,a,t)}
5else if(t!==undefined){n[r]=t}}}};return n}})(jQuery);;
6/* Source and licensing information for the above line(s) can be found at https://dannybarnes.com/misc/jquery-extend-3.4.0.js. */
7;/*})'"*/
8/**
9 * For jQuery versions less than 3.5.0, this replaces the jQuery.htmlPrefilter()
10 * function with one that fixes these security vulnerabilities while also
11 * retaining the pre-3.5.0 behavior where it's safe to do so.
12 * - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-11022
13 * - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-11023
14 *
15 * Additionally, for jQuery versions that do not have a jQuery.htmlPrefilter()
16 * function (1.x prior to 1.12 and 2.x prior to 2.2), this adds it, and
17 * extends the functions that need to call it to do so.
18 *
19 * Drupal core's jQuery version is 1.4.4, but jQuery Update can provide a
20 * different version, so this covers all versions between 1.4.4 and 3.4.1.
21 * The GitHub links in the code comments below link to jQuery 1.5 code, because
22 * 1.4.4 isn't on GitHub, but the referenced code didn't change from 1.4.4 to
23 * 1.5.
24 */
25
26(function (jQuery) {
27
28  // Parts of this backport differ by jQuery version.
29  var versionParts = jQuery.fn.jquery.split('.');
30  var majorVersion = parseInt(versionParts[0]);
31  var minorVersion = parseInt(versionParts[1]);
32
33  // No backport is needed if we're already on jQuery 3.5 or higher.
34  if ( (majorVersion > 3) || (majorVersion === 3 && minorVersion >= 5) ) {
35    return;
36  }
37
38  // Prior to jQuery 3.5, jQuery converted XHTML-style self-closing tags to
39  // their XML equivalent: e.g., "<div />" to "<div></div>". This is
40  // problematic for several reasons, including that it's vulnerable to XSS
41  // attacks. However, since this was jQuery's behavior for many years, many
42  // Drupal modules and jQuery plugins may be relying on it. Therefore, we
43  // preserve that behavior, but for a limited set of tags only, that we believe
44  // to not be vulnerable. This is the set of HTML tags that satisfy all of the
45  // following conditions:
46  // - In DOMPurify's list of HTML tags. If an HTML tag isn't safe enough to
47  //   appear in that list, then we don't want to mess with it here either.
48  //   @see https://github.com/cure53/DOMPurify/blob/2.0.11/dist/purify.js#L128
49  // - A normal element (not a void, template, text, or foreign element).
50  //   @see https://html.spec.whatwg.org/multipage/syntax.html#elements-2
51  // - An element that is still defined by the current HTML specification
52  //   (not a deprecated element), because we do not want to rely on how
53  //   browsers parse deprecated elements.
54  //   @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element
55  // - Not 'html', 'head', or 'body', because this pseudo-XHTML expansion is
56  //   designed for fragments, not entire documents.
57  // - Not 'colgroup', because due to an idiosyncrasy of jQuery's original
58  //   regular expression, it didn't match on colgroup, and we don't want to
59  //   introduce a behavior change for that.
60  var selfClosingTagsToReplace = [
61    'a', 'abbr', 'address', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo',
62    'blockquote', 'button', 'canvas', 'caption', 'cite', 'code', 'data',
63    'datalist', 'dd', 'del', 'details', 'dfn', 'div', 'dl', 'dt', 'em',
64    'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
65    'h4', 'h5', 'h6', 'header', 'hgroup', 'i', 'ins', 'kbd', 'label', 'legend',
66    'li', 'main', 'map', 'mark', 'menu', 'meter', 'nav', 'ol', 'optgroup',
67    'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt',
68    'ruby', 's', 'samp', 'section', 'select', 'small', 'source', 'span',
69    'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'tfoot', 'th',
70    'thead', 'time', 'tr', 'u', 'ul', 'var', 'video'
71  ];
72
73  // Define regular expressions for <TAG/> and <TAG ATTRIBUTES/>. Doing this as
74  // two expressions makes it easier to target <a/> without also targeting
75  // every tag that starts with "a".
76  var xhtmlRegExpGroup = '(' + selfClosingTagsToReplace.join('|') + ')';
77  var whitespace = '[\\x20\\t\\r\\n\\f]';
78  var rxhtmlTagWithoutSpaceOrAttributes = new RegExp('<' + xhtmlRegExpGroup + '\\/>', 'gi');
79  var rxhtmlTagWithSpaceAndMaybeAttributes = new RegExp('<' + xhtmlRegExpGroup + '(' + whitespace + '[^>]*)\\/>', 'gi');
80
81  // jQuery 3.5 also fixed a vulnerability for when </select> appears within
82  // an <option> or <optgroup>, but it did that in local code that we can't
83  // backport directly. Instead, we filter such cases out. To do so, we need to
84  // determine when jQuery would otherwise invoke the vulnerable code, which it
85  // uses this regular expression to determine. The regular expression changed
86  // for version 3.0.0 and changed again for 3.4.0.
87  // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L4958
88  // @see https://github.com/jquery/jquery/blob/3.0.0/dist/jquery.js#L4584
89  // @see https://github.com/jquery/jquery/blob/3.4.0/dist/jquery.js#L4712
90  var rtagName;
91  if (majorVersion < 3) {
92    rtagName = /<([\w:]+)/;
93  }
94  else if (minorVersion < 4) {
95    rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i;
96  }
97  else {
98    rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]*)/i;
99  }
100
101  // The regular expression that jQuery uses to determine which self-closing
102  // tags to expand to open and close tags. This is vulnerable, because it
103  // matches all tag names except the few excluded ones. We only use this
104  // expression for determining vulnerability. The expression changed for
105  // version 3, but we only need to check for vulnerability in versions 1 and 2,
106  // so we use the expression from those versions.
107  // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L4957
108  var rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
109
110  jQuery.extend({
111    htmlPrefilter: function (html) {
112      // This is how jQuery determines the first tag in the HTML.
113      // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L5521
114      var tag = ( rtagName.exec( html ) || [ "", "" ] )[ 1 ].toLowerCase();
115
116      // It is not valid HTML for <option> or <optgroup> to have <select> as
117      // either a descendant or sibling, and attempts to inject one can cause
118      // XSS on jQuery versions before 3.5. Since this is invalid HTML and a
119      // possible XSS attack, reject the entire string.
120      // @see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-11023
121      if ((tag === 'option' || tag === 'optgroup') && html.match(/<\/?select/i)) {
122        html = '';
123      }
124
125      // Retain jQuery's prior to 3.5 conversion of pseudo-XHTML, but for only
126      // the tags in the `selfClosingTagsToReplace` list defined above.
127      // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L5518
128      // @see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-11022
129      html = html.replace(rxhtmlTagWithoutSpaceOrAttributes, "<$1></$1>");
130      html = html.replace(rxhtmlTagWithSpaceAndMaybeAttributes, "<$1$2></$1>");
131
132      // Prior to jQuery 1.12 and 2.2, this function gets called (via code later
133      // in this file) in addition to, rather than instead of, the unsafe
134      // expansion of self-closing tags (including ones not in the list above).
135      // We can't prevent that unsafe expansion from running, so instead we
136      // check to make sure that it doesn't affect the DOM returned by the
137      // browser's parsing logic. If it does affect it, then it's vulnerable to
138      // XSS, so we reject the entire string.
139      if ( (majorVersion === 1 && minorVersion < 12) || (majorVersion === 2 && minorVersion < 2) ) {
140        var htmlRisky = html.replace(rxhtmlTag, "<$1></$2>");
141        if (htmlRisky !== html) {
142          // Even though htmlRisky and html are different strings, they might
143          // represent the same HTML structure once parsed, in which case,
144          // htmlRisky is actually safe. We can ask the browser to parse both
145          // to find out, but the browser can't parse table fragments (e.g., a
146          // root-level "<td>"), so we need to wrap them. We just need this
147          // technique to work on all supported browsers; we don't need to
148          // copy from the specific jQuery version we're using.
149          // @see https://github.com/jquery/jquery/blob/3.5.1/dist/jquery.js#L4939
150          var wrapMap = {
151            thead: [ 1, "<table>", "</table>" ],
152            col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
153            tr: [ 2, "<table><tbody>", "</tbody></table>" ],
154            td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
155          };
156          wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
157          wrapMap.th = wrapMap.td;
158
159          // Function to wrap HTML into something that a browser can parse.
160          // @see https://github.com/jquery/jquery/blob/3.5.1/dist/jquery.js#L5032
161          var getWrappedHtml = function (html) {
162            var wrap = wrapMap[tag];
163            if (wrap) {
164              html = wrap[1] + html + wrap[2];
165            }
166            return html;
167          };
168
169          // Function to return canonical HTML after parsing it. This parses
170          // only; it doesn't execute scripts.
171          // @see https://github.com/jquery/jquery-migrate/blob/3.3.0/src/jquery/manipulation.js#L5
172          var getParsedHtml = function (html) {
173            var doc = window.document.implementation.createHTMLDocument( "" );
174            doc.body.innerHTML = html;
175            return doc.body ? doc.body.innerHTML : '';
176          };
177
178          // If the browser couldn't parse either one successfully, or if
179          // htmlRisky parses differently than html, then html is vulnerable,
180          // so reject it.
181          var htmlParsed = getParsedHtml(getWrappedHtml(html));
182          var htmlRiskyParsed = getParsedHtml(getWrappedHtml(htmlRisky));
183          if (htmlRiskyParsed === '' || htmlParsed === '' || (htmlRiskyParsed !== htmlParsed)) {
184            html = '';
185          }
186        }
187      }
188
189      return html;
190    }
191  });
192
193  // Prior to jQuery 1.12 and 2.2, jQuery.clean(), jQuery.buildFragment(), and
194  // jQuery.fn.html() did not call jQuery.htmlPrefilter(), so we add that.
195  if ( (majorVersion === 1 && minorVersion < 12) || (majorVersion === 2 && minorVersion < 2) ) {
196    // Filter the HTML coming into jQuery.fn.html().
197    var fnOriginalHtml = jQuery.fn.html;
198    jQuery.fn.extend({
199      // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L5147
200      html: function (value) {
201        if (typeof value === "string") {
202          value = jQuery.htmlPrefilter(value);
203        }
204        // .html() can be called as a setter (with an argument) or as a getter
205        // (without an argument), so invoke fnOriginalHtml() the same way that
206        // we were invoked.
207        return fnOriginalHtml.apply(this, arguments.length ? [value] : []);
208      }
209    });
210
211    // The regular expression that jQuery uses to determine if a string is HTML.
212    // Used by both clean() and buildFragment().
213    // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L4960
214    var rhtml = /<|&#?\w+;/;
215
216    // Filter HTML coming into:
217    // - jQuery.clean() for versions prior to 1.9.
218    // - jQuery.buildFragment() for 1.9 and above.
219    //
220    // The looping constructs in the two functions might be essentially
221    // identical, but they're each expressed here in the way that most closely
222    // matches their original expression in jQuery, so that we filter all of
223    // the items and only the items that jQuery will treat as HTML strings.
224    if (majorVersion === 1 && minorVersion < 9) {
225      var originalClean = jQuery.clean;
226      jQuery.extend({
227        // @see https://github.com/jquery/jquery/blob/1.5/jquery.js#L5493
228        'clean': function (elems, context, fragment, scripts) {
229          for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
230            if ( typeof elem === "string" && rhtml.test( elem ) ) {
231              elems[i] = elem = jQuery.htmlPrefilter(elem);
232            }
233          }
234          return originalClean.call(this, elems, context, fragment, scripts);
235        }
236      });
237    }
238    else {
239      var originalBuildFragment = jQuery.buildFragment;
240      jQuery.extend({
241        // @see https://github.com/jquery/jquery/blob/1.9.0/jquery.js#L6419
242        'buildFragment': function (elems, context, scripts, selection) {
243          var l = elems.length;
244          for ( var i = 0; i < l; i++ ) {
245            var elem = elems[i];
246            if (elem || elem === 0) {
247              if ( jQuery.type( elem ) !== "object" && rhtml.test( elem ) ) {
248                elems[i] = elem = jQuery.htmlPrefilter(elem);
249              }
250            }
251          }
252          return originalBuildFragment.call(this, elems, context, scripts, selection);
253        }
254      });
255    }
256  }
257
258})(jQuery);
259
260;/*})'"*/
261;/*})'"*/
262/* Source and licensing information for the line(s) below can be found at https://dannybarnes.com/misc/jquery.once.js. */
263(function(n){var e={},i=0;n.fn.once=function(r,o){if(typeof r!='string'){if(!(r in e)){e[r]=++i};if(!o){o=r};r='jquery-once-'+e[r]};var s=r+'-processed',t=this.not('.'+s).addClass(s);return n.isFunction(o)?t.each(o):t};n.fn.removeOnce=function(e,i){var r=e+'-processed',o=this.filter('.'+r).removeClass(r);return n.isFunction(i)?o.each(i):o}})(jQuery);;
264/* Source and licensing information for the above line(s) can be found at https://dannybarnes.com/misc/jquery.once.js. */
265;/*})'"*/
266
267var Drupal = Drupal || { 'settings': {}, 'behaviors': {}, 'locale': {} };
268
269// Allow other JavaScript libraries to use $.
270jQuery.noConflict();
271
272(function ($) {
273
274/**
275 * Override jQuery.fn.init to guard against XSS attacks.
276 *
277 * See http://bugs.jquery.com/ticket/9521
278 */
279var jquery_init = $.fn.init;
280$.fn.init = function (selector, context, rootjQuery) {
281  // If the string contains a "#" before a "<", treat it as invalid HTML.
282  if (selector && typeof selector === 'string') {
283    var hash_position = selector.indexOf('#');
284    if (hash_position >= 0) {
285      var bracket_position = selector.indexOf('<');
286      if (bracket_position > hash_position) {
287        throw 'Syntax error, unrecognized expression: ' + selector;
288      }
289    }
290  }
291  return jquery_init.call(this, selector, context, rootjQuery);
292};
293$.fn.init.prototype = jquery_init.prototype;
294
295/**
296 * Pre-filter Ajax requests to guard against XSS attacks.
297 *
298 * See https://github.com/jquery/jquery/issues/2432
299 */
300if ($.ajaxPrefilter) {
301  // For newer versions of jQuery, use an Ajax prefilter to prevent
302  // auto-executing script tags from untrusted domains. This is similar to the
303  // fix that is built in to jQuery 3.0 and higher.
304  $.ajaxPrefilter(function (s) {
305    if (s.crossDomain) {
306      s.contents.script = false;
307    }
308  });
309}
310else if ($.httpData) {
311  // For the version of jQuery that ships with Drupal core, override
312  // jQuery.httpData to prevent auto-detecting "script" data types from
313  // untrusted domains.
314  var jquery_httpData = $.httpData;
315  $.httpData = function (xhr, type, s) {
316    // @todo Consider backporting code from newer jQuery versions to check for
317    //   a cross-domain request here, rather than using Drupal.urlIsLocal() to
318    //   block scripts from all URLs that are not on the same site.
319    if (!type && !Drupal.urlIsLocal(s.url)) {
320      var content_type = xhr.getResponseHeader('content-type') || '';
321      if (content_type.indexOf('javascript') >= 0) {
322        // Default to a safe data type.
323        type = 'text';
324      }
325    }
326    return jquery_httpData.call(this, xhr, type, s);
327  };
328  $.httpData.prototype = jquery_httpData.prototype;
329}
330
331/**
332 * Attach all registered behaviors to a page element.
333 *
334 * Behaviors are event-triggered actions that attach to page elements, enhancing
335 * default non-JavaScript UIs. Behaviors are registered in the Drupal.behaviors
336 * object using the method 'attach' and optionally also 'detach' as follows:
337 * @code
338 *    Drupal.behaviors.behaviorName = {
339 *      attach: function (context, settings) {
340 *        ...
341 *      },
342 *      detach: function (context, settings, trigger) {
343 *        ...
344 *      }
345 *    };
346 * @endcode
347 *
348 * Drupal.attachBehaviors is added below to the jQuery ready event and so
349 * runs on initial page load. Developers implementing AHAH/Ajax in their
350 * solutions should also call this function after new page content has been
351 * loaded, feeding in an element to be processed, in order to attach all
352 * behaviors to the new content.
353 *
354 * Behaviors should use
355 * @code
356 *   $(selector).once('behavior-name', function () {
357 *     ...
358 *   });
359 * @endcode
360 * to ensure the behavior is attached only once to a given element. (Doing so
361 * enables the reprocessing of given elements, which may be needed on occasion
362 * despite the ability to limit behavior attachment to a particular element.)
363 *
364 * @param context
365 *   An element to attach behaviors to. If none is given, the document element
366 *   is used.
367 * @param settings
368 *   An object containing settings for the current context. If none given, the
369 *   global Drupal.settings object is used.
370 */
371Drupal.attachBehaviors = function (context, settings) {
372  context = context || document;
373  settings = settings || Drupal.settings;
374  // Execute all of them.
375  $.each(Drupal.behaviors, function () {
376    if ($.isFunction(this.attach)) {
377      this.attach(context, settings);
378    }
379  });
380};
381
382/**
383 * Detach registered behaviors from a page element.
384 *
385 * Developers implementing AHAH/Ajax in their solutions should call this
386 * function before page content is about to be removed, feeding in an element
387 * to be processed, in order to allow special behaviors to detach from the
388 * content.
389 *
390 * Such implementations should look for the class name that was added in their
391 * corresponding Drupal.behaviors.behaviorName.attach implementation, i.e.
392 * behaviorName-processed, to ensure the behavior is detached only from
393 * previously processed elements.
394 *
395 * @param context
396 *   An element to detach behaviors from. If none is given, the document element
397 *   is used.
398 * @param settings
399 *   An object containing settings for the current context. If none given, the
400 *   global Drupal.settings object is used.
401 * @param trigger
402 *   A string containing what's causing the behaviors to be detached. The
403 *   possible triggers are:
404 *   - unload: (default) The context element is being removed from the DOM.
405 *   - move: The element is about to be moved within the DOM (for example,
406 *     during a tabledrag row swap). After the move is completed,
407 *     Drupal.attachBehaviors() is called, so that the behavior can undo
408 *     whatever it did in response to the move. Many behaviors won't need to
409 *     do anything simply in response to the element being moved, but because
410 *     IFRAME elements reload their "src" when being moved within the DOM,
411 *     behaviors bound to IFRAME elements (like WYSIWYG editors) may need to
412 *     take some action.
413 *   - serialize: When an Ajax form is submitted, this is called with the
414 *     form as the context. This provides every behavior within the form an
415 *     opportunity to ensure that the field elements have correct content
416 *     in them before the form is serialized. The canonical use-case is so
417 *     that WYSIWYG editors can update the hidden textarea to which they are
418 *     bound.
419 *
420 * @see Drupal.attachBehaviors
421 */
422Drupal.detachBehaviors = function (context, settings, trigger) {
423  context = context || document;
424  settings = settings || Drupal.settings;
425  trigger = trigger || 'unload';
426  // Execute all of them.
427  $.each(Drupal.behaviors, function () {
428    if ($.isFunction(this.detach)) {
429      this.detach(context, settings, trigger);
430    }
431  });
432};
433
434/**
435 * Encode special characters in a plain-text string for display as HTML.
436 *
437 * @ingroup sanitization
438 */
439Drupal.checkPlain = function (str) {
440  var character, regex,
441      replace = { '&': '&amp;', "'": '&#39;', '"': '&quot;', '<': '&lt;', '>': '&gt;' };
442  str = String(str);
443  for (character in replace) {
444    if (replace.hasOwnProperty(character)) {
445      regex = new RegExp(character, 'g');
446      str = str.replace(regex, replace[character]);
447    }
448  }
449  return str;
450};
451
452/**
453 * Replace placeholders with sanitized values in a string.
454 *
455 * @param str
456 *   A string with placeholders.
457 * @param args
458 *   An object of replacements pairs to make. Incidences of any key in this
459 *   array are replaced with the corresponding value. Based on the first
460 *   character of the key, the value is escaped and/or themed:
461 *    - !variable: inserted as is
462 *    - @variable: escape plain text to HTML (Drupal.checkPlain)
463 *    - %variable: escape text and theme as a placeholder for user-submitted
464 *      content (checkPlain + Drupal.theme('placeholder'))
465 *
466 * @see Drupal.t()
467 * @ingroup sanitization
468 */
469Drupal.formatString = function(str, args) {
470  // Transform arguments before inserting them.
471  for (var key in args) {
472    if (args.hasOwnProperty(key)) {
473      switch (key.charAt(0)) {
474        // Escaped only.
475        case '@':
476          args[key] = Drupal.checkPlain(args[key]);
477          break;
478        // Pass-through.
479        case '!':
480          break;
481        // Escaped and placeholder.
482        default:
483          args[key] = Drupal.theme('placeholder', args[key]);
484          break;
485      }
486    }
487  }
488
489  return Drupal.stringReplace(str, args, null);
490};
491
492/**
493 * Replace substring.
494 *
495 * The longest keys will be tried first. Once a substring has been replaced,
496 * its new value will not be searched again.
497 *
498 * @param {String} str
499 *   A string with placeholders.
500 * @param {Object} args
501 *   Key-value pairs.
502 * @param {Array|null} keys
503 *   Array of keys from the "args".  Internal use only.
504 *
505 * @return {String}
506 *   Returns the replaced string.
507 */
508Drupal.stringReplace = function (str, args, keys) {
509  if (str.length === 0) {
510    return str;
511  }
512
513  // If the array of keys is not passed then collect the keys from the args.
514  if (!$.isArray(keys)) {
515    keys = [];
516    for (var k in args) {
517      if (args.hasOwnProperty(k)) {
518        keys.push(k);
519      }
520    }
521
522    // Order the keys by the character length. The shortest one is the first.
523    keys.sort(function (a, b) { return a.length - b.length; });
524  }
525
526  if (keys.length === 0) {
527    return str;
528  }
529
530  // Take next longest one from the end.
531  var key = keys.pop();
532  var fragments = str.split(key);
533
534  if (keys.length) {
535    for (var i = 0; i < fragments.length; i++) {
536      // Process each fragment with a copy of remaining keys.
537      fragments[i] = Drupal.stringReplace(fragments[i], args, keys.slice(0));
538    }
539  }
540
541  return fragments.join(args[key]);
542};
543
544/**
545 * Translate strings to the page language or a given language.
546 *
547 * See the documentation of the server-side t() function for further details.
548 *
549 * @param str
550 *   A string containing the English string to translate.
551 * @param args
552 *   An object of replacements pairs to make after translation. Incidences
553 *   of any key in this array are replaced with the corresponding value.
554 *   See Drupal.formatString().
555 *
556 * @param options
557 *   - 'context' (defaults to the empty context): The context the source string
558 *     belongs to.
559 *
560 * @return
561 *   The translated string.
562 */
563Drupal.t = function (str, args, options) {
564  options = options || {};
565  options.context = options.context || '';
566
567  // Fetch the localized version of the string.
568  if (Drupal.locale.strings && Drupal.locale.strings[options.context] && Drupal.locale.strings[options.context][str]) {
569    str = Drupal.locale.strings[options.context][str];
570  }
571
572  if (args) {
573    str = Drupal.formatString(str, args);
574  }
575  return str;
576};
577
578/**
579 * Format a string containing a count of items.
580 *
581 * This function ensures that the string is pluralized correctly. Since Drupal.t() is
582 * called by this function, make sure not to pass already-localized strings to it.
583 *
584 * See the documentation of the server-side format_plural() function for further details.
585 *
586 * @param count
587 *   The item count to display.
588 * @param singular
589 *   The string for the singular case. Please make sure it is clear this is
590 *   singular, to ease translation (e.g. use "1 new comment" instead of "1 new").
591 *   Do not use @count in the singular string.
592 * @param plural
593 *   The string for the plural case. Please make sure it is clear this is plural,
594 *   to ease translation. Use @count in place of the item count, as in "@count
595 *   new comments".
596 * @param args
597 *   An object of replacements pairs to make after translation. Incidences
598 *   of any key in this array are replaced with the corresponding value.
599 *   See Drupal.formatString().
600 *   Note that you do not need to include @count in this array.
601 *   This replacement is done automatically for the plural case.
602 * @param options
603 *   The options to pass to the Drupal.t() function.
604 * @return
605 *   A translated string.
606 */
607Drupal.formatPlural = function (count, singular, plural, args, options) {
608  args = args || {};
609  args['@count'] = count;
610  // Determine the index of the plural form.
611  var index = Drupal.locale.pluralFormula ? Drupal.locale.pluralFormula(args['@count']) : ((args['@count'] == 1) ? 0 : 1);
612
613  if (index == 0) {
614    return Drupal.t(singular, args, options);
615  }
616  else if (index == 1) {
617    return Drupal.t(plural, args, options);
618  }
619  else {
620    args['@count[' + index + ']'] = args['@count'];
621    delete args['@count'];
622    return Drupal.t(plural.replace('@count', '@count[' + index + ']'), args, options);
623  }
624};
625
626/**
627 * Returns the passed in URL as an absolute URL.
628 *
629 * @param url
630 *   The URL string to be normalized to an absolute URL.
631 *
632 * @return
633 *   The normalized, absolute URL.
634 *
635 * @see https://github.com/angular/angular.js/blob/v1.4.4/src/ng/urlUtils.js
636 * @see https://grack.com/blog/2009/11/17/absolutizing-url-in-javascript
637 * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L53
638 */
639Drupal.absoluteUrl = function (url) {
640  var urlParsingNode = document.createElement('a');
641
642  // Decode the URL first; this is required by IE <= 6. Decoding non-UTF-8
643  // strings may throw an exception.
644  try {
645    url = decodeURIComponent(url);
646  } catch (e) {}
647
648  urlParsingNode.setAttribute('href', url);
649
650  // IE <= 7 normalizes the URL when assigned to the anchor node similar to
651  // the other browsers.
652  return urlParsingNode.cloneNode(false).href;
653};
654
655/**
656 * Returns true if the URL is within Drupal's base path.
657 *
658 * @param url
659 *   The URL string to be tested.
660 *
661 * @return
662 *   Boolean true if local.
663 *
664 * @see https://github.com/jquery/jquery-ui/blob/1.11.4/ui/tabs.js#L58
665 */
666Drupal.urlIsLocal = function (url) {
667  // Always use browser-derived absolute URLs in the comparison, to avoid
668  // attempts to break out of the base path using directory traversal.
669  var absoluteUrl = Drupal.absoluteUrl(url);
670  var protocol = location.protocol;
671
672  // Consider URLs that match this site's base URL but use HTTPS instead of HTTP
673  // as local as well.
674  if (protocol === 'http:' && absoluteUrl.indexOf('https:') === 0) {
675    protocol = 'https:';
676  }
677  var baseUrl = protocol + '//' + location.host + Drupal.settings.basePath.slice(0, -1);
678
679  // Decoding non-UTF-8 strings may throw an exception.
680  try {
681    absoluteUrl = decodeURIComponent(absoluteUrl);
682  } catch (e) {}
683  try {
684    baseUrl = decodeURIComponent(baseUrl);
685  } catch (e) {}
686
687  // The given URL matches the site's base URL, or has a path under the site's
688  // base URL.
689  return absoluteUrl === baseUrl || absoluteUrl.indexOf(baseUrl + '/') === 0;
690};
691
692/**
693 * Sanitizes a URL for use with jQuery.ajax().
694 *
695 * @param url
696 *   The URL string to be sanitized.
697 *
698 * @return
699 *   The sanitized URL.
700 */
701Drupal.sanitizeAjaxUrl = function (url) {
702  var regex = /\=\?(&|$)/;
703  while (url.match(regex)) {
704    url = url.replace(regex, '');
705  }
706  return url;
707}
708
709/**
710 * Generate the themed representation of a Drupal object.
711 *
712 * All requests for themed output must go through this function. It examines
713 * the request and routes it to the appropriate theme function. If the current
714 * theme does not provide an override function, the generic theme function is
715 * called.
716 *
717 * For example, to retrieve the HTML for text that should be emphasized and
718 * displayed as a placeholder inside a sentence, call
719 * Drupal.theme('placeholder', text).
720 *
721 * @param func
722 *   The name of the theme function to call.
723 * @param ...
724 *   Additional arguments to pass along to the theme function.
725 * @return
726 *   Any data the theme function returns. This could be a plain HTML string,
727 *   but also a complex object.
728 */
729Drupal.theme = function (func) {
730  var args = Array.prototype.slice.apply(arguments, [1]);
731
732  return (Drupal.theme[func] || Drupal.theme.prototype[func]).apply(this, args);
733};
734
735/**
736 * Freeze the current body height (as minimum height). Used to prevent
737 * unnecessary upwards scrolling when doing DOM manipulations.
738 */
739Drupal.freezeHeight = function () {
740  Drupal.unfreezeHeight();
741  $('<div id="freeze-height"></div>').css({
742    position: 'absolute',
743    top: '0px',
744    left: '0px',
745    width: '1px',
746    height: $('body').css('height')
747  }).appendTo('body');
748};
749
750/**
751 * Unfreeze the body height.
752 */
753Drupal.unfreezeHeight = function () {
754  $('#freeze-height').remove();
755};
756
757/**
758 * Encodes a Drupal path for use in a URL.
759 *
760 * For aesthetic reasons slashes are not escaped.
761 */
762Drupal.encodePath = function (item, uri) {
763  uri = uri || location.href;
764  return encodeURIComponent(item).replace(/%2F/g, '/');
765};
766
767/**
768 * Get the text selection in a textarea.
769 */
770Drupal.getSelection = function (element) {
771  if (typeof element.selectionStart != 'number' && document.selection) {
772    // The current selection.
773    var range1 = document.selection.createRange();
774    var range2 = range1.duplicate();
775    // Select all text.
776    range2.moveToElementText(element);
777    // Now move 'dummy' end point to end point of original range.
778    range2.setEndPoint('EndToEnd', range1);
779    // Now we can calculate start and end points.
780    var start = range2.text.length - range1.text.length;
781    var end = start + range1.text.length;
782    return { 'start': start, 'end': end };
783  }
784  return { 'start': element.selectionStart, 'end': element.selectionEnd };
785};
786
787/**
788 * Add a global variable which determines if the window is being unloaded.
789 *
790 * This is primarily used by Drupal.displayAjaxError().
791 */
792Drupal.beforeUnloadCalled = false;
793$(window).bind('beforeunload pagehide', function () {
794    Drupal.beforeUnloadCalled = true;
795});
796
797/**
798 * Displays a JavaScript error from an Ajax response when appropriate to do so.
799 */
800Drupal.displayAjaxError = function (message) {
801  // Skip displaying the message if the user deliberately aborted (for example,
802  // by reloading the page or navigating to a different page) while the Ajax
803  // request was still ongoing. See, for example, the discussion at
804  // http://stackoverflow.com/questions/699941/handle-ajax-error-when-a-user-clicks-refresh.
805  if (!Drupal.beforeUnloadCalled) {
806    alert(message);
807  }
808};
809
810/**
811 * Build an error message from an Ajax response.
812 */
813Drupal.ajaxError = function (xmlhttp, uri, customMessage) {
814  var statusCode, statusText, pathText, responseText, readyStateText, message;
815  if (xmlhttp.status) {
816    statusCode = "\n" + Drupal.t("An AJAX HTTP error occurred.") +  "\n" + Drupal.t("HTTP Result Code: !status", {'!status': xmlhttp.status});
817  }
818  else {
819    statusCode = "\n" + Drupal.t("An AJAX HTTP request terminated abnormally.");
820  }
821  statusCode += "\n" + Drupal.t("Debugging information follows.");
822  pathText = "\n" + Drupal.t("Path: !uri", {'!uri': uri} );
823  statusText = '';
824  // In some cases, when statusCode == 0, xmlhttp.statusText may not be defined.
825  // Unfortunately, testing for it with typeof, etc, doesn't seem to catch that
826  // and the test causes an exception. So we need to catch the exception here.
827  try {
828    statusText = "\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)});
829  }
830  catch (e) {}
831
832  responseText = '';
833  // Again, we don't have a way to know for sure whether accessing
834  // xmlhttp.responseText is going to throw an exception. So we'll catch it.
835  try {
836    responseText = "\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText) } );
837  } catch (e) {}
838
839  // Make the responseText more readable by stripping HTML tags and newlines.
840  responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi,"");
841  responseText = responseText.replace(/[\n]+\s+/g,"\n");
842
843  // We don't need readyState except for status == 0.
844  readyStateText = xmlhttp.status == 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : "";
845
846  // Additional message beyond what the xmlhttp object provides.
847  customMessage = customMessage ? ("\n" + Drupal.t("CustomMessage: !customMessage", {'!customMessage': customMessage})) : "";
848
849  message = statusCode + pathText + statusText + customMessage + responseText + readyStateText;
850  return message;
851};
852
853// Class indicating that JS is enabled; used for styling purpose.
854$('html').addClass('js');
855
856$(function () {
857  if (Drupal.settings.setHasJsCookie === 1) {
858    // 'js enabled' cookie.
859    document.cookie = 'has_js=1; path=/; SameSite=Lax';
860  }
861});
862
863/**
864 * Additions to jQuery.support.
865 */
866$(function () {
867  /**
868   * Boolean indicating whether or not position:fixed is supported.
869   */
870  if (jQuery.support.positionFixed === undefined) {
871    var el = $('<div style="position:fixed; top:10px" />').appendTo(document.body);
872    jQuery.support.positionFixed = el[0].offsetTop === 10;
873    el.remove();
874  }
875});
876
877//Attach all behaviors.
878$(function () {
879  Drupal.attachBehaviors(document, Drupal.settings);
880});
881
882/**
883 * The default themes.
884 */
885Drupal.theme.prototype = {
886
887  /**
888   * Formats text for emphasized display in a placeholder inside a sentence.
889   *
890   * @param str
891   *   The text to format (plain-text).
892   * @return
893   *   The formatted text (html).
894   */
895  placeholder: function (str) {
896    return '<em class="placeholder">' + Drupal.checkPlain(str) + '</em>';
897  }
898};
899
900})(jQuery);
901
902;/*})'"*/
903;/*})'"*/
904/**
905 * Workaround for deprecated $.browser which was removed in jQuery 1.9
906 * @see https://api.jquery.com/jquery.browser/
907 */
908(function ($) {
909  if ($.browser===undefined) {
910    $.browser={};
911    $.browser.msie=false;
912    $.browser.version=0;
913    if (navigator.userAgent.match(/MSIE ([0-9]+)\./)) {
914      $.browser.msie=true;
915      $.browser.version=RegExp.$1;
916    }
917  }
918})(jQuery);
919
920;/*})'"*/
921;/*})'"*/

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.