Add datatables-1.9.4 and jquery-1.10.2 libraries
[proteocache.git] / webapp / resources / datatables-1.9.4 / examples / examples_support / syntax / js / shCore.js
1 // XRegExp 1.5.1
2 // (c) 2007-2012 Steven Levithan
3 // MIT License
4 // <http://xregexp.com>
5 // Provides an augmented, extensible, cross-browser implementation of regular expressions,
6 // including support for additional syntax, flags, and methods
7
8 var XRegExp;
9
10 if (XRegExp) {
11     // Avoid running twice, since that would break references to native globals
12     throw Error("can't load XRegExp twice in the same frame");
13 }
14
15 // Run within an anonymous function to protect variables and avoid new globals
16 (function (undefined) {
17
18     //---------------------------------
19     //  Constructor
20     //---------------------------------
21
22     // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
23     // regular expression in that additional syntax and flags are supported and cross-browser
24     // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
25     // converts to type XRegExp
26     XRegExp = function (pattern, flags) {
27         var output = [],
28             currScope = XRegExp.OUTSIDE_CLASS,
29             pos = 0,
30             context, tokenResult, match, chr, regex;
31
32         if (XRegExp.isRegExp(pattern)) {
33             if (flags !== undefined)
34                 throw TypeError("can't supply flags when constructing one RegExp from another");
35             return clone(pattern);
36         }
37         // Tokens become part of the regex construction process, so protect against infinite
38         // recursion when an XRegExp is constructed within a token handler or trigger
39         if (isInsideConstructor)
40             throw Error("can't call the XRegExp constructor within token definition functions");
41
42         flags = flags || "";
43         context = { // `this` object for custom tokens
44             hasNamedCapture: false,
45             captureNames: [],
46             hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
47             setFlag: function (flag) {flags += flag;}
48         };
49
50         while (pos < pattern.length) {
51             // Check for custom tokens at the current position
52             tokenResult = runTokens(pattern, pos, currScope, context);
53
54             if (tokenResult) {
55                 output.push(tokenResult.output);
56                 pos += (tokenResult.match[0].length || 1);
57             } else {
58                 // Check for native multicharacter metasequences (excluding character classes) at
59                 // the current position
60                 if (match = nativ.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
61                     output.push(match[0]);
62                     pos += match[0].length;
63                 } else {
64                     chr = pattern.charAt(pos);
65                     if (chr === "[")
66                         currScope = XRegExp.INSIDE_CLASS;
67                     else if (chr === "]")
68                         currScope = XRegExp.OUTSIDE_CLASS;
69                     // Advance position one character
70                     output.push(chr);
71                     pos++;
72                 }
73             }
74         }
75
76         regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, ""));
77         regex._xregexp = {
78             source: pattern,
79             captureNames: context.hasNamedCapture ? context.captureNames : null
80         };
81         return regex;
82     };
83
84
85     //---------------------------------
86     //  Public properties
87     //---------------------------------
88
89     XRegExp.version = "1.5.1";
90
91     // Token scope bitflags
92     XRegExp.INSIDE_CLASS = 1;
93     XRegExp.OUTSIDE_CLASS = 2;
94
95
96     //---------------------------------
97     //  Private variables
98     //---------------------------------
99
100     var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
101         flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
102         quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
103         isInsideConstructor = false,
104         tokens = [],
105         // Copy native globals for reference ("native" is an ES3 reserved keyword)
106         nativ = {
107             exec: RegExp.prototype.exec,
108             test: RegExp.prototype.test,
109             match: String.prototype.match,
110             replace: String.prototype.replace,
111             split: String.prototype.split
112         },
113         compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
114         compliantLastIndexIncrement = function () {
115             var x = /^/g;
116             nativ.test.call(x, "");
117             return !x.lastIndex;
118         }(),
119         hasNativeY = RegExp.prototype.sticky !== undefined,
120         nativeTokens = {};
121
122     // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
123     // excluding character classes)
124     nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/;
125     nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/;
126
127
128     //---------------------------------
129     //  Public methods
130     //---------------------------------
131
132     // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
133     // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
134     // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
135     // be disabled by `XRegExp.freezeTokens`
136     XRegExp.addToken = function (regex, handler, scope, trigger) {
137         tokens.push({
138             pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
139             handler: handler,
140             scope: scope || XRegExp.OUTSIDE_CLASS,
141             trigger: trigger || null
142         });
143     };
144
145     // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
146     // combination has previously been cached, the cached copy is returned; otherwise the newly
147     // created regex is cached
148     XRegExp.cache = function (pattern, flags) {
149         var key = pattern + "/" + (flags || "");
150         return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
151     };
152
153     // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
154     // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
155     // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
156     // special properties required for named capture
157     XRegExp.copyAsGlobal = function (regex) {
158         return clone(regex, "g");
159     };
160
161     // Accepts a string; returns the string with regex metacharacters escaped. The returned string
162     // can safely be used at any point within a regex to match the provided literal string. Escaped
163     // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
164     XRegExp.escape = function (str) {
165         return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
166     };
167
168     // Accepts a string to search, regex to search with, position to start the search within the
169     // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
170     // after the position or at the specified position only. This function ignores the `lastIndex`
171     // of the provided regex in its own handling, but updates the property for compatibility
172     XRegExp.execAt = function (str, regex, pos, anchored) {
173         var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")),
174             match;
175         r2.lastIndex = pos = pos || 0;
176         match = r2.exec(str); // Run the altered `exec` (required for `lastIndex` fix, etc.)
177         if (anchored && match && match.index !== pos)
178             match = null;
179         if (regex.global)
180             regex.lastIndex = match ? r2.lastIndex : 0;
181         return match;
182     };
183
184     // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
185     // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
186     XRegExp.freezeTokens = function () {
187         XRegExp.addToken = function () {
188             throw Error("can't run addToken after freezeTokens");
189         };
190     };
191
192     // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
193     // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
194     // constructor. This works correctly for variables created in another frame, when `instanceof`
195     // and `constructor` checks would fail to work as intended
196     XRegExp.isRegExp = function (o) {
197         return Object.prototype.toString.call(o) === "[object RegExp]";
198     };
199
200     // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
201     // iterate over regex matches compared to the traditional approaches of subverting
202     // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
203     XRegExp.iterate = function (str, regex, callback, context) {
204         var r2 = clone(regex, "g"),
205             i = -1, match;
206         while (match = r2.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
207             if (regex.global)
208                 regex.lastIndex = r2.lastIndex; // Doing this to follow expectations if `lastIndex` is checked within `callback`
209             callback.call(context, match, ++i, str, regex);
210             if (r2.lastIndex === match.index)
211                 r2.lastIndex++;
212         }
213         if (regex.global)
214             regex.lastIndex = 0;
215     };
216
217     // Accepts a string and an array of regexes; returns the result of using each successive regex
218     // to search within the matches of the previous regex. The array of regexes can also contain
219     // objects with `regex` and `backref` properties, in which case the named or numbered back-
220     // references specified are passed forward to the next regex or returned. E.g.:
221     // var xregexpImgFileNames = XRegExp.matchChain(html, [
222     //     {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
223     //     {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
224     //     {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
225     //     /[^\/]+$/ // filenames (strip directory paths)
226     // ]);
227     XRegExp.matchChain = function (str, chain) {
228         return function recurseChain (values, level) {
229             var item = chain[level].regex ? chain[level] : {regex: chain[level]},
230                 regex = clone(item.regex, "g"),
231                 matches = [], i;
232             for (i = 0; i < values.length; i++) {
233                 XRegExp.iterate(values[i], regex, function (match) {
234                     matches.push(item.backref ? (match[item.backref] || "") : match[0]);
235                 });
236             }
237             return ((level === chain.length - 1) || !matches.length) ?
238                 matches : recurseChain(matches, level + 1);
239         }([str], 0);
240     };
241
242
243     //---------------------------------
244     //  New RegExp prototype methods
245     //---------------------------------
246
247     // Accepts a context object and arguments array; returns the result of calling `exec` with the
248     // first value in the arguments array. the context is ignored but is accepted for congruity
249     // with `Function.prototype.apply`
250     RegExp.prototype.apply = function (context, args) {
251         return this.exec(args[0]);
252     };
253
254     // Accepts a context object and string; returns the result of calling `exec` with the provided
255     // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
256     RegExp.prototype.call = function (context, str) {
257         return this.exec(str);
258     };
259
260
261     //---------------------------------
262     //  Overriden native methods
263     //---------------------------------
264
265     // Adds named capture support (with backreferences returned as `result.name`), and fixes two
266     // cross-browser issues per ES3:
267     // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
268     //   rather than the empty string.
269     // - `lastIndex` should not be incremented after zero-length matches.
270     RegExp.prototype.exec = function (str) {
271         var match, name, r2, origLastIndex;
272         if (!this.global)
273             origLastIndex = this.lastIndex;
274         match = nativ.exec.apply(this, arguments);
275         if (match) {
276             // Fix browsers whose `exec` methods don't consistently return `undefined` for
277             // nonparticipating capturing groups
278             if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
279                 r2 = RegExp(this.source, nativ.replace.call(getNativeFlags(this), "g", ""));
280                 // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
281                 // matching due to characters outside the match
282                 nativ.replace.call((str + "").slice(match.index), r2, function () {
283                     for (var i = 1; i < arguments.length - 2; i++) {
284                         if (arguments[i] === undefined)
285                             match[i] = undefined;
286                     }
287                 });
288             }
289             // Attach named capture properties
290             if (this._xregexp && this._xregexp.captureNames) {
291                 for (var i = 1; i < match.length; i++) {
292                     name = this._xregexp.captureNames[i - 1];
293                     if (name)
294                        match[name] = match[i];
295                 }
296             }
297             // Fix browsers that increment `lastIndex` after zero-length matches
298             if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
299                 this.lastIndex--;
300         }
301         if (!this.global)
302             this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
303         return match;
304     };
305
306     // Fix browser bugs in native method
307     RegExp.prototype.test = function (str) {
308         // Use the native `exec` to skip some processing overhead, even though the altered
309         // `exec` would take care of the `lastIndex` fixes
310         var match, origLastIndex;
311         if (!this.global)
312             origLastIndex = this.lastIndex;
313         match = nativ.exec.call(this, str);
314         // Fix browsers that increment `lastIndex` after zero-length matches
315         if (match && !compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
316             this.lastIndex--;
317         if (!this.global)
318             this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
319         return !!match;
320     };
321
322     // Adds named capture support and fixes browser bugs in native method
323     String.prototype.match = function (regex) {
324         if (!XRegExp.isRegExp(regex))
325             regex = RegExp(regex); // Native `RegExp`
326         if (regex.global) {
327             var result = nativ.match.apply(this, arguments);
328             regex.lastIndex = 0; // Fix IE bug
329             return result;
330         }
331         return regex.exec(this); // Run the altered `exec`
332     };
333
334     // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
335     // and provides named backreferences to replacement functions as `arguments[0].name`. Also
336     // fixes cross-browser differences in replacement text syntax when performing a replacement
337     // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
338     // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
339     // third (`flags`) parameter
340     String.prototype.replace = function (search, replacement) {
341         var isRegex = XRegExp.isRegExp(search),
342             captureNames, result, str, origLastIndex;
343
344         // There are too many combinations of search/replacement types/values and browser bugs that
345         // preclude passing to native `replace`, so don't try
346         //if (...)
347         //    return nativ.replace.apply(this, arguments);
348
349         if (isRegex) {
350             if (search._xregexp)
351                 captureNames = search._xregexp.captureNames; // Array or `null`
352             if (!search.global)
353                 origLastIndex = search.lastIndex;
354         } else {
355             search = search + ""; // Type conversion
356         }
357
358         if (Object.prototype.toString.call(replacement) === "[object Function]") {
359             result = nativ.replace.call(this + "", search, function () {
360                 if (captureNames) {
361                     // Change the `arguments[0]` string primitive to a String object which can store properties
362                     arguments[0] = new String(arguments[0]);
363                     // Store named backreferences on `arguments[0]`
364                     for (var i = 0; i < captureNames.length; i++) {
365                         if (captureNames[i])
366                             arguments[0][captureNames[i]] = arguments[i + 1];
367                     }
368                 }
369                 // Update `lastIndex` before calling `replacement` (fix browsers)
370                 if (isRegex && search.global)
371                     search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
372                 return replacement.apply(null, arguments);
373             });
374         } else {
375             str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
376             result = nativ.replace.call(str, search, function () {
377                 var args = arguments; // Keep this function's `arguments` available through closure
378                 return nativ.replace.call(replacement + "", replacementToken, function ($0, $1, $2) {
379                     // Numbered backreference (without delimiters) or special variable
380                     if ($1) {
381                         switch ($1) {
382                             case "$": return "$";
383                             case "&": return args[0];
384                             case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
385                             case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
386                             // Numbered backreference
387                             default:
388                                 // What does "$10" mean?
389                                 // - Backreference 10, if 10 or more capturing groups exist
390                                 // - Backreference 1 followed by "0", if 1-9 capturing groups exist
391                                 // - Otherwise, it's the string "$10"
392                                 // Also note:
393                                 // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
394                                 // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
395                                 // - There is no "$0" token ("$&" is the entire match)
396                                 var literalNumbers = "";
397                                 $1 = +$1; // Type conversion; drop leading zero
398                                 if (!$1) // `$1` was "0" or "00"
399                                     return $0;
400                                 while ($1 > args.length - 3) {
401                                     literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
402                                     $1 = Math.floor($1 / 10); // Drop the last digit
403                                 }
404                                 return ($1 ? args[$1] || "" : "$") + literalNumbers;
405                         }
406                     // Named backreference or delimited numbered backreference
407                     } else {
408                         // What does "${n}" mean?
409                         // - Backreference to numbered capture n. Two differences from "$n":
410                         //   - n can be more than two digits
411                         //   - Backreference 0 is allowed, and is the entire match
412                         // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
413                         // - Otherwise, it's the string "${n}"
414                         var n = +$2; // Type conversion; drop leading zeros
415                         if (n <= args.length - 3)
416                             return args[n];
417                         n = captureNames ? indexOf(captureNames, $2) : -1;
418                         return n > -1 ? args[n + 1] : $0;
419                     }
420                 });
421             });
422         }
423
424         if (isRegex) {
425             if (search.global)
426                 search.lastIndex = 0; // Fix IE, Safari bug (last tested IE 9.0.5, Safari 5.1.2 on Windows)
427             else
428                 search.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
429         }
430
431         return result;
432     };
433
434     // A consistent cross-browser, ES3 compliant `split`
435     String.prototype.split = function (s /* separator */, limit) {
436         // If separator `s` is not a regex, use the native `split`
437         if (!XRegExp.isRegExp(s))
438             return nativ.split.apply(this, arguments);
439
440         var str = this + "", // Type conversion
441             output = [],
442             lastLastIndex = 0,
443             match, lastLength;
444
445         // Behavior for `limit`: if it's...
446         // - `undefined`: No limit
447         // - `NaN` or zero: Return an empty array
448         // - A positive number: Use `Math.floor(limit)`
449         // - A negative number: No limit
450         // - Other: Type-convert, then use the above rules
451         if (limit === undefined || +limit < 0) {
452             limit = Infinity;
453         } else {
454             limit = Math.floor(+limit);
455             if (!limit)
456                 return [];
457         }
458
459         // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
460         // and restore it to its original value when we're done using the regex
461         s = XRegExp.copyAsGlobal(s);
462
463         while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
464             if (s.lastIndex > lastLastIndex) {
465                 output.push(str.slice(lastLastIndex, match.index));
466
467                 if (match.length > 1 && match.index < str.length)
468                     Array.prototype.push.apply(output, match.slice(1));
469
470                 lastLength = match[0].length;
471                 lastLastIndex = s.lastIndex;
472
473                 if (output.length >= limit)
474                     break;
475             }
476
477             if (s.lastIndex === match.index)
478                 s.lastIndex++;
479         }
480
481         if (lastLastIndex === str.length) {
482             if (!nativ.test.call(s, "") || lastLength)
483                 output.push("");
484         } else {
485             output.push(str.slice(lastLastIndex));
486         }
487
488         return output.length > limit ? output.slice(0, limit) : output;
489     };
490
491
492     //---------------------------------
493     //  Private helper functions
494     //---------------------------------
495
496     // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
497     // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
498     // capture. Also allows adding new flags in the process of copying the regex
499     function clone (regex, additionalFlags) {
500         if (!XRegExp.isRegExp(regex))
501             throw TypeError("type RegExp expected");
502         var x = regex._xregexp;
503         regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
504         if (x) {
505             regex._xregexp = {
506                 source: x.source,
507                 captureNames: x.captureNames ? x.captureNames.slice(0) : null
508             };
509         }
510         return regex;
511     }
512
513     function getNativeFlags (regex) {
514         return (regex.global     ? "g" : "") +
515                (regex.ignoreCase ? "i" : "") +
516                (regex.multiline  ? "m" : "") +
517                (regex.extended   ? "x" : "") + // Proposed for ES4; included in AS3
518                (regex.sticky     ? "y" : "");
519     }
520
521     function runTokens (pattern, index, scope, context) {
522         var i = tokens.length,
523             result, match, t;
524         // Protect against constructing XRegExps within token handler and trigger functions
525         isInsideConstructor = true;
526         // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
527         try {
528             while (i--) { // Run in reverse order
529                 t = tokens[i];
530                 if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
531                     t.pattern.lastIndex = index;
532                     match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
533                     if (match && match.index === index) {
534                         result = {
535                             output: t.handler.call(context, match, scope),
536                             match: match
537                         };
538                         break;
539                     }
540                 }
541             }
542         } catch (err) {
543             throw err;
544         } finally {
545             isInsideConstructor = false;
546         }
547         return result;
548     }
549
550     function indexOf (array, item, from) {
551         if (Array.prototype.indexOf) // Use the native array method if available
552             return array.indexOf(item, from);
553         for (var i = from || 0; i < array.length; i++) {
554             if (array[i] === item)
555                 return i;
556         }
557         return -1;
558     }
559
560
561     //---------------------------------
562     //  Built-in tokens
563     //---------------------------------
564
565     // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
566     // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`
567
568     // Comment pattern: (?# )
569     XRegExp.addToken(
570         /\(\?#[^)]*\)/,
571         function (match) {
572             // Keep tokens separated unless the following token is a quantifier
573             return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
574         }
575     );
576
577     // Capturing group (match the opening parenthesis only).
578     // Required for support of named capturing groups
579     XRegExp.addToken(
580         /\((?!\?)/,
581         function () {
582             this.captureNames.push(null);
583             return "(";
584         }
585     );
586
587     // Named capturing group (match the opening delimiter only): (?<name>
588     XRegExp.addToken(
589         /\(\?<([$\w]+)>/,
590         function (match) {
591             this.captureNames.push(match[1]);
592             this.hasNamedCapture = true;
593             return "(";
594         }
595     );
596
597     // Named backreference: \k<name>
598     XRegExp.addToken(
599         /\\k<([\w$]+)>/,
600         function (match) {
601             var index = indexOf(this.captureNames, match[1]);
602             // Keep backreferences separate from subsequent literal numbers. Preserve back-
603             // references to named groups that are undefined at this point as literal strings
604             return index > -1 ?
605                 "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
606                 match[0];
607         }
608     );
609
610     // Empty character class: [] or [^]
611     XRegExp.addToken(
612         /\[\^?]/,
613         function (match) {
614             // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
615             // (?!) should work like \b\B, but is unreliable in Firefox
616             return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
617         }
618     );
619
620     // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
621     // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
622     XRegExp.addToken(
623         /^\(\?([imsx]+)\)/,
624         function (match) {
625             this.setFlag(match[1]);
626             return "";
627         }
628     );
629
630     // Whitespace and comments, in free-spacing (aka extended) mode only
631     XRegExp.addToken(
632         /(?:\s+|#.*)+/,
633         function (match) {
634             // Keep tokens separated unless the following token is a quantifier
635             return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
636         },
637         XRegExp.OUTSIDE_CLASS,
638         function () {return this.hasFlag("x");}
639     );
640
641     // Dot, in dotall (aka singleline) mode only
642     XRegExp.addToken(
643         /\./,
644         function () {return "[\\s\\S]";},
645         XRegExp.OUTSIDE_CLASS,
646         function () {return this.hasFlag("s");}
647     );
648
649
650     //---------------------------------
651     //  Backward compatibility
652     //---------------------------------
653
654     // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
655     /*
656     XRegExp.matchWithinChain = XRegExp.matchChain;
657     RegExp.prototype.addFlags = function (s) {return clone(this, s);};
658     RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
659     RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
660     RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
661     */
662
663 })();
664
665 //
666 // Begin anonymous function. This is used to contain local scope variables without polutting global scope.
667 //
668 if (typeof(SyntaxHighlighter) == 'undefined') var SyntaxHighlighter = function() { 
669
670 // CommonJS
671 if (typeof(require) != 'undefined' && typeof(XRegExp) == 'undefined')
672 {
673         XRegExp = require('XRegExp').XRegExp;
674 }
675
676 // Shortcut object which will be assigned to the SyntaxHighlighter variable.
677 // This is a shorthand for local reference in order to avoid long namespace 
678 // references to SyntaxHighlighter.whatever...
679 var sh = {
680         defaults : {
681                 /** Additional CSS class names to be added to highlighter elements. */
682                 'class-name' : '',
683                 
684                 /** First line number. */
685                 'first-line' : 1,
686                 
687                 /**
688                  * Pads line numbers. Possible values are:
689                  *
690                  *   false - don't pad line numbers.
691                  *   true  - automaticaly pad numbers with minimum required number of leading zeroes.
692                  *   [int] - length up to which pad line numbers.
693                  */
694                 'pad-line-numbers' : false,
695                 
696                 /** Lines to highlight. */
697                 'highlight' : null,
698                 
699                 /** Title to be displayed above the code block. */
700                 'title' : null,
701                 
702                 /** Enables or disables smart tabs. */
703                 'smart-tabs' : true,
704                 
705                 /** Gets or sets tab size. */
706                 'tab-size' : 4,
707                 
708                 /** Enables or disables gutter. */
709                 'gutter' : true,
710                 
711                 /** Enables or disables toolbar. */
712                 'toolbar' : true,
713                 
714                 /** Enables quick code copy and paste from double click. */
715                 'quick-code' : true,
716                 
717                 /** Forces code view to be collapsed. */
718                 'collapse' : false,
719                 
720                 /** Enables or disables automatic links. */
721                 'auto-links' : true,
722                 
723                 /** Gets or sets light mode. Equavalent to turning off gutter and toolbar. */
724                 'light' : false,
725
726                 'unindent' : true,
727                 
728                 'html-script' : false
729         },
730         
731         config : {
732                 space : '&nbsp;',
733                 
734                 /** Enables use of <SCRIPT type="syntaxhighlighter" /> tags. */
735                 useScriptTags : true,
736                 
737                 /** Blogger mode flag. */
738                 bloggerMode : false,
739                 
740                 stripBrs : false,
741                 
742                 /** Name of the tag that SyntaxHighlighter will automatically look for. */
743                 tagName : 'pre',
744                 
745                 strings : {
746                         expandSource : 'expand source',
747                         help : '?',
748                         alert: 'SyntaxHighlighter\n\n',
749                         noBrush : 'Can\'t find brush for: ',
750                         brushNotHtmlScript : 'Brush wasn\'t configured for html-script option: ',
751                         
752                         // this is populated by the build script
753                         aboutDialog : '@ABOUT@'
754                 }
755         },
756         
757         /** Internal 'global' variables. */
758         vars : {
759                 discoveredBrushes : null,
760                 highlighters : {}
761         },
762         
763         /** This object is populated by user included external brush files. */
764         brushes : {},
765
766         /** Common regular expressions. */
767         regexLib : {
768                 multiLineCComments                      : /\/\*[\s\S]*?\*\//gm,
769                 singleLineCComments                     : /\/\/.*$/gm,
770                 singleLinePerlComments          : /#.*$/gm,
771                 doubleQuotedString                      : /"([^\\"\n]|\\.)*"/g,
772                 singleQuotedString                      : /'([^\\'\n]|\\.)*'/g,
773                 multiLineDoubleQuotedString     : new XRegExp('"([^\\\\"]|\\\\.)*"', 'gs'),
774                 multiLineSingleQuotedString     : new XRegExp("'([^\\\\']|\\\\.)*'", 'gs'),
775                 xmlComments                                     : /(&lt;|<)!--[\s\S]*?--(&gt;|>)/gm,
776                 url                                                     : /\w+:\/\/[\w-.\/?%&=:@;#]*/g,
777                 
778                 /** <?= ?> tags. */
779                 phpScriptTags                           : { left: /(&lt;|<)\?(?:=|php)?/g, right: /\?(&gt;|>)/g, 'eof' : true },
780                 
781                 /** <%= %> tags. */
782                 aspScriptTags                           : { left: /(&lt;|<)%=?/g, right: /%(&gt;|>)/g },
783                 
784                 /** <script> tags. */
785                 scriptScriptTags                        : { left: /(&lt;|<)\s*script.*?(&gt;|>)/gi, right: /(&lt;|<)\/\s*script\s*(&gt;|>)/gi }
786         },
787
788         toolbar: {
789                 /**
790                  * Generates HTML markup for the toolbar.
791                  * @param {Highlighter} highlighter Highlighter instance.
792                  * @return {String} Returns HTML markup.
793                  */
794                 getHtml: function(highlighter)
795                 {
796                         var html = '<div class="toolbar">',
797                                 items = sh.toolbar.items,
798                                 list = items.list
799                                 ;
800                         
801                         function defaultGetHtml(highlighter, name)
802                         {
803                                 return sh.toolbar.getButtonHtml(highlighter, name, sh.config.strings[name]);
804                         };
805                         
806                         for (var i = 0; i < list.length; i++)
807                                 html += (items[list[i]].getHtml || defaultGetHtml)(highlighter, list[i]);
808                         
809                         html += '</div>';
810                         
811                         return html;
812                 },
813                 
814                 /**
815                  * Generates HTML markup for a regular button in the toolbar.
816                  * @param {Highlighter} highlighter Highlighter instance.
817                  * @param {String} commandName          Command name that would be executed.
818                  * @param {String} label                        Label text to display.
819                  * @return {String}                                     Returns HTML markup.
820                  */
821                 getButtonHtml: function(highlighter, commandName, label)
822                 {
823                         return '<span><a href="#" class="toolbar_item'
824                                 + ' command_' + commandName
825                                 + ' ' + commandName
826                                 + '">' + label + '</a></span>'
827                                 ;
828                 },
829                 
830                 /**
831                  * Event handler for a toolbar anchor.
832                  */
833                 handler: function(e)
834                 {
835                         var target = e.target,
836                                 className = target.className || ''
837                                 ;
838
839                         function getValue(name)
840                         {
841                                 var r = new RegExp(name + '_(\\w+)'),
842                                         match = r.exec(className)
843                                         ;
844
845                                 return match ? match[1] : null;
846                         };
847                         
848                         var highlighter = getHighlighterById(findParentElement(target, '.syntaxhighlighter').id),
849                                 commandName = getValue('command')
850                                 ;
851                         
852                         // execute the toolbar command
853                         if (highlighter && commandName)
854                                 sh.toolbar.items[commandName].execute(highlighter);
855
856                         // disable default A click behaviour
857                         e.preventDefault();
858                 },
859                 
860                 /** Collection of toolbar items. */
861                 items : {
862                         // Ordered lis of items in the toolbar. Can't expect `for (var n in items)` to be consistent.
863                         list: ['expandSource', 'help'],
864
865                         expandSource: {
866                                 getHtml: function(highlighter)
867                                 {
868                                         if (highlighter.getParam('collapse') != true)
869                                                 return '';
870                                                 
871                                         var title = highlighter.getParam('title');
872                                         return sh.toolbar.getButtonHtml(highlighter, 'expandSource', title ? title : sh.config.strings.expandSource);
873                                 },
874                         
875                                 execute: function(highlighter)
876                                 {
877                                         var div = getHighlighterDivById(highlighter.id);
878                                         removeClass(div, 'collapsed');
879                                 }
880                         },
881
882                         /** Command to display the about dialog window. */
883                         help: {
884                                 execute: function(highlighter)
885                                 {       
886                                         var wnd = popup('', '_blank', 500, 250, 'scrollbars=0'),
887                                                 doc = wnd.document
888                                                 ;
889                                         
890                                         doc.write(sh.config.strings.aboutDialog);
891                                         doc.close();
892                                         wnd.focus();
893                                 }
894                         }
895                 }
896         },
897
898         /**
899          * Finds all elements on the page which should be processes by SyntaxHighlighter.
900          *
901          * @param {Object} globalParams         Optional parameters which override element's 
902          *                                                                      parameters. Only used if element is specified.
903          * 
904          * @param {Object} element      Optional element to highlight. If none is
905          *                                                      provided, all elements in the current document 
906          *                                                      are returned which qualify.
907          *
908          * @return {Array}      Returns list of <code>{ target: DOMElement, params: Object }</code> objects.
909          */
910         findElements: function(globalParams, element)
911         {
912                 var elements = element ? [element] : toArray(document.getElementsByTagName(sh.config.tagName)), 
913                         conf = sh.config,
914                         result = []
915                         ;
916
917                 // support for <SCRIPT TYPE="syntaxhighlighter" /> feature
918                 if (conf.useScriptTags)
919                         elements = elements.concat(getSyntaxHighlighterScriptTags());
920
921                 if (elements.length === 0) 
922                         return result;
923         
924                 for (var i = 0; i < elements.length; i++) 
925                 {
926                         var item = {
927                                 target: elements[i], 
928                                 // local params take precedence over globals
929                                 params: merge(globalParams, parseParams(elements[i].className))
930                         };
931
932                         if (item.params['brush'] == null)
933                                 continue;
934                                 
935                         result.push(item);
936                 }
937                 
938                 return result;
939         },
940
941         /**
942          * Shorthand to highlight all elements on the page that are marked as 
943          * SyntaxHighlighter source code.
944          * 
945          * @param {Object} globalParams         Optional parameters which override element's 
946          *                                                                      parameters. Only used if element is specified.
947          * 
948          * @param {Object} element      Optional element to highlight. If none is
949          *                                                      provided, all elements in the current document 
950          *                                                      are highlighted.
951          */ 
952         highlight: function(globalParams, element)
953         {
954                 var elements = this.findElements(globalParams, element),
955                         propertyName = 'innerHTML', 
956                         highlighter = null,
957                         conf = sh.config
958                         ;
959
960                 if (elements.length === 0) 
961                         return;
962         
963                 for (var i = 0; i < elements.length; i++) 
964                 {
965                         var element = elements[i],
966                                 target = element.target,
967                                 params = element.params,
968                                 brushName = params.brush,
969                                 code
970                                 ;
971
972                         if (brushName == null)
973                                 continue;
974
975                         // Instantiate a brush
976                         if (params['html-script'] == 'true' || sh.defaults['html-script'] == true) 
977                         {
978                                 highlighter = new sh.HtmlScript(brushName);
979                                 brushName = 'htmlscript';
980                         }
981                         else
982                         {
983                                 var brush = findBrush(brushName);
984                                 
985                                 if (brush)
986                                         highlighter = new brush();
987                                 else
988                                         continue;
989                         }
990                         
991                         code = target[propertyName];
992                         
993                         // remove CDATA from <SCRIPT/> tags if it's present
994                         if (conf.useScriptTags)
995                                 code = stripCData(code);
996                                 
997                         // Inject title if the attribute is present
998                         if ((target.title || '') != '')
999                                 params.title = target.title;
1000                                 
1001                         params['brush'] = brushName;
1002                         highlighter.init(params);
1003                         element = highlighter.getDiv(code);
1004                         
1005                         // carry over ID
1006                         if ((target.id || '') != '')
1007                                 element.id = target.id;
1008                         
1009                         target.parentNode.replaceChild(element, target);
1010                 }
1011         },
1012
1013         /**
1014          * Main entry point for the SyntaxHighlighter.
1015          * @param {Object} params Optional params to apply to all highlighted elements.
1016          */
1017         all: function(params)
1018         {
1019                 attachEvent(
1020                         window,
1021                         'load',
1022                         function() { sh.highlight(params); }
1023                 );
1024         }
1025 }; // end of sh
1026
1027 /**
1028  * Checks if target DOM elements has specified CSS class.
1029  * @param {DOMElement} target Target DOM element to check.
1030  * @param {String} className Name of the CSS class to check for.
1031  * @return {Boolean} Returns true if class name is present, false otherwise.
1032  */
1033 function hasClass(target, className)
1034 {
1035         return target.className.indexOf(className) != -1;
1036 };
1037
1038 /**
1039  * Adds CSS class name to the target DOM element.
1040  * @param {DOMElement} target Target DOM element.
1041  * @param {String} className New CSS class to add.
1042  */
1043 function addClass(target, className)
1044 {
1045         if (!hasClass(target, className))
1046                 target.className += ' ' + className;
1047 };
1048
1049 /**
1050  * Removes CSS class name from the target DOM element.
1051  * @param {DOMElement} target Target DOM element.
1052  * @param {String} className CSS class to remove.
1053  */
1054 function removeClass(target, className)
1055 {
1056         target.className = target.className.replace(className, '');
1057 };
1058
1059 /**
1060  * Converts the source to array object. Mostly used for function arguments and 
1061  * lists returned by getElementsByTagName() which aren't Array objects.
1062  * @param {List} source Source list.
1063  * @return {Array} Returns array.
1064  */
1065 function toArray(source)
1066 {
1067         var result = [];
1068         
1069         for (var i = 0; i < source.length; i++) 
1070                 result.push(source[i]);
1071                 
1072         return result;
1073 };
1074
1075 /**
1076  * Splits block of text into lines.
1077  * @param {String} block Block of text.
1078  * @return {Array} Returns array of lines.
1079  */
1080 function splitLines(block)
1081 {
1082         return block.split(/\r?\n/);
1083 }
1084
1085 /**
1086  * Generates HTML ID for the highlighter.
1087  * @param {String} highlighterId Highlighter ID.
1088  * @return {String} Returns HTML ID.
1089  */
1090 function getHighlighterId(id)
1091 {
1092         var prefix = 'highlighter_';
1093         return id.indexOf(prefix) == 0 ? id : prefix + id;
1094 };
1095
1096 /**
1097  * Finds Highlighter instance by ID.
1098  * @param {String} highlighterId Highlighter ID.
1099  * @return {Highlighter} Returns instance of the highlighter.
1100  */
1101 function getHighlighterById(id)
1102 {
1103         return sh.vars.highlighters[getHighlighterId(id)];
1104 };
1105
1106 /**
1107  * Finds highlighter's DIV container.
1108  * @param {String} highlighterId Highlighter ID.
1109  * @return {Element} Returns highlighter's DIV element.
1110  */
1111 function getHighlighterDivById(id)
1112 {
1113         return document.getElementById(getHighlighterId(id));
1114 };
1115
1116 /**
1117  * Stores highlighter so that getHighlighterById() can do its thing. Each
1118  * highlighter must call this method to preserve itself.
1119  * @param {Highilghter} highlighter Highlighter instance.
1120  */
1121 function storeHighlighter(highlighter)
1122 {
1123         sh.vars.highlighters[getHighlighterId(highlighter.id)] = highlighter;
1124 };
1125
1126 /**
1127  * Looks for a child or parent node which has specified classname.
1128  * Equivalent to jQuery's $(container).find(".className")
1129  * @param {Element} target Target element.
1130  * @param {String} search Class name or node name to look for.
1131  * @param {Boolean} reverse If set to true, will go up the node tree instead of down.
1132  * @return {Element} Returns found child or parent element on null.
1133  */
1134 function findElement(target, search, reverse /* optional */)
1135 {
1136         if (target == null)
1137                 return null;
1138                 
1139         var nodes                       = reverse != true ? target.childNodes : [ target.parentNode ],
1140                 propertyToFind  = { '#' : 'id', '.' : 'className' }[search.substr(0, 1)] || 'nodeName',
1141                 expectedValue,
1142                 found
1143                 ;
1144
1145         expectedValue = propertyToFind != 'nodeName'
1146                 ? search.substr(1)
1147                 : search.toUpperCase()
1148                 ;
1149                 
1150         // main return of the found node
1151         if ((target[propertyToFind] || '').indexOf(expectedValue) != -1)
1152                 return target;
1153         
1154         for (var i = 0; nodes && i < nodes.length && found == null; i++)
1155                 found = findElement(nodes[i], search, reverse);
1156         
1157         return found;
1158 };
1159
1160 /**
1161  * Looks for a parent node which has specified classname.
1162  * This is an alias to <code>findElement(container, className, true)</code>.
1163  * @param {Element} target Target element.
1164  * @param {String} className Class name to look for.
1165  * @return {Element} Returns found parent element on null.
1166  */
1167 function findParentElement(target, className)
1168 {
1169         return findElement(target, className, true);
1170 };
1171
1172 /**
1173  * Finds an index of element in the array.
1174  * @ignore
1175  * @param {Object} searchElement
1176  * @param {Number} fromIndex
1177  * @return {Number} Returns index of element if found; -1 otherwise.
1178  */
1179 function indexOf(array, searchElement, fromIndex)
1180 {
1181         fromIndex = Math.max(fromIndex || 0, 0);
1182
1183         for (var i = fromIndex; i < array.length; i++)
1184                 if(array[i] == searchElement)
1185                         return i;
1186         
1187         return -1;
1188 };
1189
1190 /**
1191  * Generates a unique element ID.
1192  */
1193 function guid(prefix)
1194 {
1195         return (prefix || '') + Math.round(Math.random() * 1000000).toString();
1196 };
1197
1198 /**
1199  * Merges two objects. Values from obj2 override values in obj1.
1200  * Function is NOT recursive and works only for one dimensional objects.
1201  * @param {Object} obj1 First object.
1202  * @param {Object} obj2 Second object.
1203  * @return {Object} Returns combination of both objects.
1204  */
1205 function merge(obj1, obj2)
1206 {
1207         var result = {}, name;
1208
1209         for (name in obj1) 
1210                 result[name] = obj1[name];
1211         
1212         for (name in obj2) 
1213                 result[name] = obj2[name];
1214                 
1215         return result;
1216 };
1217
1218 /**
1219  * Attempts to convert string to boolean.
1220  * @param {String} value Input string.
1221  * @return {Boolean} Returns true if input was "true", false if input was "false" and value otherwise.
1222  */
1223 function toBoolean(value)
1224 {
1225         var result = { "true" : true, "false" : false }[value];
1226         return result == null ? value : result;
1227 };
1228
1229 /**
1230  * Opens up a centered popup window.
1231  * @param {String} url          URL to open in the window.
1232  * @param {String} name         Popup name.
1233  * @param {int} width           Popup width.
1234  * @param {int} height          Popup height.
1235  * @param {String} options      window.open() options.
1236  * @return {Window}                     Returns window instance.
1237  */
1238 function popup(url, name, width, height, options)
1239 {
1240         var x = (screen.width - width) / 2,
1241                 y = (screen.height - height) / 2
1242                 ;
1243                 
1244         options +=      ', left=' + x + 
1245                                 ', top=' + y +
1246                                 ', width=' + width +
1247                                 ', height=' + height
1248                 ;
1249         options = options.replace(/^,/, '');
1250
1251         var win = window.open(url, name, options);
1252         win.focus();
1253         return win;
1254 };
1255
1256 /**
1257  * Adds event handler to the target object.
1258  * @param {Object} obj          Target object.
1259  * @param {String} type         Name of the event.
1260  * @param {Function} func       Handling function.
1261  */
1262 function attachEvent(obj, type, func, scope)
1263 {
1264         function handler(e)
1265         {
1266                 e = e || window.event;
1267                 
1268                 if (!e.target)
1269                 {
1270                         e.target = e.srcElement;
1271                         e.preventDefault = function()
1272                         {
1273                                 this.returnValue = false;
1274                         };
1275                 }
1276                         
1277                 func.call(scope || window, e);
1278         };
1279         
1280         if (obj.attachEvent) 
1281         {
1282                 obj.attachEvent('on' + type, handler);
1283         }
1284         else 
1285         {
1286                 obj.addEventListener(type, handler, false);
1287         }
1288 };
1289
1290 /**
1291  * Displays an alert.
1292  * @param {String} str String to display.
1293  */
1294 function alert(str)
1295 {
1296         window.alert(sh.config.strings.alert + str);
1297 };
1298
1299 /**
1300  * Finds a brush by its alias.
1301  *
1302  * @param {String} alias                Brush alias.
1303  * @param {Boolean} showAlert   Suppresses the alert if false.
1304  * @return {Brush}                              Returns bursh constructor if found, null otherwise.
1305  */
1306 function findBrush(alias, showAlert)
1307 {
1308         var brushes = sh.vars.discoveredBrushes,
1309                 result = null
1310                 ;
1311         
1312         if (brushes == null) 
1313         {
1314                 brushes = {};
1315                 
1316                 // Find all brushes
1317                 for (var brush in sh.brushes) 
1318                 {
1319                         var info = sh.brushes[brush],
1320                                 aliases = info.aliases
1321                                 ;
1322                         
1323                         if (aliases == null) 
1324                                 continue;
1325                         
1326                         // keep the brush name
1327                         info.brushName = brush.toLowerCase();
1328                         
1329                         for (var i = 0; i < aliases.length; i++) 
1330                                 brushes[aliases[i]] = brush;
1331                 }
1332                 
1333                 sh.vars.discoveredBrushes = brushes;
1334         }
1335         
1336         result = sh.brushes[brushes[alias]];
1337
1338         if (result == null && showAlert)
1339                 alert(sh.config.strings.noBrush + alias);
1340         
1341         return result;
1342 };
1343
1344 /**
1345  * Executes a callback on each line and replaces each line with result from the callback.
1346  * @param {Object} str                  Input string.
1347  * @param {Object} callback             Callback function taking one string argument and returning a string.
1348  */
1349 function eachLine(str, callback)
1350 {
1351         var lines = splitLines(str);
1352         
1353         for (var i = 0; i < lines.length; i++)
1354                 lines[i] = callback(lines[i], i);
1355                 
1356         // include \r to enable copy-paste on windows (ie8) without getting everything on one line
1357         return lines.join('\r\n');
1358 };
1359
1360 /**
1361  * This is a special trim which only removes first and last empty lines
1362  * and doesn't affect valid leading space on the first line.
1363  * 
1364  * @param {String} str   Input string
1365  * @return {String}      Returns string without empty first and last lines.
1366  */
1367 function trimFirstAndLastLines(str)
1368 {
1369         return str.replace(/^[ ]*[\n]+|[\n]*[ ]*$/g, '');
1370 };
1371
1372 /**
1373  * Parses key/value pairs into hash object.
1374  * 
1375  * Understands the following formats:
1376  * - name: word;
1377  * - name: [word, word];
1378  * - name: "string";
1379  * - name: 'string';
1380  * 
1381  * For example:
1382  *   name1: value; name2: [value, value]; name3: 'value'
1383  *   
1384  * @param {String} str    Input string.
1385  * @return {Object}       Returns deserialized object.
1386  */
1387 function parseParams(str)
1388 {
1389         var match, 
1390                 result = {},
1391                 arrayRegex = new XRegExp("^\\[(?<values>(.*?))\\]$"),
1392                 regex = new XRegExp(
1393                         "(?<name>[\\w-]+)" +
1394                         "\\s*:\\s*" +
1395                         "(?<value>" +
1396                                 "[\\w-%#]+|" +          // word
1397                                 "\\[.*?\\]|" +          // [] array
1398                                 '".*?"|' +                      // "" string
1399                                 "'.*?'" +                       // '' string
1400                         ")\\s*;?",
1401                         "g"
1402                 )
1403                 ;
1404
1405         while ((match = regex.exec(str)) != null) 
1406         {
1407                 var value = match.value
1408                         .replace(/^['"]|['"]$/g, '') // strip quotes from end of strings
1409                         ;
1410                 
1411                 // try to parse array value
1412                 if (value != null && arrayRegex.test(value))
1413                 {
1414                         var m = arrayRegex.exec(value);
1415                         value = m.values.length > 0 ? m.values.split(/\s*,\s*/) : [];
1416                 }
1417                 
1418                 result[match.name] = value;
1419         }
1420         
1421         return result;
1422 };
1423
1424 /**
1425  * Wraps each line of the string into <code/> tag with given style applied to it.
1426  * 
1427  * @param {String} str   Input string.
1428  * @param {String} css   Style name to apply to the string.
1429  * @return {String}      Returns input string with each line surrounded by <span/> tag.
1430  */
1431 function wrapLinesWithCode(str, css)
1432 {
1433         if (str == null || str.length == 0 || str == '\n') 
1434                 return str;
1435
1436         str = str.replace(/</g, '&lt;');
1437
1438         // Replace two or more sequential spaces with &nbsp; leaving last space untouched.
1439         str = str.replace(/ {2,}/g, function(m)
1440         {
1441                 var spaces = '';
1442                 
1443                 for (var i = 0; i < m.length - 1; i++)
1444                         spaces += sh.config.space;
1445                 
1446                 return spaces + ' ';
1447         });
1448
1449         // Split each line and apply <span class="...">...</span> to them so that
1450         // leading spaces aren't included.
1451         if (css != null) 
1452                 str = eachLine(str, function(line)
1453                 {
1454                         if (line.length == 0) 
1455                                 return '';
1456                         
1457                         var spaces = '';
1458                         
1459                         line = line.replace(/^(&nbsp;| )+/, function(s)
1460                         {
1461                                 spaces = s;
1462                                 return '';
1463                         });
1464                         
1465                         if (line.length == 0) 
1466                                 return spaces;
1467                         
1468                         return spaces + '<code class="' + css + '">' + line + '</code>';
1469                 });
1470
1471         return str;
1472 };
1473
1474 /**
1475  * Pads number with zeros until it's length is the same as given length.
1476  * 
1477  * @param {Number} number       Number to pad.
1478  * @param {Number} length       Max string length with.
1479  * @return {String}                     Returns a string padded with proper amount of '0'.
1480  */
1481 function padNumber(number, length)
1482 {
1483         var result = number.toString();
1484         
1485         while (result.length < length)
1486                 result = '0' + result;
1487         
1488         return result;
1489 };
1490
1491 /**
1492  * Replaces tabs with spaces.
1493  * 
1494  * @param {String} code         Source code.
1495  * @param {Number} tabSize      Size of the tab.
1496  * @return {String}                     Returns code with all tabs replaces by spaces.
1497  */
1498 function processTabs(code, tabSize)
1499 {
1500         var tab = '';
1501         
1502         for (var i = 0; i < tabSize; i++)
1503                 tab += ' ';
1504
1505         return code.replace(/\t/g, tab);
1506 };
1507
1508 /**
1509  * Replaces tabs with smart spaces.
1510  * 
1511  * @param {String} code    Code to fix the tabs in.
1512  * @param {Number} tabSize Number of spaces in a column.
1513  * @return {String}        Returns code with all tabs replaces with roper amount of spaces.
1514  */
1515 function processSmartTabs(code, tabSize)
1516 {
1517         var lines = splitLines(code),
1518                 tab = '\t',
1519                 spaces = ''
1520                 ;
1521         
1522         // Create a string with 1000 spaces to copy spaces from... 
1523         // It's assumed that there would be no indentation longer than that.
1524         for (var i = 0; i < 50; i++) 
1525                 spaces += '                    '; // 20 spaces * 50
1526                         
1527         // This function inserts specified amount of spaces in the string
1528         // where a tab is while removing that given tab.
1529         function insertSpaces(line, pos, count)
1530         {
1531                 return line.substr(0, pos)
1532                         + spaces.substr(0, count)
1533                         + line.substr(pos + 1, line.length) // pos + 1 will get rid of the tab
1534                         ;
1535         };
1536
1537         // Go through all the lines and do the 'smart tabs' magic.
1538         code = eachLine(code, function(line)
1539         {
1540                 if (line.indexOf(tab) == -1) 
1541                         return line;
1542                 
1543                 var pos = 0;
1544                 
1545                 while ((pos = line.indexOf(tab)) != -1) 
1546                 {
1547                         // This is pretty much all there is to the 'smart tabs' logic.
1548                         // Based on the position within the line and size of a tab,
1549                         // calculate the amount of spaces we need to insert.
1550                         var spaces = tabSize - pos % tabSize;
1551                         line = insertSpaces(line, pos, spaces);
1552                 }
1553                 
1554                 return line;
1555         });
1556         
1557         return code;
1558 };
1559
1560 /**
1561  * Performs various string fixes based on configuration.
1562  */
1563 function fixInputString(str)
1564 {
1565         var br = /<br\s*\/?>|&lt;br\s*\/?&gt;/gi;
1566         
1567         if (sh.config.bloggerMode == true)
1568                 str = str.replace(br, '\n');
1569
1570         if (sh.config.stripBrs == true)
1571                 str = str.replace(br, '');
1572                 
1573         return str;
1574 };
1575
1576 /**
1577  * Removes all white space at the begining and end of a string.
1578  * 
1579  * @param {String} str   String to trim.
1580  * @return {String}      Returns string without leading and following white space characters.
1581  */
1582 function trim(str)
1583 {
1584         return str.replace(/^\s+|\s+$/g, '');
1585 };
1586
1587 /**
1588  * Unindents a block of text by the lowest common indent amount.
1589  * @param {String} str   Text to unindent.
1590  * @return {String}      Returns unindented text block.
1591  */
1592 function unindent(str)
1593 {
1594         var lines = splitLines(fixInputString(str)),
1595                 indents = new Array(),
1596                 regex = /^\s*/,
1597                 min = 1000
1598                 ;
1599         
1600         // go through every line and check for common number of indents
1601         for (var i = 0; i < lines.length && min > 0; i++) 
1602         {
1603                 var line = lines[i];
1604                 
1605                 if (trim(line).length == 0) 
1606                         continue;
1607                 
1608                 var matches = regex.exec(line);
1609                 
1610                 // In the event that just one line doesn't have leading white space
1611                 // we can't unindent anything, so bail completely.
1612                 if (matches == null) 
1613                         return str;
1614                         
1615                 min = Math.min(matches[0].length, min);
1616         }
1617         
1618         // trim minimum common number of white space from the begining of every line
1619         if (min > 0) 
1620                 for (var i = 0; i < lines.length; i++) 
1621                         lines[i] = lines[i].substr(min);
1622         
1623         return lines.join('\n');
1624 };
1625
1626 /**
1627  * Callback method for Array.sort() which sorts matches by
1628  * index position and then by length.
1629  * 
1630  * @param {Match} m1    Left object.
1631  * @param {Match} m2    Right object.
1632  * @return {Number}     Returns -1, 0 or -1 as a comparison result.
1633  */
1634 function matchesSortCallback(m1, m2)
1635 {
1636         // sort matches by index first
1637         if(m1.index < m2.index)
1638                 return -1;
1639         else if(m1.index > m2.index)
1640                 return 1;
1641         else
1642         {
1643                 // if index is the same, sort by length
1644                 if(m1.length < m2.length)
1645                         return -1;
1646                 else if(m1.length > m2.length)
1647                         return 1;
1648         }
1649         
1650         return 0;
1651 };
1652
1653 /**
1654  * Executes given regular expression on provided code and returns all
1655  * matches that are found.
1656  * 
1657  * @param {String} code    Code to execute regular expression on.
1658  * @param {Object} regex   Regular expression item info from <code>regexList</code> collection.
1659  * @return {Array}         Returns a list of Match objects.
1660  */ 
1661 function getMatches(code, regexInfo)
1662 {
1663         function defaultAdd(match, regexInfo)
1664         {
1665                 return match[0];
1666         };
1667         
1668         var index = 0,
1669                 match = null,
1670                 matches = [],
1671                 func = regexInfo.func ? regexInfo.func : defaultAdd
1672                 ;
1673         
1674         while((match = regexInfo.regex.exec(code)) != null)
1675         {
1676                 var resultMatch = func(match, regexInfo);
1677                 
1678                 if (typeof(resultMatch) == 'string')
1679                         resultMatch = [new sh.Match(resultMatch, match.index, regexInfo.css)];
1680
1681                 matches = matches.concat(resultMatch);
1682         }
1683         
1684         return matches;
1685 };
1686
1687 /**
1688  * Turns all URLs in the code into <a/> tags.
1689  * @param {String} code Input code.
1690  * @return {String} Returns code with </a> tags.
1691  */
1692 function processUrls(code)
1693 {
1694         var gt = /(.*)((&gt;|&lt;).*)/;
1695         
1696         return code.replace(sh.regexLib.url, function(m)
1697         {
1698                 var suffix = '',
1699                         match = null
1700                         ;
1701                 
1702                 // We include &lt; and &gt; in the URL for the common cases like <http://google.com>
1703                 // The problem is that they get transformed into &lt;http://google.com&gt;
1704                 // Where as &gt; easily looks like part of the URL string.
1705         
1706                 if (match = gt.exec(m))
1707                 {
1708                         m = match[1];
1709                         suffix = match[2];
1710                 }
1711                 
1712                 return '<a href="' + m + '">' + m + '</a>' + suffix;
1713         });
1714 };
1715
1716 /**
1717  * Finds all <SCRIPT TYPE="syntaxhighlighter" /> elementss.
1718  * @return {Array} Returns array of all found SyntaxHighlighter tags.
1719  */
1720 function getSyntaxHighlighterScriptTags()
1721 {
1722         var tags = document.getElementsByTagName('script'),
1723                 result = []
1724                 ;
1725         
1726         for (var i = 0; i < tags.length; i++)
1727                 if (tags[i].type == 'syntaxhighlighter')
1728                         result.push(tags[i]);
1729                         
1730         return result;
1731 };
1732
1733 /**
1734  * Strips <![CDATA[]]> from <SCRIPT /> content because it should be used
1735  * there in most cases for XHTML compliance.
1736  * @param {String} original     Input code.
1737  * @return {String} Returns code without leading <![CDATA[]]> tags.
1738  */
1739 function stripCData(original)
1740 {
1741         var left = '<![CDATA[',
1742                 right = ']]>',
1743                 // for some reason IE inserts some leading blanks here
1744                 copy = trim(original),
1745                 changed = false,
1746                 leftLength = left.length,
1747                 rightLength = right.length
1748                 ;
1749         
1750         if (copy.indexOf(left) == 0)
1751         {
1752                 copy = copy.substring(leftLength);
1753                 changed = true;
1754         }
1755         
1756         var copyLength = copy.length;
1757         
1758         if (copy.indexOf(right) == copyLength - rightLength)
1759         {
1760                 copy = copy.substring(0, copyLength - rightLength);
1761                 changed = true;
1762         }
1763         
1764         return changed ? copy : original;
1765 };
1766
1767
1768 /**
1769  * Quick code mouse double click handler.
1770  */
1771 function quickCodeHandler(e)
1772 {
1773         var target = e.target,
1774                 highlighterDiv = findParentElement(target, '.syntaxhighlighter'),
1775                 container = findParentElement(target, '.container'),
1776                 textarea = document.createElement('textarea'),
1777                 highlighter
1778                 ;
1779
1780         if (!container || !highlighterDiv || findElement(container, 'textarea'))
1781                 return;
1782
1783         highlighter = getHighlighterById(highlighterDiv.id);
1784         
1785         // add source class name
1786         addClass(highlighterDiv, 'source');
1787
1788         // Have to go over each line and grab it's text, can't just do it on the
1789         // container because Firefox loses all \n where as Webkit doesn't.
1790         var lines = container.childNodes,
1791                 code = []
1792                 ;
1793         
1794         for (var i = 0; i < lines.length; i++)
1795                 code.push(lines[i].innerText || lines[i].textContent);
1796         
1797         // using \r instead of \r or \r\n makes this work equally well on IE, FF and Webkit
1798         code = code.join('\r');
1799
1800     // For Webkit browsers, replace nbsp with a breaking space
1801     code = code.replace(/\u00a0/g, " ");
1802         
1803         // inject <textarea/> tag
1804         textarea.appendChild(document.createTextNode(code));
1805         container.appendChild(textarea);
1806         
1807         // preselect all text
1808         textarea.focus();
1809         textarea.select();
1810         
1811         // set up handler for lost focus
1812         attachEvent(textarea, 'blur', function(e)
1813         {
1814                 textarea.parentNode.removeChild(textarea);
1815                 removeClass(highlighterDiv, 'source');
1816         });
1817 };
1818
1819 /**
1820  * Match object.
1821  */
1822 sh.Match = function(value, index, css)
1823 {
1824         this.value = value;
1825         this.index = index;
1826         this.length = value.length;
1827         this.css = css;
1828         this.brushName = null;
1829 };
1830
1831 sh.Match.prototype.toString = function()
1832 {
1833         return this.value;
1834 };
1835
1836 /**
1837  * Simulates HTML code with a scripting language embedded.
1838  * 
1839  * @param {String} scriptBrushName Brush name of the scripting language.
1840  */
1841 sh.HtmlScript = function(scriptBrushName)
1842 {
1843         var brushClass = findBrush(scriptBrushName),
1844                 scriptBrush,
1845                 xmlBrush = new sh.brushes.Xml(),
1846                 bracketsRegex = null,
1847                 ref = this,
1848                 methodsToExpose = 'getDiv getHtml init'.split(' ')
1849                 ;
1850
1851         if (brushClass == null)
1852                 return;
1853         
1854         scriptBrush = new brushClass();
1855         
1856         for(var i = 0; i < methodsToExpose.length; i++)
1857                 // make a closure so we don't lose the name after i changes
1858                 (function() {
1859                         var name = methodsToExpose[i];
1860                         
1861                         ref[name] = function()
1862                         {
1863                                 return xmlBrush[name].apply(xmlBrush, arguments);
1864                         };
1865                 })();
1866         
1867         if (scriptBrush.htmlScript == null)
1868         {
1869                 alert(sh.config.strings.brushNotHtmlScript + scriptBrushName);
1870                 return;
1871         }
1872         
1873         xmlBrush.regexList.push(
1874                 { regex: scriptBrush.htmlScript.code, func: process }
1875         );
1876         
1877         function offsetMatches(matches, offset)
1878         {
1879                 for (var j = 0; j < matches.length; j++) 
1880                         matches[j].index += offset;
1881         }
1882         
1883         function process(match, info)
1884         {
1885                 var code = match.code,
1886                         matches = [],
1887                         regexList = scriptBrush.regexList,
1888                         offset = match.index + match.left.length,
1889                         htmlScript = scriptBrush.htmlScript,
1890                         result
1891                         ;
1892
1893                 // add all matches from the code
1894                 for (var i = 0; i < regexList.length; i++)
1895                 {
1896                         result = getMatches(code, regexList[i]);
1897                         offsetMatches(result, offset);
1898                         matches = matches.concat(result);
1899                 }
1900                 
1901                 // add left script bracket
1902                 if (htmlScript.left != null && match.left != null)
1903                 {
1904                         result = getMatches(match.left, htmlScript.left);
1905                         offsetMatches(result, match.index);
1906                         matches = matches.concat(result);
1907                 }
1908                 
1909                 // add right script bracket
1910                 if (htmlScript.right != null && match.right != null)
1911                 {
1912                         result = getMatches(match.right, htmlScript.right);
1913                         offsetMatches(result, match.index + match[0].lastIndexOf(match.right));
1914                         matches = matches.concat(result);
1915                 }
1916                 
1917                 for (var j = 0; j < matches.length; j++)
1918                         matches[j].brushName = brushClass.brushName;
1919                         
1920                 return matches;
1921         }
1922 };
1923
1924 /**
1925  * Main Highlither class.
1926  * @constructor
1927  */
1928 sh.Highlighter = function()
1929 {
1930         // not putting any code in here because of the prototype inheritance
1931 };
1932
1933 sh.Highlighter.prototype = {
1934         /**
1935          * Returns value of the parameter passed to the highlighter.
1936          * @param {String} name                         Name of the parameter.
1937          * @param {Object} defaultValue         Default value.
1938          * @return {Object}                                     Returns found value or default value otherwise.
1939          */
1940         getParam: function(name, defaultValue)
1941         {
1942                 var result = this.params[name];
1943                 return toBoolean(result == null ? defaultValue : result);
1944         },
1945         
1946         /**
1947          * Shortcut to document.createElement().
1948          * @param {String} name         Name of the element to create (DIV, A, etc).
1949          * @return {HTMLElement}        Returns new HTML element.
1950          */
1951         create: function(name)
1952         {
1953                 return document.createElement(name);
1954         },
1955         
1956         /**
1957          * Applies all regular expression to the code and stores all found
1958          * matches in the `this.matches` array.
1959          * @param {Array} regexList             List of regular expressions.
1960          * @param {String} code                 Source code.
1961          * @return {Array}                              Returns list of matches.
1962          */
1963         findMatches: function(regexList, code)
1964         {
1965                 var result = [];
1966                 
1967                 if (regexList != null)
1968                         for (var i = 0; i < regexList.length; i++) 
1969                                 // BUG: length returns len+1 for array if methods added to prototype chain (oising@gmail.com)
1970                                 if (typeof (regexList[i]) == "object")
1971                                         result = result.concat(getMatches(code, regexList[i]));
1972                 
1973                 // sort and remove nested the matches
1974                 return this.removeNestedMatches(result.sort(matchesSortCallback));
1975         },
1976         
1977         /**
1978          * Checks to see if any of the matches are inside of other matches. 
1979          * This process would get rid of highligted strings inside comments, 
1980          * keywords inside strings and so on.
1981          */
1982         removeNestedMatches: function(matches)
1983         {
1984                 // Optimized by Jose Prado (http://joseprado.com)
1985                 for (var i = 0; i < matches.length; i++) 
1986                 { 
1987                         if (matches[i] === null)
1988                                 continue;
1989                         
1990                         var itemI = matches[i],
1991                                 itemIEndPos = itemI.index + itemI.length
1992                                 ;
1993                         
1994                         for (var j = i + 1; j < matches.length && matches[i] !== null; j++) 
1995                         {
1996                                 var itemJ = matches[j];
1997                                 
1998                                 if (itemJ === null) 
1999                                         continue;
2000                                 else if (itemJ.index > itemIEndPos) 
2001                                         break;
2002                                 else if (itemJ.index == itemI.index && itemJ.length > itemI.length)
2003                                         matches[i] = null;
2004                                 else if (itemJ.index >= itemI.index && itemJ.index < itemIEndPos) 
2005                                         matches[j] = null;
2006                         }
2007                 }
2008                 
2009                 return matches;
2010         },
2011         
2012         /**
2013          * Creates an array containing integer line numbers starting from the 'first-line' param.
2014          * @return {Array} Returns array of integers.
2015          */
2016         figureOutLineNumbers: function(code)
2017         {
2018                 var lines = [],
2019                         firstLine = parseInt(this.getParam('first-line'))
2020                         ;
2021                 
2022                 eachLine(code, function(line, index)
2023                 {
2024                         lines.push(index + firstLine);
2025                 });
2026                 
2027                 return lines;
2028         },
2029         
2030         /**
2031          * Determines if specified line number is in the highlighted list.
2032          */
2033         isLineHighlighted: function(lineNumber)
2034         {
2035                 var list = this.getParam('highlight', []);
2036                 
2037                 if (typeof(list) != 'object' && list.push == null) 
2038                         list = [ list ];
2039                 
2040                 return indexOf(list, lineNumber.toString()) != -1;
2041         },
2042         
2043         /**
2044          * Generates HTML markup for a single line of code while determining alternating line style.
2045          * @param {Integer} lineNumber  Line number.
2046          * @param {String} code Line    HTML markup.
2047          * @return {String}                             Returns HTML markup.
2048          */
2049         getLineHtml: function(lineIndex, lineNumber, code)
2050         {
2051                 var classes = [
2052                         'line',
2053                         'number' + lineNumber,
2054                         'index' + lineIndex,
2055                         'alt' + (lineNumber % 2 == 0 ? 1 : 2).toString()
2056                 ];
2057                 
2058                 if (this.isLineHighlighted(lineNumber))
2059                         classes.push('highlighted');
2060                 
2061                 if (lineNumber == 0)
2062                         classes.push('break');
2063                         
2064                 return '<div class="' + classes.join(' ') + '">' + code + '</div>';
2065         },
2066         
2067         /**
2068          * Generates HTML markup for line number column.
2069          * @param {String} code                 Complete code HTML markup.
2070          * @param {Array} lineNumbers   Calculated line numbers.
2071          * @return {String}                             Returns HTML markup.
2072          */
2073         getLineNumbersHtml: function(code, lineNumbers)
2074         {
2075                 var html = '',
2076                         count = splitLines(code).length,
2077                         firstLine = parseInt(this.getParam('first-line')),
2078                         pad = this.getParam('pad-line-numbers')
2079                         ;
2080                 
2081                 if (pad == true)
2082                         pad = (firstLine + count - 1).toString().length;
2083                 else if (isNaN(pad) == true)
2084                         pad = 0;
2085                         
2086                 for (var i = 0; i < count; i++)
2087                 {
2088                         var lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i,
2089                                 code = lineNumber == 0 ? sh.config.space : padNumber(lineNumber, pad)
2090                                 ;
2091                                 
2092                         html += this.getLineHtml(i, lineNumber, code);
2093                 }
2094                 
2095                 return html;
2096         },
2097         
2098         /**
2099          * Splits block of text into individual DIV lines.
2100          * @param {String} code                 Code to highlight.
2101          * @param {Array} lineNumbers   Calculated line numbers.
2102          * @return {String}                             Returns highlighted code in HTML form.
2103          */
2104         getCodeLinesHtml: function(html, lineNumbers)
2105         {
2106                 html = trim(html);
2107                 
2108                 var lines = splitLines(html),
2109                         padLength = this.getParam('pad-line-numbers'),
2110                         firstLine = parseInt(this.getParam('first-line')),
2111                         html = '',
2112                         brushName = this.getParam('brush')
2113                         ;
2114
2115                 for (var i = 0; i < lines.length; i++)
2116                 {
2117                         var line = lines[i],
2118                                 indent = /^(&nbsp;|\s)+/.exec(line),
2119                                 spaces = null,
2120                                 lineNumber = lineNumbers ? lineNumbers[i] : firstLine + i;
2121                                 ;
2122
2123                         if (indent != null)
2124                         {
2125                                 spaces = indent[0].toString();
2126                                 line = line.substr(spaces.length);
2127                                 spaces = spaces.replace(' ', sh.config.space);
2128                         }
2129
2130                         line = trim(line);
2131                         
2132                         if (line.length == 0)
2133                                 line = sh.config.space;
2134                         
2135                         html += this.getLineHtml(
2136                                 i,
2137                                 lineNumber, 
2138                                 (spaces != null ? '<code class="' + brushName + ' spaces">' + spaces + '</code>' : '') + line
2139                         );
2140                 }
2141                 
2142                 return html;
2143         },
2144         
2145         /**
2146          * Returns HTML for the table title or empty string if title is null.
2147          */
2148         getTitleHtml: function(title)
2149         {
2150                 return title ? '<caption>' + title + '</caption>' : '';
2151         },
2152         
2153         /**
2154          * Finds all matches in the source code.
2155          * @param {String} code         Source code to process matches in.
2156          * @param {Array} matches       Discovered regex matches.
2157          * @return {String} Returns formatted HTML with processed mathes.
2158          */
2159         getMatchesHtml: function(code, matches)
2160         {
2161                 var pos = 0, 
2162                         result = '',
2163                         brushName = this.getParam('brush', '')
2164                         ;
2165                 
2166                 function getBrushNameCss(match)
2167                 {
2168                         var result = match ? (match.brushName || brushName) : brushName;
2169                         return result ? result + ' ' : '';
2170                 };
2171                 
2172                 // Finally, go through the final list of matches and pull the all
2173                 // together adding everything in between that isn't a match.
2174                 for (var i = 0; i < matches.length; i++) 
2175                 {
2176                         var match = matches[i],
2177                                 matchBrushName
2178                                 ;
2179                         
2180                         if (match === null || match.length === 0) 
2181                                 continue;
2182                         
2183                         matchBrushName = getBrushNameCss(match);
2184                         
2185                         result += wrapLinesWithCode(code.substr(pos, match.index - pos), matchBrushName + 'plain')
2186                                         + wrapLinesWithCode(match.value, matchBrushName + match.css)
2187                                         ;
2188
2189                         pos = match.index + match.length + (match.offset || 0);
2190                 }
2191
2192                 // don't forget to add whatever's remaining in the string
2193                 result += wrapLinesWithCode(code.substr(pos), getBrushNameCss() + 'plain');
2194
2195                 return result;
2196         },
2197         
2198         /**
2199          * Generates HTML markup for the whole syntax highlighter.
2200          * @param {String} code Source code.
2201          * @return {String} Returns HTML markup.
2202          */
2203         getHtml: function(code)
2204         {
2205                 var html = '',
2206                         classes = [ 'syntaxhighlighter' ],
2207                         tabSize,
2208                         matches,
2209                         lineNumbers
2210                         ;
2211                 
2212                 // process light mode
2213                 if (this.getParam('light') == true)
2214                         this.params.toolbar = this.params.gutter = false;
2215
2216                 className = 'syntaxhighlighter';
2217
2218                 if (this.getParam('collapse') == true)
2219                         classes.push('collapsed');
2220                 
2221                 if ((gutter = this.getParam('gutter')) == false)
2222                         classes.push('nogutter');
2223
2224                 // add custom user style name
2225                 classes.push(this.getParam('class-name'));
2226
2227                 // add brush alias to the class name for custom CSS
2228                 classes.push(this.getParam('brush'));
2229
2230                 code = trimFirstAndLastLines(code)
2231                         .replace(/\r/g, ' ') // IE lets these buggers through
2232                         ;
2233
2234                 tabSize = this.getParam('tab-size');
2235
2236                 // replace tabs with spaces
2237                 code = this.getParam('smart-tabs') == true
2238                         ? processSmartTabs(code, tabSize)
2239                         : processTabs(code, tabSize)
2240                         ;
2241
2242                 // unindent code by the common indentation
2243                 if (this.getParam('unindent'))
2244                         code = unindent(code);
2245
2246                 if (gutter)
2247                         lineNumbers = this.figureOutLineNumbers(code);
2248                 
2249                 // find matches in the code using brushes regex list
2250                 matches = this.findMatches(this.regexList, code);
2251                 // processes found matches into the html
2252                 html = this.getMatchesHtml(code, matches);
2253                 // finally, split all lines so that they wrap well
2254                 html = this.getCodeLinesHtml(html, lineNumbers);
2255
2256                 // finally, process the links
2257                 if (this.getParam('auto-links'))
2258                         html = processUrls(html);
2259                 
2260                 if (typeof(navigator) != 'undefined' && navigator.userAgent && navigator.userAgent.match(/MSIE/))
2261                         classes.push('ie');
2262                 
2263                 html = 
2264                         '<div id="' + getHighlighterId(this.id) + '" class="' + classes.join(' ') + '">'
2265                                 + (this.getParam('toolbar') ? sh.toolbar.getHtml(this) : '')
2266                                 + '<table border="0" cellpadding="0" cellspacing="0">'
2267                                         + this.getTitleHtml(this.getParam('title'))
2268                                         + '<tbody>'
2269                                                 + '<tr>'
2270                                                         + (gutter ? '<td class="gutter">' + this.getLineNumbersHtml(code) + '</td>' : '')
2271                                                         + '<td class="code">'
2272                                                                 + '<div class="container">'
2273                                                                         + html
2274                                                                 + '</div>'
2275                                                         + '</td>'
2276                                                 + '</tr>'
2277                                         + '</tbody>'
2278                                 + '</table>'
2279                         + '</div>'
2280                         ;
2281                         
2282                 return html;
2283         },
2284         
2285         /**
2286          * Highlights the code and returns complete HTML.
2287          * @param {String} code     Code to highlight.
2288          * @return {Element}        Returns container DIV element with all markup.
2289          */
2290         getDiv: function(code)
2291         {
2292                 if (code === null) 
2293                         code = '';
2294                 
2295                 this.code = code;
2296
2297                 var div = this.create('div');
2298
2299                 // create main HTML
2300                 div.innerHTML = this.getHtml(code);
2301                 
2302                 // set up click handlers
2303                 if (this.getParam('toolbar'))
2304                         attachEvent(findElement(div, '.toolbar'), 'click', sh.toolbar.handler);
2305                 
2306                 if (this.getParam('quick-code'))
2307                         attachEvent(findElement(div, '.code'), 'dblclick', quickCodeHandler);
2308                 
2309                 return div;
2310         },
2311         
2312         /**
2313          * Initializes the highlighter/brush.
2314          *
2315          * Constructor isn't used for initialization so that nothing executes during necessary
2316          * `new SyntaxHighlighter.Highlighter()` call when setting up brush inheritence.
2317          *
2318          * @param {Hash} params Highlighter parameters.
2319          */
2320         init: function(params)
2321         {
2322                 this.id = guid();
2323                 
2324                 // register this instance in the highlighters list
2325                 storeHighlighter(this);
2326                 
2327                 // local params take precedence over defaults
2328                 this.params = merge(sh.defaults, params || {})
2329                 
2330                 // process light mode
2331                 if (this.getParam('light') == true)
2332                         this.params.toolbar = this.params.gutter = false;
2333         },
2334         
2335         /**
2336          * Converts space separated list of keywords into a regular expression string.
2337          * @param {String} str    Space separated keywords.
2338          * @return {String}       Returns regular expression string.
2339          */
2340         getKeywords: function(str)
2341         {
2342                 str = str
2343                         .replace(/^\s+|\s+$/g, '')
2344                         .replace(/\s+/g, '|')
2345                         ;
2346                 
2347                 return '\\b(?:' + str + ')\\b';
2348         },
2349         
2350         /**
2351          * Makes a brush compatible with the `html-script` functionality.
2352          * @param {Object} regexGroup Object containing `left` and `right` regular expressions.
2353          */
2354         forHtmlScript: function(regexGroup)
2355         {
2356                 var regex = { 'end' : regexGroup.right.source };
2357
2358                 if(regexGroup.eof)
2359                         regex.end = "(?:(?:" + regex.end + ")|$)";
2360                 
2361                 this.htmlScript = {
2362                         left : { regex: regexGroup.left, css: 'script' },
2363                         right : { regex: regexGroup.right, css: 'script' },
2364                         code : new XRegExp(
2365                                 "(?<left>" + regexGroup.left.source + ")" +
2366                                 "(?<code>.*?)" +
2367                                 "(?<right>" + regex.end + ")",
2368                                 "sgi"
2369                                 )
2370                 };
2371         }
2372 }; // end of Highlighter
2373
2374 return sh;
2375 }(); // end of anonymous function
2376
2377 // CommonJS
2378 typeof(exports) != 'undefined' ? exports.SyntaxHighlighter = SyntaxHighlighter : null;/**
2379  * SyntaxHighlighter
2380  * http://alexgorbatchev.com/SyntaxHighlighter
2381  *
2382  * SyntaxHighlighter is donationware. If you are using it, please donate.
2383  * http://alexgorbatchev.com/SyntaxHighlighter/donate.html
2384  *
2385  * @version
2386  * 3.0.83 (July 02 2010)
2387  * 
2388  * @copyright
2389  * Copyright (C) 2004-2010 Alex Gorbatchev.
2390  *
2391  * @license
2392  * Dual licensed under the MIT and GPL licenses.
2393  */
2394 ;(function()
2395 {
2396         // CommonJS
2397         typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
2398
2399         function Brush()
2400         {
2401                 var keywords =  'break case catch continue ' +
2402                                                 'default delete do else false  ' +
2403                                                 'for function if in instanceof ' +
2404                                                 'new null return super switch ' +
2405                                                 'this throw true try typeof var while with'
2406                                                 ;
2407                 
2408                 var datatablesAPI =
2409                         'fnSettings fnDraw fnFilter fnSort fnAddData fnDeleteRow fnClearTable fnGetData '+
2410                         'fnGetPosition fnGetNodes fnOpen fnClose fnUpdate fnSetColumnVis fnVersionCheck '+
2411                         'fnPageChange fnSortListener fnDestroy fnAdjustColumnSizing';
2412
2413                 var r = SyntaxHighlighter.regexLib;
2414                 
2415                 this.regexList = [
2416                         { regex: r.multiLineDoubleQuotedString,                                 css: 'string' },                        // double quoted strings
2417                         { regex: r.multiLineSingleQuotedString,                                 css: 'string' },                        // single quoted strings
2418                         { regex: r.singleLineCComments,                                                 css: 'comments' },                      // one line comments
2419                         { regex: r.multiLineCComments,                                                  css: 'comments' },                      // multiline comments
2420                         { regex: /\s*#.*/gm,                                                                    css: 'preprocessor' },          // preprocessor tags like #region and #endregion
2421                         { regex: new RegExp(this.getKeywords(keywords), 'gm'),  css: 'keyword' },                       // keywords
2422                         { regex: new RegExp(this.getKeywords(datatablesAPI), 'gm'),     css: 'dtapi' }                  // DataTables API methods
2423                         ];
2424         
2425                 this.forHtmlScript(r.scriptScriptTags);
2426         };
2427
2428         Brush.prototype = new SyntaxHighlighter.Highlighter();
2429         Brush.aliases   = ['js', 'jscript', 'javascript'];
2430
2431         SyntaxHighlighter.brushes.JScript = Brush;
2432
2433         // CommonJS
2434         typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
2435 })();
2436
2437 /*
2438     http://www.JSON.org/json2.js
2439     2011-02-23
2440     Public Domain.
2441 */
2442 var JSON;JSON||(JSON={});
2443 (function(){function k(a){return a<10?"0"+a:a}function o(a){p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function(a){var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j){var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b){case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if(!b)return"null";
2444 e+=n;f=[];if(Object.prototype.toString.apply(b)==="[object Array]"){m=b.length;for(c=0;c<m;c+=1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if(i&&typeof i==="object"){m=i.length;for(c=0;c<m;c+=1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for(d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+
2445 "}";e=g;return h}}if(typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
2446 p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,j,c){var d;n=e="";if(typeof c==="number")for(d=0;d<c;d+=1)n+=" ";else typeof c==="string"&&(n=c);if((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("",
2447 {"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,e){function c(a,d){var g,f,b=a[d];if(b&&typeof b==="object")for(g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
2448 "]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})();
2449
2450
2451 /* Self initialise */
2452 SyntaxHighlighter.all();
2453
2454 $(window).load( function() {
2455 var dtOptions = [
2456 'fnSettings',
2457 'fnDraw',
2458 'fnFilter',
2459 'fnSort',
2460 'fnAddData',
2461 'fnDeleteRow',
2462 'fnClearTable',
2463 'fnGetData',
2464 'fnGetPosition',
2465 'fnGetNodes',
2466 'fnOpen',
2467 'fnClose',
2468 'fnUpdate',
2469 'fnSetColumnVis',
2470 'fnVersionCheck',
2471 'fnPageChange',
2472 'fnSortListener',
2473 'fnDestroy',
2474 'fnAdjustColumnSizing',
2475 'bPaginate',
2476 'bLengthChange',
2477 'bFilter',
2478 'bSort',
2479 'bInfo',
2480 'bProcessing',
2481 'bAutoWidth',
2482 'bSortClasses',
2483 'bStateSave',
2484 'fnRowCallback',
2485 'fnDrawCallback',
2486 'fnHeaderCallback',
2487 'fnFooterCallback',
2488 'fnInitComplete',
2489 'fnServerParams',
2490 'iDisplayLength',
2491 'aaSorting',
2492 'sPaginationType',
2493 'sDom',
2494 'sAjaxSource',
2495 'iCookieDuration',
2496 'asStripClasses',
2497 'bVisible',
2498 'bSearchable',
2499 'bSortable',
2500 'sTitle',
2501 'sWidth',
2502 'sClass',
2503 'fnRender',
2504 'sType',
2505 'iDataSort',
2506 'bUseRendered',
2507 'bServerSide',
2508 'sAjaxSource',
2509 'fnServerData',
2510 'aaSortingFixed',
2511 'oSearch',
2512 'aoSearchCols',
2513 'sName',
2514 'bJQueryUI',
2515 'iDisplayStart',
2516 'asSorting',
2517 'sSortDataType',
2518 'fnServerData',
2519 'sScrollX',
2520 'sScrollY',
2521 'bScrollCollapse',
2522 'sScrollXInner',
2523 'sCookiePrefix',
2524 'aLengthMenu',
2525 'fnFormatNumber',
2526 'bRetrieve',
2527 'bDestroy',
2528 'aTargets',
2529 'fnCookieCallback',
2530 'fnInfoCallback',
2531 'bScrollInfinite',
2532 'iScrollLoadGap',
2533 'fnStateLoadCallback',
2534 'fnStateSaveCallback',
2535 'bDeferRender',
2536 'mDataProp',
2537 'mData',
2538 'mRender',
2539 'iDeferLoading',
2540 'bSortCellsTop',
2541 'sDefaultContent',
2542 'fnPreDrawCallback',
2543 'sAjaxDataProp',
2544 'aaData',
2545 'sLoadingRecords',
2546 'sProcessing',
2547 'sLengthMenu',
2548 'sZeroRecords',
2549 'sInfo',
2550 'sInfoEmpty',
2551 'sInfoFiltered',
2552 'sInfoPostFix',
2553 'sSearch',
2554 'sUrl',
2555 'sFirst',
2556 'sPrevious',
2557 'sNext',
2558 'sLast',
2559 'sEmptyTable',
2560 'sInfoThousands',
2561 'oLanguage',
2562 'oPaginate'
2563 ];
2564
2565 var dtLinks = [
2566 'fnSettings',
2567 'fnDraw',
2568 'fnFilter',
2569 'fnSort',
2570 'fnAddData',
2571 'fnDeleteRow',
2572 'fnClearTable',
2573 'fnGetData',
2574 'fnGetPosition',
2575 'fnGetNodes',
2576 'fnOpen',
2577 'fnClose',
2578 'fnUpdate',
2579 'fnSetColumnVis',
2580 'fnVersionCheck',
2581 'fnPageChange',
2582 'fnSortListener',
2583 'fnDestroy',
2584 'fnAdjustColumnSizing',
2585 'bPaginate',
2586 'bLengthChange',
2587 'bFilter',
2588 'bSort',
2589 'bInfo',
2590 'bProcessing',
2591 'bAutoWidth',
2592 'bSortClasses',
2593 'bStateSave',
2594 'fnRowCallback',
2595 'fnDrawCallback',
2596 'fnHeaderCallback',
2597 'fnFooterCallback',
2598 'fnInitComplete',
2599 'fnServerParams',
2600 'iDisplayLength',
2601 'aaSorting',
2602 'sPaginationType',
2603 'sDom',
2604 'sAjaxSource',
2605 'iCookieDuration',
2606 'asStripClasses',
2607 'bVisible',
2608 'bSearchable',
2609 'bSortable',
2610 'sTitle',
2611 'sWidth',
2612 'sClass',
2613 'fnRender',
2614 'sType',
2615 'iDataSort',
2616 'bUseRendered',
2617 'bServerSide',
2618 'sAjaxSource',
2619 'fnServerData',
2620 'aaSortingFixed',
2621 'oSearch',
2622 'aoSearchCols',
2623 'sName',
2624 'bJQueryUI',
2625 'iDisplayStart',
2626 'asSorting',
2627 'sSortDataType',
2628 'fnServerData',
2629 'sScrollX',
2630 'sScrollY',
2631 'bScrollCollapse',
2632 'sScrollXInner',
2633 'sCookiePrefix',
2634 'aLengthMenu',
2635 'fnFormatNumber',
2636 'bRetrieve',
2637 'bDestroy',
2638 'aTargets',
2639 'fnCookieCallback',
2640 'fnInfoCallback',
2641 'bScrollInfinite',
2642 'iScrollLoadGap',
2643 'fnStateLoadCallback',
2644 'fnStateSaveCallback',
2645 'bDeferRender',
2646 'mDataProp',
2647 'mData',
2648 'mRender',
2649 'iDeferLoading',
2650 'bSortCellsTop',
2651 'sDefaultContent',
2652 'fnPreDrawCallback',
2653 'sAjaxDataProp',
2654 'aaData',
2655 'oLanguage.sLoadingRecords',
2656 'oLanguage.sProcessing',
2657 'oLanguage.sLengthMenu',
2658 'oLanguage.sZeroRecords',
2659 'oLanguage.sInfo',
2660 'oLanguage.sInfoEmpty',
2661 'oLanguage.sInfoFiltered',
2662 'oLanguage.sInfoPostFix',
2663 'oLanguage.sSearch',
2664 'oLanguage.sUrl',
2665 'oLanguage.oPaginate.sFirst',
2666 'oLanguage.oPaginate.sPrevious',
2667 'oLanguage.oPaginate.sNext',
2668 'oLanguage.oPaginate.sLast',
2669 'oLanguage.sEmptyTable',
2670 'oLanguage.sInfoThousands',
2671 'oLanguage',
2672 'oPaginate'
2673 ];
2674         
2675         /* Add a class to all the strings which are DataTables init options or API methods */
2676         var dtList = '"'+ dtOptions.join( '" "' ) +'"';
2677         $('code.string').each( function () {
2678                 if ( dtList.indexOf( this.innerHTML ) !== -1 ) {
2679                         $(this).addClass( 'datatables_ref' );
2680                 }
2681         } );
2682         
2683         $('code.dtapi').each( function () {
2684                 if ( dtList.indexOf( this.innerHTML ) !== -1 ) {
2685                         $(this).addClass( 'datatables_ref' );
2686                 }
2687         } );
2688         
2689         /* Click handler to redirect to the documentation */
2690         $('code.datatables_ref').live('click', function () {
2691                 var i = $.inArray( this.innerHTML.replace(/"/g,''), dtOptions );
2692                 if ( i !== -1 ) {
2693                         window.location.href = "http://datatables.net/ref#"+dtLinks[i];
2694                 }
2695         } );
2696 } );
2697
2698 /* Show and syntax highlight XHR returns from the server */
2699 $(document).ready( function () {
2700         if ( $.fn.dataTableSettings.length >= 1 ) {
2701                 $('#example').bind('xhr', function ( e, oSettings, json ) {
2702                         var n = document.getElementById('latest_xhr');
2703                         if ( n ) {
2704                                 n.innerHTML = JSON.stringify( json, null, 2 );
2705                                 n.className = "brush: js;"
2706                                 SyntaxHighlighter.highlight({}, n);
2707                         }
2708                 } );
2709         }
2710 } );