<NME> run_prettify.js <BEF> /** * @license * Copyright (C) 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview * <div style="white-space: pre"> * Looks at query parameters to decide which language handlers and style-sheets * to load. * * Query Parameter Format Effect Default * +------------------+---------------+------------------------------+--------+ * | autorun= | true | false | If true then prettyPrint() | "true" | * | | | is called on page load. | | * +------------------+---------------+------------------------------+--------+ * | lang= | language name | Loads the language handler | Can | * | | | named "lang-<NAME>.js". | appear | * | | | See available handlers at | many | * | | | https://github.com/google/ | times. | * | | | code-prettify/tree/master/ | | * | | | src | | * +------------------+---------------+------------------------------+--------+ * | skin= | skin name | Loads the skin stylesheet | none. | * | | | named "<NAME>.css". | | * | | | https://raw.githack.com/ | | * | | | google/code-prettify/master/ | | * | | | styles/index.html | | * +------------------+---------------+------------------------------+--------+ * | callback= | JS identifier | When "prettyPrint" finishes | none | * | | | window.exports[js_ident] is | | * | | | called. | | * | | | The callback must be under | | * | | | exports to reduce the risk | | * | | | of XSS via query parameter | | * | | | injection. | | * +------------------+---------------+------------------------------+--------+ * * Examples * .../run_prettify.js?lang=css&skin=sunburst * 1. Loads the CSS language handler which can be used to prettify CSS * stylesheets, HTML <style> element bodies and style="..." attributes * values. * 2. Loads the sunburst.css stylesheet instead of the default prettify.css * stylesheet. * A gallery of stylesheets is available at * https://raw.githack.com/google/code-prettify/master/styles/index.html * 3. Since autorun=false is not specified, calls prettyPrint() on page load. * </div> */ /** * @typedef {!Array.<number|string>} * Alternating indices and the decorations that should be inserted there. * The indices are monotonically increasing. */ var DecorationsT; /** * @typedef {!{ * sourceNode: !Element, * pre: !(number|boolean), * langExtension: ?string, * numberLines: ?(number|boolean), * sourceCode: ?string, * spans: ?(Array.<number|Node>), * basePos: ?number, * decorations: ?DecorationsT * }} * <dl> * <dt>sourceNode<dd>the element containing the source * <dt>sourceCode<dd>source as plain text * <dt>pre<dd>truthy if white-space in text nodes * should be considered significant. * <dt>spans<dd> alternating span start indices into source * and the text node or element (e.g. {@code <BR>}) corresponding to that * span. * <dt>decorations<dd>an array of style classes preceded * by the position at which they start in job.sourceCode in order * <dt>basePos<dd>integer position of this.sourceCode in the larger chunk of * source. * </dl> */ var JobT; /** * @typedef {!{ * sourceCode: string, * spans: !(Array.<number|Node>) * }} * <dl> * <dt>sourceCode<dd>source as plain text * <dt>spans<dd> alternating span start indices into source * and the text node or element (e.g. {@code <BR>}) corresponding to that * span. * </dl> */ var SourceSpansT; /** @define {boolean} */ var IN_GLOBAL_SCOPE = false; (function () { "use strict"; var win = window; var doc = document; var root = doc.documentElement; var head = doc['head'] || doc.getElementsByTagName("head")[0] || root; // From http://javascript.nwbox.com/ContentLoaded/contentloaded.js // Author: Diego Perini (diego.perini at gmail.com) // Summary: cross-browser wrapper for DOMContentLoaded // Updated: 20101020 // License: MIT // Version: 1.2 function contentLoaded(callback) { var addEventListener = doc['addEventListener']; var done = false, top = true, add = addEventListener ? 'addEventListener' : 'attachEvent', rem = addEventListener ? 'removeEventListener' : 'detachEvent', pre = addEventListener ? '' : 'on', init = function(e) { if (e.type == 'readystatechange' && doc.readyState != 'complete') { return; } (e.type == 'load' ? win : doc)[rem](pre + e.type, init, false); if (!done && (done = true)) { callback.call(win, e.type || e); } }, poll = function() { try { root.doScroll('left'); } catch(e) { win.setTimeout(poll, 50); return; } init('poll'); }; if (doc.readyState == 'complete') { callback.call(win, 'lazy'); } else { if (doc.createEventObject && root.doScroll) { try { top = !win.frameElement; } catch(e) { } if (top) { poll(); } } doc[add](pre + 'DOMContentLoaded', init, false); doc[add](pre + 'readystatechange', init, false); win[add](pre + 'load', init, false); } } // Given a list of URLs to stylesheets, loads the first that loads without // triggering an error event. function loadStylesheetsFallingBack(stylesheets) { var n = stylesheets.length; function load(i) { if (i === n) { return; } var link = doc.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; if (i + 1 < n) { // http://pieisgood.org/test/script-link-events/ indicates that many // versions of IE do not support onerror on <link>s, though // http://msdn.microsoft.com/en-us/library/ie/ms535848(v=vs.85).aspx // indicates that recent IEs do support error. link.error = link.onerror = function () { load(i + 1); }; } link.href = stylesheets[i]; head.appendChild(link); } load(0); } var scriptQuery = ''; // Look for the <script> node that loads this script to get its parameters. // This starts looking at the end instead of just considering the last // because deferred and async scripts run out of order. // If the script is loaded twice, then this will run in reverse order. var scripts = doc.getElementsByTagName('script'); for (var i = scripts.length; --i >= 0;) { var script = scripts[i]; var match = script.src.match( /^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/); if (match) { scriptQuery = match[1] || ''; // Remove the script from the DOM so that multiple runs at least run // multiple times even if parameter sets are interpreted in reverse // order. script.parentNode.removeChild(script); break; } } // Pull parameters into local variables. var autorun = true; var langs = []; var skins = []; var callbacks = []; scriptQuery.replace( /[?&]([^&=]+)=([^&]+)/g, function (_, name, value) { value = decodeURIComponent(value); name = decodeURIComponent(name); if (name == 'autorun') { autorun = !/^[0fn]/i.test(value); } else if (name == 'lang') { langs.push(value); } else if (name == 'skin') { skins.push(value); } else if (name == 'callback') { callbacks.push(value); } }); // Use https to avoid mixed content warnings in client pages and to // prevent a MITM from rewrite prettify mid-flight. // This only works if this script is loaded via https : something // over which we exercise no control. var LOADER_BASE_URL = 'https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader'; for (var i = 0, n = langs.length; i < n; ++i) (function (lang) { var script = doc.createElement("script"); // Excerpted from jQuery.ajaxTransport("script") to fire events when // a script is finished loading. // Attach handlers for each script script.onload = script.onerror = script.onreadystatechange = function () { if (script && ( !script.readyState || /loaded|complete/.test(script.readyState))) { // Handle memory leak in IE script.onerror = script.onload = script.onreadystatechange = null; --pendingLanguages; checkPendingLanguages(); // Remove the script if (script.parentNode) { script.parentNode.removeChild(script); } script = null; } }; script.type = 'text/javascript'; script.src = LOADER_BASE_URL + '/lang-' + encodeURIComponent(langs[i]) + '.js'; // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending head.insertBefore(script, head.firstChild); })(langs[i]); var pendingLanguages = langs.length; function checkPendingLanguages() { if (!pendingLanguages) { win.setTimeout(onLangsLoaded, 0); } } var skinUrls = []; for (var i = 0, n = skins.length; i < n; ++i) { skinUrls.push(LOADER_BASE_URL + '/skins/' + encodeURIComponent(skins[i]) + '.css'); } skinUrls.push(LOADER_BASE_URL + '/prettify.css'); loadStylesheetsFallingBack(skinUrls); var prettyPrint = (function () { /** * @license * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview * some functions for browser-side pretty printing of code contained in html. * * <p> * For a fairly comprehensive set of languages see the * <a href="https://github.com/google/code-prettify#for-which-languages-does-it-work">README</a> * file that came with this source. At a minimum, the lexer should work on a * number of languages including C and friends, Java, Python, Bash, SQL, HTML, * XML, CSS, Javascript, and Makefiles. It works passably on Ruby, PHP and Awk * and a subset of Perl, but, because of commenting conventions, doesn't work on * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class. * <p> * Usage: <ol> * <li> include this source file in an html page via * {@code <script type="text/javascript" src="/path/to/prettify.js"></script>} * <li> define style rules. See the example page for examples. * <li> mark the {@code <pre>} and {@code <code>} tags in your source with * {@code class=prettyprint.} * You can also use the (html deprecated) {@code <xmp>} tag, but the pretty * printer needs to do more substantial DOM manipulations to support that, so * some css styles may not be preserved. * </ol> * That's it. I wanted to keep the API as simple as possible, so there's no * need to specify which language the code is in, but if you wish, you can add * another class to the {@code <pre>} or {@code <code>} element to specify the * language, as in {@code <pre class="prettyprint lang-java">}. Any class that * starts with "lang-" followed by a file extension, specifies the file type. * See the "lang-*.js" files in this directory for code that implements * per-language file handlers. * <p> * Change log:<br> * cbeust, 2006/08/22 * <blockquote> * Java annotations (start with "@") are now captured as literals ("lit") * </blockquote> * @requires console */ // JSLint declarations /*global console, document, navigator, setTimeout, window, define */ /** * {@type !{ * 'createSimpleLexer': function (Array, Array): (function (JobT)), * 'registerLangHandler': function (function (JobT), Array.<string>), * 'PR_ATTRIB_NAME': string, * 'PR_ATTRIB_NAME': string, * 'PR_ATTRIB_VALUE': string, * 'PR_COMMENT': string, * 'PR_DECLARATION': string, * 'PR_KEYWORD': string, * 'PR_LITERAL': string, * 'PR_NOCODE': string, * 'PR_PLAIN': string, * 'PR_PUNCTUATION': string, * 'PR_SOURCE': string, * 'PR_STRING': string, * 'PR_TAG': string, * 'PR_TYPE': string, * 'prettyPrintOne': function (string, string, number|boolean), * 'prettyPrint': function (?function, ?(HTMLElement|HTMLDocument)) * }} * @const */ var PR; /** * Split {@code prettyPrint} into multiple timeouts so as not to interfere with * UI events. * If set to {@code false}, {@code prettyPrint()} is synchronous. */ var PR_SHOULD_USE_CONTINUATION = true if (typeof window !== 'undefined') { window['PR_SHOULD_USE_CONTINUATION'] = PR_SHOULD_USE_CONTINUATION; } /** * Pretty print a chunk of code. * @param {string} sourceCodeHtml The HTML to pretty print. * @param {string} opt_langExtension The language name to use. * Typically, a filename extension like 'cpp' or 'java'. * @param {number|boolean} opt_numberLines True to number lines, * or the 1-indexed number of the first line in sourceCodeHtml. * @return {string} code as html, but prettier */ var prettyPrintOne; /** * Find all the {@code <pre>} and {@code <code>} tags in the DOM with * {@code class=prettyprint} and prettify them. * * @param {Function} opt_whenDone called when prettifying is done. * @param {HTMLElement|HTMLDocument} opt_root an element or document * containing all the elements to pretty print. * Defaults to {@code document.body}. */ var prettyPrint; (function () { var win = (typeof window !== 'undefined') ? window : {}; // Keyword lists for various languages. // We use things that coerce to strings to make them compact when minified // and to defeat aggressive optimizers that fold large string constants. var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"]; var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," + "double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed," + "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"]; var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," + "new,operator,private,protected,public,this,throw,true,try,typeof"]; var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignas,alignof,align_union,asm,axiom,bool," + "concept,concept_map,const_cast,constexpr,decltype,delegate," + "dynamic_cast,explicit,export,friend,generic,late_check," + "mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert," + "static_cast,template,typeid,typename,using,virtual,where"]; var JAVA_KEYWORDS = [COMMON_KEYWORDS, "abstract,assert,boolean,byte,extends,finally,final,implements,import," + "instanceof,interface,null,native,package,strictfp,super,synchronized," + "throws,transient"]; var CSHARP_KEYWORDS = [COMMON_KEYWORDS, "abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending," + "dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface," + "internal,into,is,join,let,lock,null,object,out,override,orderby,params," + "partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong," + "unchecked,unsafe,ushort,value,var,virtual,where,yield"]; var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," + "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," + "throw,true,try,unless,until,when,while,yes"; var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS, "abstract,async,await,constructor,debugger,enum,eval,export,function," + "get,implements,instanceof,interface,let,null,set,undefined,var,with," + "yield,Infinity,NaN"]; var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," + "goto,if,import,last,local,my,next,no,our,print,package,redo,require," + "sub,undef,unless,until,use,wantarray,while,BEGIN,END"; var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "and,as,assert,class,def,del," + "elif,except,exec,finally,from,global,import,in,is,lambda," + "nonlocal,not,or,pass,print,raise,try,with,yield," + "False,True,None"]; var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," + "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," + "rescue,retry,self,super,then,true,undef,unless,until,when,yield," + "BEGIN,END"]; var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," + "function,in,local,set,then,until"]; var ALL_KEYWORDS = [ CPP_KEYWORDS, CSHARP_KEYWORDS, JAVA_KEYWORDS, JSCRIPT_KEYWORDS, PERL_KEYWORDS, PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS]; var C_TYPES = /^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\d*)\b/; // token style names. correspond to css classes /** * token style for a string literal * @const */ var PR_STRING = 'str'; /** * token style for a keyword * @const */ var PR_KEYWORD = 'kwd'; /** * token style for a comment * @const */ var PR_COMMENT = 'com'; /** * token style for a type * @const */ var PR_TYPE = 'typ'; /** * token style for a literal value. e.g. 1, null, true. * @const */ var PR_LITERAL = 'lit'; /** * token style for a punctuation string. * @const */ var PR_PUNCTUATION = 'pun'; /** * token style for plain text. * @const */ var PR_PLAIN = 'pln'; /** * token style for an sgml tag. * @const */ var PR_TAG = 'tag'; /** * token style for a markup declaration such as a DOCTYPE. * @const */ var PR_DECLARATION = 'dec'; /** * token style for embedded source. * @const */ var PR_SOURCE = 'src'; /** * token style for an sgml attribute name. * @const */ var PR_ATTRIB_NAME = 'atn'; /** * token style for an sgml attribute value. * @const */ var PR_ATTRIB_VALUE = 'atv'; /** * A class that indicates a section of markup that is not code, e.g. to allow * embedding of line numbers within code listings. * @const */ var PR_NOCODE = 'nocode'; // Regex pattern below is automatically generated by regexpPrecederPatterns.pl // Do not modify, your changes will be erased. // CAVEAT: this does not properly handle the case where a regular // expression immediately follows another since a regular expression may // have flags for case-sensitivity and the like. Having regexp tokens // adjacent is not valid in any language I'm aware of, so I'm punting. // TODO: maybe style special characters inside a regexp as punctuation. /** * A set of tokens that can precede a regular expression literal in * javascript * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html * has the full list, but I've removed ones that might be problematic when * seen in languages that don't support regular expression literals. * * Specifically, I've removed any keywords that can't precede a regexp * literal in a syntactically legal javascript program, and I've removed the * "in" keyword since it's not a keyword in many languages, and might be used * as a count of inches. * * The link above does not accurately describe EcmaScript rules since * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works * very well in practice. * * @private * @const */ var REGEXP_PRECEDER_PATTERN = '(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*'; /** * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally * matches the union of the sets of strings matched by the input RegExp. * Since it matches globally, if the input strings have a start-of-input * anchor (/^.../), it is ignored for the purposes of unioning. * @param {Array.<RegExp>} regexs non multiline, non-global regexs. * @return {RegExp} a global regex. */ function combinePrefixPatterns(regexs) { var capturedGroupIndex = 0; var needToFoldCase = false; var ignoreCase = false; for (var i = 0, n = regexs.length; i < n; ++i) { var regex = regexs[i]; if (regex.ignoreCase) { ignoreCase = true; } else if (/[a-z]/i.test(regex.source.replace( /\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi, ''))) { needToFoldCase = true; ignoreCase = false; break; } } var escapeCharToCodeUnit = { 'b': 8, 't': 9, 'n': 0xa, 'v': 0xb, 'f': 0xc, 'r': 0xd }; function decodeEscape(charsetPart) { var cc0 = charsetPart.charCodeAt(0); if (cc0 !== 92 /* \\ */) { return cc0; } var c1 = charsetPart.charAt(1); cc0 = escapeCharToCodeUnit[c1]; if (cc0) { return cc0; } else if ('0' <= c1 && c1 <= '7') { return parseInt(charsetPart.substring(1), 8); } else if (c1 === 'u' || c1 === 'x') { return parseInt(charsetPart.substring(2), 16); } else { return charsetPart.charCodeAt(1); } } function encodeEscape(charCode) { if (charCode < 0x20) { return (charCode < 0x10 ? '\\x0' : '\\x') + charCode.toString(16); } var ch = String.fromCharCode(charCode); return (ch === '\\' || ch === '-' || ch === ']' || ch === '^') ? "\\" + ch : ch; } function caseFoldCharset(charSet) { var charsetParts = charSet.substring(1, charSet.length - 1).match( new RegExp( '\\\\u[0-9A-Fa-f]{4}' + '|\\\\x[0-9A-Fa-f]{2}' + '|\\\\[0-3][0-7]{0,2}' + '|\\\\[0-7]{1,2}' + '|\\\\[\\s\\S]' + '|-' + '|[^-\\\\]', 'g')); var ranges = []; var inverse = charsetParts[0] === '^'; var out = ['[']; if (inverse) { out.push('^'); } for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) { var p = charsetParts[i]; if (/\\[bdsw]/i.test(p)) { // Don't muck with named groups. out.push(p); } else { var start = decodeEscape(p); var end; if (i + 2 < n && '-' === charsetParts[i + 1]) { end = decodeEscape(charsetParts[i + 2]); i += 2; } else { end = start; } ranges.push([start, end]); // If the range might intersect letters, then expand it. // This case handling is too simplistic. // It does not deal with non-latin case folding. // It works for latin source code identifiers though. if (!(end < 65 || start > 122)) { if (!(end < 65 || start > 90)) { ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]); } if (!(end < 97 || start > 122)) { ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]); } } } } // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]] // -> [[1, 12], [14, 14], [16, 17]] ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1] - a[1]); }); var consolidatedRanges = []; var lastRange = []; for (var i = 0; i < ranges.length; ++i) { var range = ranges[i]; if (range[0] <= lastRange[1] + 1) { lastRange[1] = Math.max(lastRange[1], range[1]); } else { consolidatedRanges.push(lastRange = range); } } for (var i = 0; i < consolidatedRanges.length; ++i) { var range = consolidatedRanges[i]; out.push(encodeEscape(range[0])); if (range[1] > range[0]) { if (range[1] + 1 > range[0]) { out.push('-'); } out.push(encodeEscape(range[1])); } } out.push(']'); return out.join(''); } function allowAnywhereFoldCaseAndRenumberGroups(regex) { // Split into character sets, escape sequences, punctuation strings // like ('(', '(?:', ')', '^'), and runs of characters that do not // include any of the above. var parts = regex.source.match( new RegExp( '(?:' + '\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]' // a character set + '|\\\\u[A-Fa-f0-9]{4}' // a unicode escape + '|\\\\x[A-Fa-f0-9]{2}' // a hex escape + '|\\\\[0-9]+' // a back-reference or octal escape + '|\\\\[^ux0-9]' // other escape sequence + '|\\(\\?[:!=]' // start of a non-capturing group + '|[\\(\\)\\^]' // start/end of a group, or line start + '|[^\\x5B\\x5C\\(\\)\\^]+' // run of other characters + ')', 'g')); var n = parts.length; // Maps captured group numbers to the number they will occupy in // the output or to -1 if that has not been determined, or to // undefined if they need not be capturing in the output. var capturedGroups = []; // Walk over and identify back references to build the capturedGroups // mapping. for (var i = 0, groupIndex = 0; i < n; ++i) { var p = parts[i]; if (p === '(') { // groups are 1-indexed, so max group index is count of '(' ++groupIndex; } else if ('\\' === p.charAt(0)) { var decimalValue = +p.substring(1); if (decimalValue) { if (decimalValue <= groupIndex) { capturedGroups[decimalValue] = -1; } else { // Replace with an unambiguous escape sequence so that // an octal escape sequence does not turn into a backreference // to a capturing group from an earlier regex. parts[i] = encodeEscape(decimalValue); } } } } // Renumber groups and reduce capturing groups to non-capturing groups // where possible. for (var i = 1; i < capturedGroups.length; ++i) { if (-1 === capturedGroups[i]) { capturedGroups[i] = ++capturedGroupIndex; } } for (var i = 0, groupIndex = 0; i < n; ++i) { var p = parts[i]; if (p === '(') { ++groupIndex; if (!capturedGroups[groupIndex]) { parts[i] = '(?:'; } } else if ('\\' === p.charAt(0)) { var decimalValue = +p.substring(1); if (decimalValue && decimalValue <= groupIndex) { parts[i] = '\\' + capturedGroups[decimalValue]; } } } // Remove any prefix anchors so that the output will match anywhere. // ^^ really does mean an anchored match though. for (var i = 0; i < n; ++i) { if ('^' === parts[i] && '^' !== parts[i + 1]) { parts[i] = ''; } } // Expand letters to groups to handle mixing of case-sensitive and // case-insensitive patterns if necessary. if (regex.ignoreCase && needToFoldCase) { for (var i = 0; i < n; ++i) { var p = parts[i]; var ch0 = p.charAt(0); if (p.length >= 2 && ch0 === '[') { parts[i] = caseFoldCharset(p); } else if (ch0 !== '\\') { // TODO: handle letters in numeric escapes. parts[i] = p.replace( /[a-zA-Z]/g, function (ch) { var cc = ch.charCodeAt(0); return '[' + String.fromCharCode(cc & ~32, cc | 32) + ']'; }); } } } return parts.join(''); } var rewritten = []; for (var i = 0, n = regexs.length; i < n; ++i) { var regex = regexs[i]; if (regex.global || regex.multiline) { throw new Error('' + regex); } rewritten.push( '(?:' + allowAnywhereFoldCaseAndRenumberGroups(regex) + ')'); } return new RegExp(rewritten.join('|'), ignoreCase ? 'gi' : 'g'); } /** * Split markup into a string of source code and an array mapping ranges in * that string to the text nodes in which they appear. * * <p> * The HTML DOM structure:</p> * <pre> * (Element "p" * (Element "b" * (Text "print ")) ; #1 * (Text "'Hello '") ; #2 * (Element "br") ; #3 * (Text " + 'World';")) ; #4 * </pre> * <p> * corresponds to the HTML * {@code <p><b>print </b>'Hello '<br> + 'World';</p>}.</p> * * <p> * It will produce the output:</p> * <pre> * { * sourceCode: "print 'Hello '\n + 'World';", * // 1 2 * // 012345678901234 5678901234567 * spans: [0, #1, 6, #2, 14, #3, 15, #4] * } * </pre> * <p> * where #1 is a reference to the {@code "print "} text node above, and so * on for the other text nodes. * </p> * * <p> * The {@code} spans array is an array of pairs. Even elements are the start * indices of substrings, and odd elements are the text nodes (or BR elements) * that contain the text for those substrings. * Substrings continue until the next index or the end of the source. * </p> * * @param {Node} node an HTML DOM subtree containing source-code. * @param {boolean|number} isPreformatted truthy if white-space in * text nodes should be considered significant. * @return {SourceSpansT} source code and the nodes in which they occur. */ function extractSourceSpans(node, isPreformatted) { var nocode = /(?:^|\s)nocode(?:\s|$)/; var chunks = []; var length = 0; var spans = []; var k = 0; function walk(node) { var type = node.nodeType; if (type == 1) { // Element if (nocode.test(node.className)) { return; } for (var child = node.firstChild; child; child = child.nextSibling) { walk(child); } var nodeName = node.nodeName.toLowerCase(); if ('br' === nodeName || 'li' === nodeName) { chunks[k] = '\n'; spans[k << 1] = length++; spans[(k++ << 1) | 1] = node; } } else if (type == 3 || type == 4) { // Text var text = node.nodeValue; if (text.length) { if (!isPreformatted) { text = text.replace(/[ \t\r\n]+/g, ' '); } else { text = text.replace(/\r\n?/g, '\n'); // Normalize newlines. } // TODO: handle tabs here? chunks[k] = text; spans[k << 1] = length; length += text.length; spans[(k++ << 1) | 1] = node; } } } walk(node); return { sourceCode: chunks.join('').replace(/\n$/, ''), spans: spans }; } /** * Apply the given language handler to sourceCode and add the resulting * decorations to out. * @param {!Element} sourceNode * @param {number} basePos the index of sourceCode within the chunk of source * whose decorations are already present on out. * @param {string} sourceCode * @param {function(JobT)} langHandler * @param {DecorationsT} out */ function appendDecorations( sourceNode, basePos, sourceCode, langHandler, out) { if (!sourceCode) { return; } /** @type {JobT} */ var job = { sourceNode: sourceNode, pre: 1, langExtension: null, numberLines: null, sourceCode: sourceCode, spans: null, basePos: basePos, decorations: null }; langHandler(job); out.push.apply(out, job.decorations); } var notWs = /\S/; /** * Given an element, if it contains only one child element and any text nodes * it contains contain only space characters, return the sole child element. * Otherwise returns undefined. * <p> * This is meant to return the CODE element in {@code <pre><code ...>} when * there is a single child element that contains all the non-space textual * content, but not to return anything where there are multiple child elements * as in {@code <pre><code>...</code><code>...</code></pre>} or when there * is textual content. */ function childContentWrapper(element) { var wrapper = undefined; for (var c = element.firstChild; c; c = c.nextSibling) { var type = c.nodeType; wrapper = (type === 1) // Element Node ? (wrapper ? element : c) : (type === 3) // Text Node ? (notWs.test(c.nodeValue) ? element : wrapper) : wrapper; } return wrapper === element ? undefined : wrapper; } /** Given triples of [style, pattern, context] returns a lexing function, * The lexing function interprets the patterns to find token boundaries and * returns a decoration list of the form * [index_0, style_0, index_1, style_1, ..., index_n, style_n] * where index_n is an index into the sourceCode, and style_n is a style * constant like PR_PLAIN. index_n-1 <= index_n, and style_n-1 applies to * all characters in sourceCode[index_n-1:index_n]. * * The stylePatterns is a list whose elements have the form * [style : string, pattern : RegExp, DEPRECATED, shortcut : string]. * * Style is a style constant like PR_PLAIN, or can be a string of the * form 'lang-FOO', where FOO is a language extension describing the * language of the portion of the token in $1 after pattern executes. * E.g., if style is 'lang-lisp', and group 1 contains the text * '(hello (world))', then that portion of the token will be passed to the * registered lisp handler for formatting. * The text before and after group 1 will be restyled using this decorator * so decorators should take care that this doesn't result in infinite * recursion. For example, the HTML lexer rule for SCRIPT elements looks * something like ['lang-js', /<[s]cript>(.+?)<\/script>/]. This may match * '<script>foo()<\/script>', which would cause the current decorator to * be called with '<script>' which would not match the same rule since * group 1 must not be empty, so it would be instead styled as PR_TAG by * the generic tag rule. The handler registered for the 'js' extension would * then be called with 'foo()', and finally, the current decorator would * be called with '<\/script>' which would not match the original rule and * so the generic tag rule would identify it as a tag. * * Pattern must only match prefixes, and if it matches a prefix, then that * match is considered a token with the same style. * * Context is applied to the last non-whitespace, non-comment token * recognized. * * Shortcut is an optional string of characters, any of which, if the first * character, gurantee that this pattern and only this pattern matches. * * @param {Array} shortcutStylePatterns patterns that always start with * a known character. Must have a shortcut string. * @param {Array} fallthroughStylePatterns patterns that will be tried in * order if the shortcut ones fail. May have shortcuts. * * @return {function (JobT)} a function that takes an undecorated job and * attaches a list of decorations. */ function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) { var shortcuts = {}; var tokenizer; (function () { var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns); var allRegexs = []; var regexKeys = {}; for (var i = 0, n = allPatterns.length; i < n; ++i) { var patternParts = allPatterns[i]; var shortcutChars = patternParts[3]; if (shortcutChars) { for (var c = shortcutChars.length; --c >= 0;) { shortcuts[shortcutChars.charAt(c)] = patternParts; } } var regex = patternParts[1]; var k = '' + regex; if (!regexKeys.hasOwnProperty(k)) { allRegexs.push(regex); regexKeys[k] = null; } } allRegexs.push(/[\0-\uffff]/); tokenizer = combinePrefixPatterns(allRegexs); })(); var nPatterns = fallthroughStylePatterns.length; /** * Lexes job.sourceCode and attaches an output array job.decorations of * style classes preceded by the position at which they start in * job.sourceCode in order. * * @type{function (JobT)} */ var decorate = function (job) { var sourceCode = job.sourceCode, basePos = job.basePos; var sourceNode = job.sourceNode; /** Even entries are positions in source in ascending order. Odd enties * are style markers (e.g., PR_COMMENT) that run from that position until * the end. * @type {DecorationsT} */ var decorations = [basePos, PR_PLAIN]; var pos = 0; // index into sourceCode var tokens = sourceCode.match(tokenizer) || []; var styleCache = {}; for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) { var token = tokens[ti]; var style = styleCache[token]; var match = void 0; var isEmbedded; if (typeof style === 'string') { isEmbedded = false; } else { var patternParts = shortcuts[token.charAt(0)]; if (patternParts) { match = token.match(patternParts[1]); style = patternParts[0]; } else { for (var i = 0; i < nPatterns; ++i) { patternParts = fallthroughStylePatterns[i]; match = token.match(patternParts[1]); if (match) { style = patternParts[0]; break; } } if (!match) { // make sure that we make progress style = PR_PLAIN; } } isEmbedded = style.length >= 5 && 'lang-' === style.substring(0, 5); if (isEmbedded && !(match && typeof match[1] === 'string')) { isEmbedded = false; style = PR_SOURCE; } if (!isEmbedded) { styleCache[token] = style; } } var tokenStart = pos; pos += token.length; if (!isEmbedded) { decorations.push(basePos + tokenStart, style); } else { // Treat group 1 as an embedded block of source code. var embeddedSource = match[1]; var embeddedSourceStart = token.indexOf(embeddedSource); var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length; if (match[2]) { // If embeddedSource can be blank, then it would match at the // beginning which would cause us to infinitely recurse on the // entire token, so we catch the right context in match[2]. embeddedSourceEnd = token.length - match[2].length; embeddedSourceStart = embeddedSourceEnd - embeddedSource.length; } var lang = style.substring(5); // Decorate the left of the embedded source appendDecorations( sourceNode, basePos + tokenStart, token.substring(0, embeddedSourceStart), decorate, decorations); // Decorate the embedded source appendDecorations( sourceNode, basePos + tokenStart + embeddedSourceStart, embeddedSource, langHandlerForExtension(lang, embeddedSource), decorations); // Decorate the right of the embedded section appendDecorations( sourceNode, basePos + tokenStart + embeddedSourceEnd, token.substring(embeddedSourceEnd), decorate, decorations); } } job.decorations = decorations; }; return decorate; } /** returns a function that produces a list of decorations from source text. * * This code treats ", ', and ` as string delimiters, and \ as a string * escape. It does not recognize perl's qq() style strings. * It has no special handling for double delimiter escapes as in basic, or * the tripled delimiters used in python, but should work on those regardless * although in those cases a single string literal may be broken up into * multiple adjacent string literals. * * It recognizes C, C++, and shell style comments. * * @param {Object} options a set of optional parameters. * @return {function (JobT)} a function that examines the source code * in the input job and builds a decoration list which it attaches to * the job. */ function sourceDecorator(options) { var shortcutStylePatterns = [], fallthroughStylePatterns = []; if (options['tripleQuotedStrings']) { // '''multi-line-string''', 'single-line-string', and double-quoted shortcutStylePatterns.push( [PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, null, '\'"']); } else if (options['multiLineStrings']) { // 'multi-line-string', "multi-line-string" shortcutStylePatterns.push( [PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, null, '\'"`']); } else { // 'single-line-string', "single-line-string" shortcutStylePatterns.push( [PR_STRING, /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, null, '"\'']); } if (options['verbatimStrings']) { // verbatim-string-literal production from the C# grammar. See issue 93. fallthroughStylePatterns.push( [PR_STRING, /^@\"(?:[^\"]|\"\")*(?:\"|$)/, null]); } var hc = options['hashComments']; if (hc) { if (options['cStyleComments']) { if (hc > 1) { // multiline hash comments shortcutStylePatterns.push( [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, '#']); } else { // Stop C preprocessor declarations at an unclosed open comment shortcutStylePatterns.push( [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/, null, '#']); } // #include <stdio.h> fallthroughStylePatterns.push( [PR_STRING, /^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/, null]); } else { shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); } } if (options['cStyleComments']) { fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); fallthroughStylePatterns.push( [PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); } var regexLiterals = options['regexLiterals']; if (regexLiterals) { /** * @const */ var regexExcls = regexLiterals > 1 ? '' // Multiline regex literals : '\n\r'; /** * @const */ var regexAny = regexExcls ? '.' : '[\\S\\s]'; /** * @const */ var REGEX_LITERAL = ( // A regular expression literal starts with a slash that is // not followed by * or / so that it is not confused with // comments. '/(?=[^/*' + regexExcls + '])' // and then contains any number of raw characters, + '(?:[^/\\x5B\\x5C' + regexExcls + ']' // escape sequences (\x5C), + '|\\x5C' + regexAny // or non-nesting character sets (\x5B\x5D); + '|\\x5B(?:[^\\x5C\\x5D' + regexExcls + ']' + '|\\x5C' + regexAny + ')*(?:\\x5D|$))+' // finally closed by a /. + '/'); fallthroughStylePatterns.push( ['lang-regex', RegExp('^' + REGEXP_PRECEDER_PATTERN + '(' + REGEX_LITERAL + ')') ]); } var types = options['types']; if (types) { fallthroughStylePatterns.push([PR_TYPE, types]); } var keywords = ("" + options['keywords']).replace(/^ | $/g, ''); if (keywords.length) { fallthroughStylePatterns.push( [PR_KEYWORD, new RegExp('^(?:' + keywords.replace(/[\s,]+/g, '|') + ')\\b'), null]); } shortcutStylePatterns.push([PR_PLAIN, /^\s+/, null, ' \r\n\t\xA0']); var punctuation = // The Bash man page says // A word is a sequence of characters considered as a single // unit by GRUB. Words are separated by metacharacters, // which are the following plus space, tab, and newline: { } // | & $ ; < > // ... // A word beginning with # causes that word and all remaining // characters on that line to be ignored. // which means that only a '#' after /(?:^|[{}|&$;<>\s])/ starts a // comment but empirically // $ echo {#} // {#} // $ echo \$# // $# // $ echo }# // }# // so /(?:^|[|&;<>\s])/ is more appropriate. // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3 // suggests that this definition is compatible with a // default mode that tries to use a single token definition // to recognize both bash/python style comments and C // preprocessor directives. // This definition of punctuation does not include # in the list of // follow-on exclusions, so # will not be broken before if preceeded // by a punctuation character. We could try to exclude # after // [|&;<>] but that doesn't seem to cause many major problems. // If that does turn out to be a problem, we should change the below // when hc is truthy to include # in the run of punctuation characters // only when not followint [|&;<>]. '^.[^\\s\\w.$@\'"`/\\\\]*'; if (options['regexLiterals']) { punctuation += '(?!\s*\/)'; } fallthroughStylePatterns.push( // TODO(mikesamuel): recognize non-latin letters and numerals in idents [PR_LITERAL, /^@[a-z_$][a-z_$@0-9]*/i, null], [PR_TYPE, /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/, null], [PR_PLAIN, /^[a-z_$][a-z_$@0-9]*/i, null], [PR_LITERAL, new RegExp( '^(?:' // A hex number + '0x[a-f0-9]+' // or an octal or decimal number, + '|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)' // possibly in scientific notation + '(?:e[+\\-]?\\d+)?' + ')' // with an optional modifier like UL for unsigned long + '[a-z]*', 'i'), null, '0123456789'], // Don't treat escaped quotes in bash as starting strings. // See issue 144. [PR_PLAIN, /^\\[\s\S]?/, null], [PR_PUNCTUATION, new RegExp(punctuation), null]); return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); } var decorateSource = sourceDecorator({ 'keywords': ALL_KEYWORDS, 'hashComments': true, 'cStyleComments': true, 'multiLineStrings': true, 'regexLiterals': true }); /** * Given a DOM subtree, wraps it in a list, and puts each line into its own * list item. * * @param {Node} node modified in place. Its content is pulled into an * HTMLOListElement, and each line is moved into a separate list item. * This requires cloning elements, so the input might not have unique * IDs after numbering. * @param {number|null|boolean} startLineNum * If truthy, coerced to an integer which is the 1-indexed line number * of the first line of code. The number of the first line will be * attached to the list. * @param {boolean} isPreformatted true iff white-space in text nodes should * be treated as significant. */ function numberLines(node, startLineNum, isPreformatted) { var nocode = /(?:^|\s)nocode(?:\s|$)/; var lineBreak = /\r\n?|\n/; var document = node.ownerDocument; var li = document.createElement('li'); while (node.firstChild) { li.appendChild(node.firstChild); } // An array of lines. We split below, so this is initialized to one // un-split line. var listItems = [li]; function walk(node) { var type = node.nodeType; if (type == 1 && !nocode.test(node.className)) { // Element if ('br' === node.nodeName.toLowerCase()) { breakAfter(node); // Discard the <BR> since it is now flush against a </LI>. if (node.parentNode) { node.parentNode.removeChild(node); } } else { for (var child = node.firstChild; child; child = child.nextSibling) { walk(child); } } } else if ((type == 3 || type == 4) && isPreformatted) { // Text var text = node.nodeValue; var match = text.match(lineBreak); if (match) { var firstLine = text.substring(0, match.index); node.nodeValue = firstLine; var tail = text.substring(match.index + match[0].length); if (tail) { var parent = node.parentNode; parent.insertBefore( document.createTextNode(tail), node.nextSibling); } breakAfter(node); if (!firstLine) { // Don't leave blank text nodes in the DOM. node.parentNode.removeChild(node); } } } } // Split a line after the given node. function breakAfter(lineEndNode) { // If there's nothing to the right, then we can skip ending the line // here, and move root-wards since splitting just before an end-tag // would require us to create a bunch of empty copies. while (!lineEndNode.nextSibling) { lineEndNode = lineEndNode.parentNode; if (!lineEndNode) { return; } } function breakLeftOf(limit, copy) { // Clone shallowly if this node needs to be on both sides of the break. var rightSide = copy ? limit.cloneNode(false) : limit; var parent = limit.parentNode; if (parent) { // We clone the parent chain. // This helps us resurrect important styling elements that cross lines. // E.g. in <i>Foo<br>Bar</i> // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>. var parentClone = breakLeftOf(parent, 1); // Move the clone and everything to the right of the original // onto the cloned parent. var next = limit.nextSibling; parentClone.appendChild(rightSide); for (var sibling = next; sibling; sibling = next) { next = sibling.nextSibling; parentClone.appendChild(sibling); } } return rightSide; } var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0); // Walk the parent chain until we reach an unattached LI. for (var parent; // Check nodeType since IE invents document fragments. (parent = copiedListItem.parentNode) && parent.nodeType === 1;) { copiedListItem = parent; } // Put it on the list of lines for later processing. listItems.push(copiedListItem); } // Split lines while there are lines left to split. for (var i = 0; // Number of lines that have been split so far. i < listItems.length; // length updated by breakAfter calls. ++i) { walk(listItems[i]); } // Make sure numeric indices show correctly. if (startLineNum === (startLineNum|0)) { listItems[0].setAttribute('value', startLineNum); } var ol = document.createElement('ol'); ol.className = 'linenums'; var offset = Math.max(0, ((startLineNum - 1 /* zero index */)) | 0) || 0; for (var i = 0, n = listItems.length; i < n; ++i) { li = listItems[i]; // Stick a class on the LIs so that stylesheets can // color odd/even rows, or any other row pattern that // is co-prime with 10. li.className = 'L' + ((i + offset) % 10); if (!li.firstChild) { li.appendChild(document.createTextNode('\xA0')); } ol.appendChild(li); } node.appendChild(ol); } /** * Breaks {@code job.sourceCode} around style boundaries in * {@code job.decorations} and modifies {@code job.sourceNode} in place. * @param {JobT} job * @private */ function recombineTagsAndDecorations(job) { var isIE8OrEarlier = /\bMSIE\s(\d+)/.exec(navigator.userAgent); isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8; var newlineRe = /\n/g; var source = job.sourceCode; var sourceLength = source.length; // Index into source after the last code-unit recombined. var sourceIndex = 0; var spans = job.spans; var nSpans = spans.length; // Index into spans after the last span which ends at or before sourceIndex. var spanIndex = 0; var decorations = job.decorations; var nDecorations = decorations.length; // Index into decorations after the last decoration which ends at or before // sourceIndex. var decorationIndex = 0; // Remove all zero-length decorations. decorations[nDecorations] = sourceLength; var decPos, i; for (i = decPos = 0; i < nDecorations;) { if (decorations[i] !== decorations[i + 2]) { decorations[decPos++] = decorations[i++]; decorations[decPos++] = decorations[i++]; } else { i += 2; } } nDecorations = decPos; // Simplify decorations. for (i = decPos = 0; i < nDecorations;) { var startPos = decorations[i]; // Conflate all adjacent decorations that use the same style. var startDec = decorations[i + 1]; var end = i + 2; while (end + 2 <= nDecorations && decorations[end + 1] === startDec) { end += 2; } decorations[decPos++] = startPos; decorations[decPos++] = startDec; i = end; } nDecorations = decorations.length = decPos; var sourceNode = job.sourceNode; var oldDisplay = ""; if (sourceNode) { oldDisplay = sourceNode.style.display; sourceNode.style.display = 'none'; } try { var decoration = null; while (spanIndex < nSpans) { var spanStart = spans[spanIndex]; var spanEnd = /** @type{number} */ (spans[spanIndex + 2]) || sourceLength; var decEnd = decorations[decorationIndex + 2] || sourceLength; var end = Math.min(spanEnd, decEnd); var textNode = /** @type{Node} */ (spans[spanIndex + 1]); var styledText; if (textNode.nodeType !== 1 // Don't muck with <BR>s or <LI>s // Don't introduce spans around empty text nodes. && (styledText = source.substring(sourceIndex, end))) { // This may seem bizarre, and it is. Emitting LF on IE causes the // code to display with spaces instead of line breaks. // Emitting Windows standard issue linebreaks (CRLF) causes a blank // space to appear at the beginning of every line but the first. // Emitting an old Mac OS 9 line separator makes everything spiffy. if (isIE8OrEarlier) { styledText = styledText.replace(newlineRe, '\r'); } textNode.nodeValue = styledText; var document = textNode.ownerDocument; var span = document.createElement('span'); span.className = decorations[decorationIndex + 1]; var parentNode = textNode.parentNode; parentNode.replaceChild(span, textNode); span.appendChild(textNode); if (sourceIndex < spanEnd) { // Split off a text node. spans[spanIndex + 1] = textNode // TODO: Possibly optimize by using '' if there's no flicker. = document.createTextNode(source.substring(end, spanEnd)); parentNode.insertBefore(textNode, span.nextSibling); } } sourceIndex = end; if (sourceIndex >= spanEnd) { spanIndex += 2; } if (sourceIndex >= decEnd) { decorationIndex += 2; } } } finally { if (sourceNode) { sourceNode.style.display = oldDisplay; } } } /** Maps language-specific file extensions to handlers. */ var langHandlerRegistry = {}; /** Register a language handler for the given file extensions. * @param {function (JobT)} handler a function from source code to a list * of decorations. Takes a single argument job which describes the * state of the computation and attaches the decorations to it. * @param {Array.<string>} fileExtensions */ function registerLangHandler(handler, fileExtensions) { for (var i = fileExtensions.length; --i >= 0;) { var ext = fileExtensions[i]; if (!langHandlerRegistry.hasOwnProperty(ext)) { langHandlerRegistry[ext] = handler; } else if (win['console']) { console['warn']('cannot override language handler %s', ext); } } } function langHandlerForExtension(extension, source) { if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) { // Treat it as markup if the first non whitespace character is a < and // the last non-whitespace character is a >. extension = /^\s*</.test(source) ? 'default-markup' : 'default-code'; } return langHandlerRegistry[extension]; } registerLangHandler(decorateSource, ['default-code']); registerLangHandler( createSimpleLexer( [], [ [PR_PLAIN, /^[^<?]+/], [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/], [PR_COMMENT, /^<\!--[\s\S]*?(?:-\->|$)/], // Unescaped content in an unknown language ['lang-', /^<\?([\s\S]+?)(?:\?>|$)/], ['lang-', /^<%([\s\S]+?)(?:%>|$)/], [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/], ['lang-', /^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i], // Unescaped content in javascript. (Or possibly vbscript). ['lang-js', /^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i], // Contains unescaped stylesheet content ['lang-css', /^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i], ['lang-in.tag', /^(<\/?[a-z][^<>]*>)/i] ]), ['default-markup', 'htm', 'html', 'mxml', 'xhtml', 'xml', 'xsl']); registerLangHandler( createSimpleLexer( [ [PR_PLAIN, /^[\s]+/, null, ' \t\r\n'], [PR_ATTRIB_VALUE, /^(?:\"[^\"]*\"?|\'[^\']*\'?)/, null, '\"\''] ], [ [PR_TAG, /^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i], [PR_ATTRIB_NAME, /^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i], ['lang-uq.val', /^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/], [PR_PUNCTUATION, /^[=<>\/]+/], ['lang-js', /^on\w+\s*=\s*\"([^\"]+)\"/i], ['lang-js', /^on\w+\s*=\s*\'([^\']+)\'/i], ['lang-js', /^on\w+\s*=\s*([^\"\'>\s]+)/i], ['lang-css', /^style\s*=\s*\"([^\"]+)\"/i], ['lang-css', /^style\s*=\s*\'([^\']+)\'/i], ['lang-css', /^style\s*=\s*([^\"\'>\s]+)/i] ]), ['in.tag']); registerLangHandler( createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\s\S]+/]]), ['uq.val']); registerLangHandler(sourceDecorator({ 'keywords': CPP_KEYWORDS, 'hashComments': true, 'cStyleComments': true, 'types': C_TYPES }), ['c', 'cc', 'cpp', 'cxx', 'cyc', 'm']); registerLangHandler(sourceDecorator({ 'keywords': 'null,true,false' }), ['json']); registerLangHandler(sourceDecorator({ 'keywords': CSHARP_KEYWORDS, 'hashComments': true, 'cStyleComments': true, 'verbatimStrings': true, 'types': C_TYPES }), ['cs']); registerLangHandler(sourceDecorator({ 'keywords': JAVA_KEYWORDS, 'cStyleComments': true }), ['java']); registerLangHandler(sourceDecorator({ 'keywords': SH_KEYWORDS, 'hashComments': true, 'multiLineStrings': true }), ['bash', 'bsh', 'csh', 'sh']); registerLangHandler(sourceDecorator({ 'keywords': PYTHON_KEYWORDS, 'hashComments': true, 'multiLineStrings': true, 'tripleQuotedStrings': true }), ['cv', 'py', 'python']); registerLangHandler(sourceDecorator({ 'keywords': PERL_KEYWORDS, 'hashComments': true, 'multiLineStrings': true, 'regexLiterals': 2 // multiline regex literals }), ['perl', 'pl', 'pm']); registerLangHandler(sourceDecorator({ 'keywords': RUBY_KEYWORDS, 'hashComments': true, 'multiLineStrings': true, 'regexLiterals': true }), ['rb', 'ruby']); registerLangHandler(sourceDecorator({ 'keywords': JSCRIPT_KEYWORDS, 'cStyleComments': true, 'regexLiterals': true }), ['javascript', 'js', 'ts', 'typescript']); registerLangHandler(sourceDecorator({ 'keywords': COFFEE_KEYWORDS, 'hashComments': 3, // ### style block comments 'cStyleComments': true, 'multilineStrings': true, 'tripleQuotedStrings': true, 'regexLiterals': true }), ['coffee']); registerLangHandler( createSimpleLexer([], [[PR_STRING, /^[\s\S]+/]]), ['regex']); /** @param {JobT} job */ function applyDecorator(job) { var opt_langExtension = job.langExtension; try { // Extract tags, and convert the source code to plain text. var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre); /** Plain text. @type {string} */ var source = sourceAndSpans.sourceCode; job.sourceCode = source; job.spans = sourceAndSpans.spans; job.basePos = 0; // Apply the appropriate language handler langHandlerForExtension(opt_langExtension, source)(job); // Integrate the decorations and tags back into the source code, // modifying the sourceNode in place. recombineTagsAndDecorations(job); } catch (e) { if (win['console']) { console['log'](e && e['stack'] || e); } } } /** * Pretty print a chunk of code. * @param sourceCodeHtml {string} The HTML to pretty print. * @param opt_langExtension {string} The language name to use. * Typically, a filename extension like 'cpp' or 'java'. * @param opt_numberLines {number|boolean} True to number lines, * or the 1-indexed number of the first line in sourceCodeHtml. */ function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) { /** @type{number|boolean} */ var nl = opt_numberLines || false; /** @type{string|null} */ var langExtension = opt_langExtension || null; /** @type{!Element} */ var container = document.createElement('div'); // This could cause images to load and onload listeners to fire. // E.g. <img onerror="alert(1337)" src="nosuchimage.png">. // We assume that the inner HTML is from a trusted source. // The pre-tag is required for IE8 which strips newlines from innerHTML // when it is injected into a <pre> tag. // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript container.innerHTML = '<pre>' + sourceCodeHtml + '</pre>'; container = /** @type{!Element} */(container.firstChild); if (nl) { numberLines(container, nl, true); } /** @type{JobT} */ var job = { langExtension: langExtension, numberLines: nl, sourceNode: container, pre: 1, sourceCode: null, basePos: null, spans: null, decorations: null }; applyDecorator(job); return container.innerHTML; } /** * Find all the {@code <pre>} and {@code <code>} tags in the DOM with * {@code class=prettyprint} and prettify them. * * @param {Function} opt_whenDone called when prettifying is done. * @param {HTMLElement|HTMLDocument} opt_root an element or document * containing all the elements to pretty print. * Defaults to {@code document.body}. */ function $prettyPrint(opt_whenDone, opt_root) { var root = opt_root || document.body; var doc = root.ownerDocument || document; function byTagName(tn) { return root.getElementsByTagName(tn); } // fetch a list of nodes to rewrite var codeSegments = [byTagName('pre'), byTagName('code'), byTagName('xmp')]; var elements = []; for (var i = 0; i < codeSegments.length; ++i) { for (var j = 0, n = codeSegments[i].length; j < n; ++j) { elements.push(codeSegments[i][j]); } } codeSegments = null; var clock = Date; if (!clock['now']) { clock = { 'now': function () { return +(new Date); } }; } // The loop is broken into a series of continuations to make sure that we // don't make the browser unresponsive when rewriting a large page. var k = 0; var langExtensionRe = /\blang(?:uage)?-([\w.]+)(?!\S)/; var prettyPrintRe = /\bprettyprint\b/; var prettyPrintedRe = /\bprettyprinted\b/; var preformattedTagNameRe = /pre|xmp/i; var codeRe = /^code$/i; var preCodeXmpRe = /^(?:pre|code|xmp)$/i; var EMPTY = {}; function doWork() { var endTime = (win['PR_SHOULD_USE_CONTINUATION'] ? clock['now']() + 250 /* ms */ : Infinity); for (; k < elements.length && clock['now']() < endTime; k++) { var cs = elements[k]; // Look for a preceding comment like // <?prettify lang="..." linenums="..."?> var attrs = EMPTY; { for (var preceder = cs; (preceder = preceder.previousSibling);) { var nt = preceder.nodeType; // <?foo?> is parsed by HTML 5 to a comment node (8) // like <!--?foo?-->, but in XML is a processing instruction var value = (nt === 7 || nt === 8) && preceder.nodeValue; if (value ? !/^\??prettify\b/.test(value) : (nt !== 3 || /\S/.test(preceder.nodeValue))) { // Skip over white-space text nodes but not others. break; } if (value) { attrs = {}; value.replace( /\b(\w+)=([\w:.%+-]+)/g, function (_, name, value) { attrs[name] = value; }); break; } } } var className = cs.className; if ((attrs !== EMPTY || prettyPrintRe.test(className)) // Don't redo this if we've already done it. // This allows recalling pretty print to just prettyprint elements // that have been added to the page since last call. && !prettyPrintedRe.test(className)) { // make sure this is not nested in an already prettified element var nested = false; for (var p = cs.parentNode; p; p = p.parentNode) { var tn = p.tagName; if (preCodeXmpRe.test(tn) && p.className && prettyPrintRe.test(p.className)) { nested = true; break; } } if (!nested) { // Mark done. If we fail to prettyprint for whatever reason, // we shouldn't try again. cs.className += ' prettyprinted'; // If the classes includes a language extensions, use it. // Language extensions can be specified like // <pre class="prettyprint lang-cpp"> // the language extension "cpp" is used to find a language handler //
{'commit': 'diff --git a/distrib/prettify-small.zip b/distrib/prettify-small.zip\nindex 8c127eb..8efe31d 100644\nBinary files a/distrib/prettify-small.zip and b/distrib/prettify-small.zip differ\ndiff --git a/js-modules/prettify.js b/js-modules/prettify.js\nindex 0c7b245..be885a8 100644\n--- a/js-modules/prettify.js\n+++ b/js-modules/prettify.js\n@@ -149,8 +149,8 @@ var prettyPrint;\n       "throw,true,try,unless,until,when,while,yes";\n   var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n       "abstract,async,await,constructor,debugger,enum,eval,export,function," +\n-      "get,implements,instanceof,interface,let,null,set,undefined,var,with," +\n-      "yield,Infinity,NaN"];\n+      "get,import,implements,instanceof,interface,let,null,of,set,undefined," +\n+      "var,with,yield,Infinity,NaN"];\n   var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +\n       "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +\n       "sub,undef,unless,until,use,wantarray,while,BEGIN,END";\ndiff --git a/loader/prettify.js b/loader/prettify.js\nindex 958ee19..1f256fe 100644\n--- a/loader/prettify.js\n+++ b/loader/prettify.js\n@@ -33,11 +33,11 @@ for(var b=[n],p=0;p<b.length;++p)c(b[p]);d===(d|0)&&b[0].setAttribute("value",d)\n try{for(;c<n;){var h=l[c+2]||q,k=b[w+2]||q,v=Math.min(h,k),A=l[c+1],C;if(1!==A.nodeType&&(C=t.substring(f,v))){m&&(C=C.replace(d,"\\r"));A.nodeValue=C;var N=A.ownerDocument,u=N.createElement("span");u.className=b[w+1];var B=A.parentNode;B.replaceChild(u,A);u.appendChild(A);f<h&&(l[c+1]=A=N.createTextNode(t.substring(v,h)),B.insertBefore(A,u.nextSibling))}f=v;f>=h&&(c+=2);f>=k&&(w+=2)}}finally{g&&(g.style.display=a)}}catch(y){D.console&&console.log(y&&y.stack||y)}}var D="undefined"!==typeof window?\n window:{},B=["break,continue,do,else,for,if,return,while"],F=[[B,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],H=[F,"alignas,alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],\n O=[F,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],P=[F,"abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface,internal,into,is,join,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,value,var,virtual,where,yield"],\n-F=[F,"abstract,async,await,constructor,debugger,enum,eval,export,function,get,implements,instanceof,interface,let,null,set,undefined,var,with,yield,Infinity,NaN"],Q=[B,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],R=[B,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],B=[B,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],\n-S=/^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/,W=/\\S/,X=x({keywords:[H,P,O,F,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",Q,R,B],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),I={};t(X,["default-code"]);t(G([],[["pln",/^[^<?]+/],["dec",\n-/^<!\\w[^>]*(?:>|$)/],["com",/^<\\!--[\\s\\S]*?(?:-\\->|$)/],["lang-",/^<\\?([\\s\\S]+?)(?:\\?>|$)/],["lang-",/^<%([\\s\\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],["lang-js",/^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],["lang-css",/^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],["lang-in.tag",/^(<\\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));t(G([["pln",/^[\\s]+/,null," \\t\\r\\n"],["atv",/^(?:\\"[^\\"]*\\"?|\\\'[^\\\']*\\\'?)/,null,\n-"\\"\'"]],[["tag",/^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],["atn",/^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],["lang-uq.val",/^=\\s*([^>\\\'\\"\\s]*(?:[^>\\\'\\"\\s\\/]|\\/(?=\\s)))/],["pun",/^[=<>\\/]+/],["lang-js",/^on\\w+\\s*=\\s*\\"([^\\"]+)\\"/i],["lang-js",/^on\\w+\\s*=\\s*\\\'([^\\\']+)\\\'/i],["lang-js",/^on\\w+\\s*=\\s*([^\\"\\\'>\\s]+)/i],["lang-css",/^style\\s*=\\s*\\"([^\\"]+)\\"/i],["lang-css",/^style\\s*=\\s*\\\'([^\\\']+)\\\'/i],["lang-css",/^style\\s*=\\s*([^\\"\\\'>\\s]+)/i]]),["in.tag"]);t(G([],[["atv",/^[\\s\\S]+/]]),["uq.val"]);t(x({keywords:H,\n-hashComments:!0,cStyleComments:!0,types:S}),"c cc cpp cxx cyc m".split(" "));t(x({keywords:"null,true,false"}),["json"]);t(x({keywords:P,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:S}),["cs"]);t(x({keywords:O,cStyleComments:!0}),["java"]);t(x({keywords:B,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);t(x({keywords:Q,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);t(x({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",\n+F=[F,"abstract,async,await,constructor,debugger,enum,eval,export,function,get,import,implements,instanceof,interface,let,null,of,set,undefined,var,with,yield,Infinity,NaN"],Q=[B,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],R=[B,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],\n+B=[B,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],S=/^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/,W=/\\S/,X=x({keywords:[H,P,O,F,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",Q,R,B],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),\n+I={};t(X,["default-code"]);t(G([],[["pln",/^[^<?]+/],["dec",/^<!\\w[^>]*(?:>|$)/],["com",/^<\\!--[\\s\\S]*?(?:-\\->|$)/],["lang-",/^<\\?([\\s\\S]+?)(?:\\?>|$)/],["lang-",/^<%([\\s\\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],["lang-js",/^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],["lang-css",/^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],["lang-in.tag",/^(<\\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));t(G([["pln",/^[\\s]+/,\n+null," \\t\\r\\n"],["atv",/^(?:\\"[^\\"]*\\"?|\\\'[^\\\']*\\\'?)/,null,"\\"\'"]],[["tag",/^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],["atn",/^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],["lang-uq.val",/^=\\s*([^>\\\'\\"\\s]*(?:[^>\\\'\\"\\s\\/]|\\/(?=\\s)))/],["pun",/^[=<>\\/]+/],["lang-js",/^on\\w+\\s*=\\s*\\"([^\\"]+)\\"/i],["lang-js",/^on\\w+\\s*=\\s*\\\'([^\\\']+)\\\'/i],["lang-js",/^on\\w+\\s*=\\s*([^\\"\\\'>\\s]+)/i],["lang-css",/^style\\s*=\\s*\\"([^\\"]+)\\"/i],["lang-css",/^style\\s*=\\s*\\\'([^\\\']+)\\\'/i],["lang-css",/^style\\s*=\\s*([^\\"\\\'>\\s]+)/i]]),["in.tag"]);\n+t(G([],[["atv",/^[\\s\\S]+/]]),["uq.val"]);t(x({keywords:H,hashComments:!0,cStyleComments:!0,types:S}),"c cc cpp cxx cyc m".split(" "));t(x({keywords:"null,true,false"}),["json"]);t(x({keywords:P,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:S}),["cs"]);t(x({keywords:O,cStyleComments:!0}),["java"]);t(x({keywords:B,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);t(x({keywords:Q,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);t(x({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",\n hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);t(x({keywords:R,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);t(x({keywords:F,cStyleComments:!0,regexLiterals:!0}),["javascript","js","ts","typescript"]);t(x({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,\n regexLiterals:!0}),["coffee"]);t(G([],[["str",/^[\\s\\S]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:G,registerLangHandler:t,sourceDecorator:x,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,f){f=f||!1;d=d||null;var c=document.createElement("div");c.innerHTML="<pre>"+a+"</pre>";\n c=c.firstChild;f&&L(c,f,!0);M({j:d,m:f,h:c,l:1,a:null,i:null,c:null,g:null});return c.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function f(){for(var c=D.PR_SHOULD_USE_CONTINUATION?b.now()+250:Infinity;p<x.length&&b.now()<c;p++){for(var d=x[p],l=g,n=d;n=n.previousSibling;){var m=n.nodeType,u=(7===m||8===m)&&n.nodeValue;if(u?!/^\\??prettify\\b/.test(u):3!==m||/\\S/.test(n.nodeValue))break;if(u){l={};u.replace(/\\b(\\w+)=([\\w:.%+-]+)/g,function(a,b,c){l[b]=c});break}}n=d.className;if((l!==g||r.test(n))&&\ndiff --git a/loader/run_prettify.js b/loader/run_prettify.js\nindex 9a72ab3..5df0242 100644\n--- a/loader/run_prettify.js\n+++ b/loader/run_prettify.js\n@@ -50,7 +50,7 @@ p.appendChild(e);for(var f=d;f;f=d)d=f.nextSibling,p.appendChild(f)}return e}for\n g=g&&8>=+g[1],d=/\\n/g,r=a.a,k=r.length,f=0,q=a.c,n=q.length,c=0,b=a.g,t=b.length,v=0;b[t]=k;var u,e;for(e=u=0;e<t;)b[e]!==b[e+2]?(b[u++]=b[e++],b[u++]=b[e++]):e+=2;t=u;for(e=u=0;e<t;){for(var x=b[e],z=b[e+1],w=e+2;w+2<=t&&b[w+1]===z;)w+=2;b[u++]=x;b[u++]=z;e=w}b.length=u;var h=a.h;a="";h&&(a=h.style.display,h.style.display="none");try{for(;c<n;){var m=q[c+2]||k,p=b[v+2]||k,w=Math.min(m,p),C=q[c+1],G;if(1!==C.nodeType&&(G=r.substring(f,w))){g&&(G=G.replace(d,"\\r"));C.nodeValue=G;var Z=C.ownerDocument,\n W=Z.createElement("span");W.className=b[v+1];var B=C.parentNode;B.replaceChild(W,C);W.appendChild(C);f<m&&(q[c+1]=C=Z.createTextNode(r.substring(w,m)),B.insertBefore(C,W.nextSibling))}f=w;f>=m&&(c+=2);f>=p&&(v+=2)}}finally{h&&(h.style.display=a)}}catch(y){Q.console&&console.log(y&&y.stack||y)}}var Q="undefined"!==typeof window?window:{},J=["break,continue,do,else,for,if,return,while"],K=[[J,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],\n "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],R=[K,"alignas,alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],L=[K,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],\n-M=[K,"abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface,internal,into,is,join,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,value,var,virtual,where,yield"],K=[K,"abstract,async,await,constructor,debugger,enum,eval,export,function,get,implements,instanceof,interface,let,null,set,undefined,var,with,yield,Infinity,NaN"],\n+M=[K,"abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface,internal,into,is,join,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,value,var,virtual,where,yield"],K=[K,"abstract,async,await,constructor,debugger,enum,eval,export,function,get,import,implements,instanceof,interface,let,null,of,set,undefined,var,with,yield,Infinity,NaN"],\n N=[J,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],O=[J,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],J=[J,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],P=/^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/,\n S=/\\S/,T=v({keywords:[R,M,L,K,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",N,O,J],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),V={};n(T,["default-code"]);n(E([],[["pln",/^[^<?]+/],["dec",/^<!\\w[^>]*(?:>|$)/],["com",/^<\\!--[\\s\\S]*?(?:-\\->|$)/],["lang-",/^<\\?([\\s\\S]+?)(?:\\?>|$)/],["lang-",/^<%([\\s\\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",\n /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],["lang-js",/^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],["lang-css",/^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],["lang-in.tag",/^(<\\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));n(E([["pln",/^[\\s]+/,null," \\t\\r\\n"],["atv",/^(?:\\"[^\\"]*\\"?|\\\'[^\\\']*\\\'?)/,null,"\\"\'"]],[["tag",/^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],["atn",/^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],["lang-uq.val",/^=\\s*([^>\\\'\\"\\s]*(?:[^>\\\'\\"\\s\\/]|\\/(?=\\s)))/],\ndiff --git a/src/node_prettify.js b/src/node_prettify.js\nindex 588952b..325d042 100644\n--- a/src/node_prettify.js\n+++ b/src/node_prettify.js\n@@ -149,8 +149,8 @@ var prettyPrint;\n       "throw,true,try,unless,until,when,while,yes";\n   var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n       "abstract,async,await,constructor,debugger,enum,eval,export,function," +\n-      "get,implements,instanceof,interface,let,null,set,undefined,var,with," +\n-      "yield,Infinity,NaN"];\n+      "get,import,implements,instanceof,interface,let,null,of,set,undefined," +\n+      "var,with,yield,Infinity,NaN"];\n   var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +\n       "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +\n       "sub,undef,unless,until,use,wantarray,while,BEGIN,END";\ndiff --git a/src/run_prettify.js b/src/run_prettify.js\nindex 93e3fec..11a2a41 100644\n--- a/src/run_prettify.js\n+++ b/src/run_prettify.js\n@@ -426,8 +426,8 @@ var IN_GLOBAL_SCOPE = false;\n           "throw,true,try,unless,until,when,while,yes";\n       var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n           "abstract,async,await,constructor,debugger,enum,eval,export,function," +\n-          "get,implements,instanceof,interface,let,null,set,undefined,var,with," +\n-          "yield,Infinity,NaN"];\n+          "get,import,implements,instanceof,interface,let,null,of,set,undefined," +\n+          "var,with,yield,Infinity,NaN"];\n       var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +\n           "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +\n           "sub,undef,unless,until,use,wantarray,while,BEGIN,END";\n', 'commit_subject': 'patch previous commit into the files of record and rebuild derivatives', 'repo_name': 'googlearchive/code-prettify', 'committer': {'name': 'Mike Samuel', 'email': 'b0d08bfe3e749932a68a800416f0aef6cb94939a@gmail.com', 'time_sec': '1520271311', 'tz_offset': '-300', 'date': {'seconds': '1520271311'}}, 'commit_tree': 'edbbc9f1ae29fdb350f4508ae2973f4fd0ac1429', 'commit_message': 'patch previous commit into the files of record and rebuild derivatives\n', 'language_name': 'HTML', 'license': 'apache-2.0', 'hunks': '@@ -426,8 +426,8 @@ var IN_GLOBAL_SCOPE = false;\n           "throw,true,try,unless,until,when,while,yes";\n       var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n           "abstract,async,await,constructor,debugger,enum,eval,export,function," +\n-          "get,implements,instanceof,interface,let,null,set,undefined,var,with," +\n-          "yield,Infinity,NaN"];\n+          "get,import,implements,instanceof,interface,let,null,of,set,undefined," +\n+          "var,with,yield,Infinity,NaN"];\n       var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +\n           "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +\n           "sub,undef,unless,until,use,wantarray,while,BEGIN,END";\n', 'addition_count': 2, 'deletion_count': 2, 'src_file': 'a/src/run_prettify.js', 'tgt_file': 'b/src/run_prettify.js', 'file_extension': '.js', 'before_file': '/**\n * @license\n * Copyright (C) 2013 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * @fileoverview\n * <div style="white-space: pre">\n * Looks at query parameters to decide which language handlers and style-sheets\n * to load.\n *\n * Query Parameter     Format           Effect                        Default\n * +------------------+---------------+------------------------------+--------+\n * | autorun=         | true | false  | If true then prettyPrint()   | "true" |\n * |                  |               | is called on page load.      |        |\n * +------------------+---------------+------------------------------+--------+\n * | lang=            | language name | Loads the language handler   | Can    |\n * |                  |               | named "lang-<NAME>.js".      | appear |\n * |                  |               | See available handlers at    | many   |\n * |                  |               | https://github.com/google/   | times. |\n * |                  |               | code-prettify/tree/master/   |        |\n * |                  |               | src                          |        |\n * +------------------+---------------+------------------------------+--------+\n * | skin=            | skin name     | Loads the skin stylesheet    | none.  |\n * |                  |               | named "<NAME>.css".          |        |\n * |                  |               | https://raw.githack.com/     |        |\n * |                  |               | google/code-prettify/master/ |        |\n * |                  |               | styles/index.html            |        |\n * +------------------+---------------+------------------------------+--------+\n * | callback=        | JS identifier | When "prettyPrint" finishes  | none   |\n * |                  |               | window.exports[js_ident] is  |        |\n * |                  |               | called.                      |        |\n * |                  |               | The callback must be under   |        |\n * |                  |               | exports to reduce the risk   |        |\n * |                  |               | of XSS via query parameter   |        |\n * |                  |               | injection.                   |        |\n * +------------------+---------------+------------------------------+--------+\n *\n * Examples\n * .../run_prettify.js?lang=css&skin=sunburst\n *   1. Loads the CSS language handler which can be used to prettify CSS\n *      stylesheets, HTML <style> element bodies and style="..." attributes\n *      values.\n *   2. Loads the sunburst.css stylesheet instead of the default prettify.css\n *      stylesheet.\n *      A gallery of stylesheets is available at\n *      https://raw.githack.com/google/code-prettify/master/styles/index.html\n *   3. Since autorun=false is not specified, calls prettyPrint() on page load.\n * </div>\n */\n\n/**\n * @typedef {!Array.<number|string>}\n * Alternating indices and the decorations that should be inserted there.\n * The indices are monotonically increasing.\n */\nvar DecorationsT;\n\n/**\n * @typedef {!{\n *   sourceNode: !Element,\n *   pre: !(number|boolean),\n *   langExtension: ?string,\n *   numberLines: ?(number|boolean),\n *   sourceCode: ?string,\n *   spans: ?(Array.<number|Node>),\n *   basePos: ?number,\n *   decorations: ?DecorationsT\n * }}\n * <dl>\n *  <dt>sourceNode<dd>the element containing the source\n *  <dt>sourceCode<dd>source as plain text\n *  <dt>pre<dd>truthy if white-space in text nodes\n *     should be considered significant.\n *  <dt>spans<dd> alternating span start indices into source\n *     and the text node or element (e.g. {@code <BR>}) corresponding to that\n *     span.\n *  <dt>decorations<dd>an array of style classes preceded\n *     by the position at which they start in job.sourceCode in order\n *  <dt>basePos<dd>integer position of this.sourceCode in the larger chunk of\n *     source.\n * </dl>\n */\nvar JobT;\n\n/**\n * @typedef {!{\n *   sourceCode: string,\n *   spans: !(Array.<number|Node>)\n * }}\n * <dl>\n *  <dt>sourceCode<dd>source as plain text\n *  <dt>spans<dd> alternating span start indices into source\n *     and the text node or element (e.g. {@code <BR>}) corresponding to that\n *     span.\n * </dl>\n */\nvar SourceSpansT;\n\n/** @define {boolean} */\nvar IN_GLOBAL_SCOPE = false;\n\n\n(function () {\n  "use strict";\n\n  var win = window;\n  var doc = document;\n  var root = doc.documentElement;\n  var head = doc[\'head\'] || doc.getElementsByTagName("head")[0] || root;\n\n  // From http://javascript.nwbox.com/ContentLoaded/contentloaded.js\n  // Author: Diego Perini (diego.perini at gmail.com)\n  // Summary: cross-browser wrapper for DOMContentLoaded\n  // Updated: 20101020\n  // License: MIT\n  // Version: 1.2\n  function contentLoaded(callback) {\n    var addEventListener = doc[\'addEventListener\'];\n    var done = false, top = true,\n        add = addEventListener ? \'addEventListener\' : \'attachEvent\',\n        rem = addEventListener ? \'removeEventListener\' : \'detachEvent\',\n        pre = addEventListener ? \'\' : \'on\',\n\n        init = function(e) {\n          if (e.type == \'readystatechange\' && doc.readyState != \'complete\') {\n            return;\n          }\n          (e.type == \'load\' ? win : doc)[rem](pre + e.type, init, false);\n          if (!done && (done = true)) { callback.call(win, e.type || e); }\n        },\n\n        poll = function() {\n          try {\n            root.doScroll(\'left\');\n          } catch(e) {\n            win.setTimeout(poll, 50);\n            return;\n          }\n          init(\'poll\');\n        };\n\n    if (doc.readyState == \'complete\') {\n      callback.call(win, \'lazy\');\n    } else {\n      if (doc.createEventObject && root.doScroll) {\n        try { top = !win.frameElement; } catch(e) { }\n        if (top) { poll(); }\n      }\n      doc[add](pre + \'DOMContentLoaded\', init, false);\n      doc[add](pre + \'readystatechange\', init, false);\n      win[add](pre + \'load\', init, false);\n    }\n  }\n\n  // Given a list of URLs to stylesheets, loads the first that loads without\n  // triggering an error event.\n  function loadStylesheetsFallingBack(stylesheets) {\n    var n = stylesheets.length;\n    function load(i) {\n      if (i === n) { return; }\n      var link = doc.createElement(\'link\');\n      link.rel = \'stylesheet\';\n      link.type = \'text/css\';\n      if (i + 1 < n) {\n        // http://pieisgood.org/test/script-link-events/ indicates that many\n        // versions of IE do not support onerror on <link>s, though\n        // http://msdn.microsoft.com/en-us/library/ie/ms535848(v=vs.85).aspx\n        // indicates that recent IEs do support error.\n        link.error = link.onerror = function () { load(i + 1); };\n      }\n      link.href = stylesheets[i];\n      head.appendChild(link);\n    }\n    load(0);\n  }\n\n  var scriptQuery = \'\';\n  // Look for the <script> node that loads this script to get its parameters.\n  // This starts looking at the end instead of just considering the last\n  // because deferred and async scripts run out of order.\n  // If the script is loaded twice, then this will run in reverse order.\n  var scripts = doc.getElementsByTagName(\'script\');\n  for (var i = scripts.length; --i >= 0;) {\n    var script = scripts[i];\n    var match = script.src.match(\n        /^[^?#]*\\/run_prettify\\.js(\\?[^#]*)?(?:#.*)?$/);\n    if (match) {\n      scriptQuery = match[1] || \'\';\n      // Remove the script from the DOM so that multiple runs at least run\n      // multiple times even if parameter sets are interpreted in reverse\n      // order.\n      script.parentNode.removeChild(script);\n      break;\n    }\n  }\n\n  // Pull parameters into local variables.\n  var autorun = true;\n  var langs = [];\n  var skins = [];\n  var callbacks = [];\n  scriptQuery.replace(\n      /[?&]([^&=]+)=([^&]+)/g,\n      function (_, name, value) {\n        value = decodeURIComponent(value);\n        name = decodeURIComponent(name);\n        if (name == \'autorun\')   { autorun = !/^[0fn]/i.test(value); } else\n        if (name == \'lang\')      { langs.push(value);                } else\n        if (name == \'skin\')      { skins.push(value);                } else\n        if (name == \'callback\')  { callbacks.push(value);            }\n      });\n\n  // Use https to avoid mixed content warnings in client pages and to\n  // prevent a MITM from rewrite prettify mid-flight.\n  // This only works if this script is loaded via https : something\n  // over which we exercise no control.\n  var LOADER_BASE_URL =\n     \'https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader\';\n\n  for (var i = 0, n = langs.length; i < n; ++i) (function (lang) {\n    var script = doc.createElement("script");\n\n    // Excerpted from jQuery.ajaxTransport("script") to fire events when\n    // a script is finished loading.\n    // Attach handlers for each script\n    script.onload = script.onerror = script.onreadystatechange = function () {\n      if (script && (\n            !script.readyState || /loaded|complete/.test(script.readyState))) {\n        // Handle memory leak in IE\n        script.onerror = script.onload = script.onreadystatechange = null;\n\n        --pendingLanguages;\n        checkPendingLanguages();\n\n        // Remove the script\n        if (script.parentNode) {\n          script.parentNode.removeChild(script);\n        }\n\n        script = null;\n      }\n    };\n\n    script.type = \'text/javascript\';\n    script.src = LOADER_BASE_URL\n      + \'/lang-\' + encodeURIComponent(langs[i]) + \'.js\';\n\n    // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending\n    head.insertBefore(script, head.firstChild);\n  })(langs[i]);\n\n  var pendingLanguages = langs.length;\n  function checkPendingLanguages() {\n    if (!pendingLanguages) {\n      win.setTimeout(onLangsLoaded, 0);\n    }\n  }\n\n  var skinUrls = [];\n  for (var i = 0, n = skins.length; i < n; ++i) {\n    skinUrls.push(LOADER_BASE_URL\n        + \'/skins/\' + encodeURIComponent(skins[i]) + \'.css\');\n  }\n  skinUrls.push(LOADER_BASE_URL + \'/prettify.css\');\n  loadStylesheetsFallingBack(skinUrls);\n\n  var prettyPrint = (function () {\n    /**\n     * @license\n     * Copyright (C) 2006 Google Inc.\n     *\n     * Licensed under the Apache License, Version 2.0 (the "License");\n     * you may not use this file except in compliance with the License.\n     * You may obtain a copy of the License at\n     *\n     *      http://www.apache.org/licenses/LICENSE-2.0\n     *\n     * Unless required by applicable law or agreed to in writing, software\n     * distributed under the License is distributed on an "AS IS" BASIS,\n     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     * See the License for the specific language governing permissions and\n     * limitations under the License.\n     */\n\n    /**\n     * @fileoverview\n     * some functions for browser-side pretty printing of code contained in html.\n     *\n     * <p>\n     * For a fairly comprehensive set of languages see the\n     * <a href="https://github.com/google/code-prettify#for-which-languages-does-it-work">README</a>\n     * file that came with this source.  At a minimum, the lexer should work on a\n     * number of languages including C and friends, Java, Python, Bash, SQL, HTML,\n     * XML, CSS, Javascript, and Makefiles.  It works passably on Ruby, PHP and Awk\n     * and a subset of Perl, but, because of commenting conventions, doesn\'t work on\n     * Smalltalk, Lisp-like, or CAML-like languages without an explicit lang class.\n     * <p>\n     * Usage: <ol>\n     * <li> include this source file in an html page via\n     *   {@code <script type="text/javascript" src="/path/to/prettify.js"></script>}\n     * <li> define style rules.  See the example page for examples.\n     * <li> mark the {@code <pre>} and {@code <code>} tags in your source with\n     *    {@code class=prettyprint.}\n     *    You can also use the (html deprecated) {@code <xmp>} tag, but the pretty\n     *    printer needs to do more substantial DOM manipulations to support that, so\n     *    some css styles may not be preserved.\n     * </ol>\n     * That\'s it.  I wanted to keep the API as simple as possible, so there\'s no\n     * need to specify which language the code is in, but if you wish, you can add\n     * another class to the {@code <pre>} or {@code <code>} element to specify the\n     * language, as in {@code <pre class="prettyprint lang-java">}.  Any class that\n     * starts with "lang-" followed by a file extension, specifies the file type.\n     * See the "lang-*.js" files in this directory for code that implements\n     * per-language file handlers.\n     * <p>\n     * Change log:<br>\n     * cbeust, 2006/08/22\n     * <blockquote>\n     *   Java annotations (start with "@") are now captured as literals ("lit")\n     * </blockquote>\n     * @requires console\n     */\n\n    // JSLint declarations\n    /*global console, document, navigator, setTimeout, window, define */\n\n\n    /**\n     * {@type !{\n     *   \'createSimpleLexer\': function (Array, Array): (function (JobT)),\n     *   \'registerLangHandler\': function (function (JobT), Array.<string>),\n     *   \'PR_ATTRIB_NAME\': string,\n     *   \'PR_ATTRIB_NAME\': string,\n     *   \'PR_ATTRIB_VALUE\': string,\n     *   \'PR_COMMENT\': string,\n     *   \'PR_DECLARATION\': string,\n     *   \'PR_KEYWORD\': string,\n     *   \'PR_LITERAL\': string,\n     *   \'PR_NOCODE\': string,\n     *   \'PR_PLAIN\': string,\n     *   \'PR_PUNCTUATION\': string,\n     *   \'PR_SOURCE\': string,\n     *   \'PR_STRING\': string,\n     *   \'PR_TAG\': string,\n     *   \'PR_TYPE\': string,\n     *   \'prettyPrintOne\': function (string, string, number|boolean),\n     *   \'prettyPrint\': function (?function, ?(HTMLElement|HTMLDocument))\n     * }}\n     * @const\n     */\n    var PR;\n\n    /**\n     * Split {@code prettyPrint} into multiple timeouts so as not to interfere with\n     * UI events.\n     * If set to {@code false}, {@code prettyPrint()} is synchronous.\n     */\n    var PR_SHOULD_USE_CONTINUATION = true\n    if (typeof window !== \'undefined\') {\n      window[\'PR_SHOULD_USE_CONTINUATION\'] = PR_SHOULD_USE_CONTINUATION;\n    }\n\n    /**\n     * Pretty print a chunk of code.\n     * @param {string} sourceCodeHtml The HTML to pretty print.\n     * @param {string} opt_langExtension The language name to use.\n     *     Typically, a filename extension like \'cpp\' or \'java\'.\n     * @param {number|boolean} opt_numberLines True to number lines,\n     *     or the 1-indexed number of the first line in sourceCodeHtml.\n     * @return {string} code as html, but prettier\n     */\n    var prettyPrintOne;\n    /**\n     * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n     * {@code class=prettyprint} and prettify them.\n     *\n     * @param {Function} opt_whenDone called when prettifying is done.\n     * @param {HTMLElement|HTMLDocument} opt_root an element or document\n     *   containing all the elements to pretty print.\n     *   Defaults to {@code document.body}.\n     */\n    var prettyPrint;\n\n\n    (function () {\n      var win = (typeof window !== \'undefined\') ? window : {};\n      // Keyword lists for various languages.\n      // We use things that coerce to strings to make them compact when minified\n      // and to defeat aggressive optimizers that fold large string constants.\n      var FLOW_CONTROL_KEYWORDS = ["break,continue,do,else,for,if,return,while"];\n      var C_KEYWORDS = [FLOW_CONTROL_KEYWORDS,"auto,case,char,const,default," +\n          "double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed," +\n          "sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];\n      var COMMON_KEYWORDS = [C_KEYWORDS,"catch,class,delete,false,import," +\n          "new,operator,private,protected,public,this,throw,true,try,typeof"];\n      var CPP_KEYWORDS = [COMMON_KEYWORDS,"alignas,alignof,align_union,asm,axiom,bool," +\n          "concept,concept_map,const_cast,constexpr,decltype,delegate," +\n          "dynamic_cast,explicit,export,friend,generic,late_check," +\n          "mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert," +\n          "static_cast,template,typeid,typename,using,virtual,where"];\n      var JAVA_KEYWORDS = [COMMON_KEYWORDS,\n          "abstract,assert,boolean,byte,extends,finally,final,implements,import," +\n          "instanceof,interface,null,native,package,strictfp,super,synchronized," +\n          "throws,transient"];\n      var CSHARP_KEYWORDS = [COMMON_KEYWORDS,\n          "abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending," +\n          "dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface," +\n          "internal,into,is,join,let,lock,null,object,out,override,orderby,params," +\n          "partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong," +\n          "unchecked,unsafe,ushort,value,var,virtual,where,yield"];\n      var COFFEE_KEYWORDS = "all,and,by,catch,class,else,extends,false,finally," +\n          "for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then," +\n          "throw,true,try,unless,until,when,while,yes";\n      var JSCRIPT_KEYWORDS = [COMMON_KEYWORDS,\n          "abstract,async,await,constructor,debugger,enum,eval,export,function," +\n          "get,implements,instanceof,interface,let,null,set,undefined,var,with," +\n          "yield,Infinity,NaN"];\n      var PERL_KEYWORDS = "caller,delete,die,do,dump,elsif,eval,exit,foreach,for," +\n          "goto,if,import,last,local,my,next,no,our,print,package,redo,require," +\n          "sub,undef,unless,until,use,wantarray,while,BEGIN,END";\n      var PYTHON_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "and,as,assert,class,def,del," +\n          "elif,except,exec,finally,from,global,import,in,is,lambda," +\n          "nonlocal,not,or,pass,print,raise,try,with,yield," +\n          "False,True,None"];\n      var RUBY_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "alias,and,begin,case,class," +\n          "def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo," +\n          "rescue,retry,self,super,then,true,undef,unless,until,when,yield," +\n          "BEGIN,END"];\n      var SH_KEYWORDS = [FLOW_CONTROL_KEYWORDS, "case,done,elif,esac,eval,fi," +\n          "function,in,local,set,then,until"];\n      var ALL_KEYWORDS = [\n          CPP_KEYWORDS, CSHARP_KEYWORDS, JAVA_KEYWORDS, JSCRIPT_KEYWORDS,\n          PERL_KEYWORDS, PYTHON_KEYWORDS, RUBY_KEYWORDS, SH_KEYWORDS];\n      var C_TYPES = /^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\\d*)\\b/;\n\n      // token style names.  correspond to css classes\n      /**\n       * token style for a string literal\n       * @const\n       */\n      var PR_STRING = \'str\';\n      /**\n       * token style for a keyword\n       * @const\n       */\n      var PR_KEYWORD = \'kwd\';\n      /**\n       * token style for a comment\n       * @const\n       */\n      var PR_COMMENT = \'com\';\n      /**\n       * token style for a type\n       * @const\n       */\n      var PR_TYPE = \'typ\';\n      /**\n       * token style for a literal value.  e.g. 1, null, true.\n       * @const\n       */\n      var PR_LITERAL = \'lit\';\n      /**\n       * token style for a punctuation string.\n       * @const\n       */\n      var PR_PUNCTUATION = \'pun\';\n      /**\n       * token style for plain text.\n       * @const\n       */\n      var PR_PLAIN = \'pln\';\n\n      /**\n       * token style for an sgml tag.\n       * @const\n       */\n      var PR_TAG = \'tag\';\n      /**\n       * token style for a markup declaration such as a DOCTYPE.\n       * @const\n       */\n      var PR_DECLARATION = \'dec\';\n      /**\n       * token style for embedded source.\n       * @const\n       */\n      var PR_SOURCE = \'src\';\n      /**\n       * token style for an sgml attribute name.\n       * @const\n       */\n      var PR_ATTRIB_NAME = \'atn\';\n      /**\n       * token style for an sgml attribute value.\n       * @const\n       */\n      var PR_ATTRIB_VALUE = \'atv\';\n\n      /**\n       * A class that indicates a section of markup that is not code, e.g. to allow\n       * embedding of line numbers within code listings.\n       * @const\n       */\n      var PR_NOCODE = \'nocode\';\n\n\n      // Regex pattern below is automatically generated by regexpPrecederPatterns.pl\n      // Do not modify, your changes will be erased.\n\n      // CAVEAT: this does not properly handle the case where a regular\n      // expression immediately follows another since a regular expression may\n      // have flags for case-sensitivity and the like.  Having regexp tokens\n      // adjacent is not valid in any language I\'m aware of, so I\'m punting.\n      // TODO: maybe style special characters inside a regexp as punctuation.\n\n      /**\n       * A set of tokens that can precede a regular expression literal in\n       * javascript\n       * http://web.archive.org/web/20070717142515/http://www.mozilla.org/js/language/js20/rationale/syntax.html\n       * has the full list, but I\'ve removed ones that might be problematic when\n       * seen in languages that don\'t support regular expression literals.\n       *\n       * Specifically, I\'ve removed any keywords that can\'t precede a regexp\n       * literal in a syntactically legal javascript program, and I\'ve removed the\n       * "in" keyword since it\'s not a keyword in many languages, and might be used\n       * as a count of inches.\n       *\n       * The link above does not accurately describe EcmaScript rules since\n       * it fails to distinguish between (a=++/b/i) and (a++/b/i) but it works\n       * very well in practice.\n       *\n       * @private\n       * @const\n       */\n      var REGEXP_PRECEDER_PATTERN = \'(?:^^\\\\.?|[+-]|[!=]=?=?|\\\\#|%=?|&&?=?|\\\\(|\\\\*=?|[+\\\\-]=|->|\\\\/=?|::?|<<?=?|>>?>?=?|,|;|\\\\?|@|\\\\[|~|{|\\\\^\\\\^?=?|\\\\|\\\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\\\s*\';\n\n\n      /**\n       * Given a group of {@link RegExp}s, returns a {@code RegExp} that globally\n       * matches the union of the sets of strings matched by the input RegExp.\n       * Since it matches globally, if the input strings have a start-of-input\n       * anchor (/^.../), it is ignored for the purposes of unioning.\n       * @param {Array.<RegExp>} regexs non multiline, non-global regexs.\n       * @return {RegExp} a global regex.\n       */\n      function combinePrefixPatterns(regexs) {\n        var capturedGroupIndex = 0;\n\n        var needToFoldCase = false;\n        var ignoreCase = false;\n        for (var i = 0, n = regexs.length; i < n; ++i) {\n          var regex = regexs[i];\n          if (regex.ignoreCase) {\n            ignoreCase = true;\n          } else if (/[a-z]/i.test(regex.source.replace(\n                         /\\\\u[0-9a-f]{4}|\\\\x[0-9a-f]{2}|\\\\[^ux]/gi, \'\'))) {\n            needToFoldCase = true;\n            ignoreCase = false;\n            break;\n          }\n        }\n\n        var escapeCharToCodeUnit = {\n          \'b\': 8,\n          \'t\': 9,\n          \'n\': 0xa,\n          \'v\': 0xb,\n          \'f\': 0xc,\n          \'r\': 0xd\n        };\n\n        function decodeEscape(charsetPart) {\n          var cc0 = charsetPart.charCodeAt(0);\n          if (cc0 !== 92 /* \\\\ */) {\n            return cc0;\n          }\n          var c1 = charsetPart.charAt(1);\n          cc0 = escapeCharToCodeUnit[c1];\n          if (cc0) {\n            return cc0;\n          } else if (\'0\' <= c1 && c1 <= \'7\') {\n            return parseInt(charsetPart.substring(1), 8);\n          } else if (c1 === \'u\' || c1 === \'x\') {\n            return parseInt(charsetPart.substring(2), 16);\n          } else {\n            return charsetPart.charCodeAt(1);\n          }\n        }\n\n        function encodeEscape(charCode) {\n          if (charCode < 0x20) {\n            return (charCode < 0x10 ? \'\\\\x0\' : \'\\\\x\') + charCode.toString(16);\n          }\n          var ch = String.fromCharCode(charCode);\n          return (ch === \'\\\\\' || ch === \'-\' || ch === \']\' || ch === \'^\')\n              ? "\\\\" + ch : ch;\n        }\n\n        function caseFoldCharset(charSet) {\n          var charsetParts = charSet.substring(1, charSet.length - 1).match(\n              new RegExp(\n                  \'\\\\\\\\u[0-9A-Fa-f]{4}\'\n                  + \'|\\\\\\\\x[0-9A-Fa-f]{2}\'\n                  + \'|\\\\\\\\[0-3][0-7]{0,2}\'\n                  + \'|\\\\\\\\[0-7]{1,2}\'\n                  + \'|\\\\\\\\[\\\\s\\\\S]\'\n                  + \'|-\'\n                  + \'|[^-\\\\\\\\]\',\n                  \'g\'));\n          var ranges = [];\n          var inverse = charsetParts[0] === \'^\';\n\n          var out = [\'[\'];\n          if (inverse) { out.push(\'^\'); }\n\n          for (var i = inverse ? 1 : 0, n = charsetParts.length; i < n; ++i) {\n            var p = charsetParts[i];\n            if (/\\\\[bdsw]/i.test(p)) {  // Don\'t muck with named groups.\n              out.push(p);\n            } else {\n              var start = decodeEscape(p);\n              var end;\n              if (i + 2 < n && \'-\' === charsetParts[i + 1]) {\n                end = decodeEscape(charsetParts[i + 2]);\n                i += 2;\n              } else {\n                end = start;\n              }\n              ranges.push([start, end]);\n              // If the range might intersect letters, then expand it.\n              // This case handling is too simplistic.\n              // It does not deal with non-latin case folding.\n              // It works for latin source code identifiers though.\n              if (!(end < 65 || start > 122)) {\n                if (!(end < 65 || start > 90)) {\n                  ranges.push([Math.max(65, start) | 32, Math.min(end, 90) | 32]);\n                }\n                if (!(end < 97 || start > 122)) {\n                  ranges.push([Math.max(97, start) & ~32, Math.min(end, 122) & ~32]);\n                }\n              }\n            }\n          }\n\n          // [[1, 10], [3, 4], [8, 12], [14, 14], [16, 16], [17, 17]]\n          // -> [[1, 12], [14, 14], [16, 17]]\n          ranges.sort(function (a, b) { return (a[0] - b[0]) || (b[1]  - a[1]); });\n          var consolidatedRanges = [];\n          var lastRange = [];\n          for (var i = 0; i < ranges.length; ++i) {\n            var range = ranges[i];\n            if (range[0] <= lastRange[1] + 1) {\n              lastRange[1] = Math.max(lastRange[1], range[1]);\n            } else {\n              consolidatedRanges.push(lastRange = range);\n            }\n          }\n\n          for (var i = 0; i < consolidatedRanges.length; ++i) {\n            var range = consolidatedRanges[i];\n            out.push(encodeEscape(range[0]));\n            if (range[1] > range[0]) {\n              if (range[1] + 1 > range[0]) { out.push(\'-\'); }\n              out.push(encodeEscape(range[1]));\n            }\n          }\n          out.push(\']\');\n          return out.join(\'\');\n        }\n\n        function allowAnywhereFoldCaseAndRenumberGroups(regex) {\n          // Split into character sets, escape sequences, punctuation strings\n          // like (\'(\', \'(?:\', \')\', \'^\'), and runs of characters that do not\n          // include any of the above.\n          var parts = regex.source.match(\n              new RegExp(\n                  \'(?:\'\n                  + \'\\\\[(?:[^\\\\x5C\\\\x5D]|\\\\\\\\[\\\\s\\\\S])*\\\\]\'  // a character set\n                  + \'|\\\\\\\\u[A-Fa-f0-9]{4}\'  // a unicode escape\n                  + \'|\\\\\\\\x[A-Fa-f0-9]{2}\'  // a hex escape\n                  + \'|\\\\\\\\[0-9]+\'  // a back-reference or octal escape\n                  + \'|\\\\\\\\[^ux0-9]\'  // other escape sequence\n                  + \'|\\\\(\\\\?[:!=]\'  // start of a non-capturing group\n                  + \'|[\\\\(\\\\)\\\\^]\'  // start/end of a group, or line start\n                  + \'|[^\\\\x5B\\\\x5C\\\\(\\\\)\\\\^]+\'  // run of other characters\n                  + \')\',\n                  \'g\'));\n          var n = parts.length;\n\n          // Maps captured group numbers to the number they will occupy in\n          // the output or to -1 if that has not been determined, or to\n          // undefined if they need not be capturing in the output.\n          var capturedGroups = [];\n\n          // Walk over and identify back references to build the capturedGroups\n          // mapping.\n          for (var i = 0, groupIndex = 0; i < n; ++i) {\n            var p = parts[i];\n            if (p === \'(\') {\n              // groups are 1-indexed, so max group index is count of \'(\'\n              ++groupIndex;\n            } else if (\'\\\\\' === p.charAt(0)) {\n              var decimalValue = +p.substring(1);\n              if (decimalValue) {\n                if (decimalValue <= groupIndex) {\n                  capturedGroups[decimalValue] = -1;\n                } else {\n                  // Replace with an unambiguous escape sequence so that\n                  // an octal escape sequence does not turn into a backreference\n                  // to a capturing group from an earlier regex.\n                  parts[i] = encodeEscape(decimalValue);\n                }\n              }\n            }\n          }\n\n          // Renumber groups and reduce capturing groups to non-capturing groups\n          // where possible.\n          for (var i = 1; i < capturedGroups.length; ++i) {\n            if (-1 === capturedGroups[i]) {\n              capturedGroups[i] = ++capturedGroupIndex;\n            }\n          }\n          for (var i = 0, groupIndex = 0; i < n; ++i) {\n            var p = parts[i];\n            if (p === \'(\') {\n              ++groupIndex;\n              if (!capturedGroups[groupIndex]) {\n                parts[i] = \'(?:\';\n              }\n            } else if (\'\\\\\' === p.charAt(0)) {\n              var decimalValue = +p.substring(1);\n              if (decimalValue && decimalValue <= groupIndex) {\n                parts[i] = \'\\\\\' + capturedGroups[decimalValue];\n              }\n            }\n          }\n\n          // Remove any prefix anchors so that the output will match anywhere.\n          // ^^ really does mean an anchored match though.\n          for (var i = 0; i < n; ++i) {\n            if (\'^\' === parts[i] && \'^\' !== parts[i + 1]) { parts[i] = \'\'; }\n          }\n\n          // Expand letters to groups to handle mixing of case-sensitive and\n          // case-insensitive patterns if necessary.\n          if (regex.ignoreCase && needToFoldCase) {\n            for (var i = 0; i < n; ++i) {\n              var p = parts[i];\n              var ch0 = p.charAt(0);\n              if (p.length >= 2 && ch0 === \'[\') {\n                parts[i] = caseFoldCharset(p);\n              } else if (ch0 !== \'\\\\\') {\n                // TODO: handle letters in numeric escapes.\n                parts[i] = p.replace(\n                    /[a-zA-Z]/g,\n                    function (ch) {\n                      var cc = ch.charCodeAt(0);\n                      return \'[\' + String.fromCharCode(cc & ~32, cc | 32) + \']\';\n                    });\n              }\n            }\n          }\n\n          return parts.join(\'\');\n        }\n\n        var rewritten = [];\n        for (var i = 0, n = regexs.length; i < n; ++i) {\n          var regex = regexs[i];\n          if (regex.global || regex.multiline) { throw new Error(\'\' + regex); }\n          rewritten.push(\n              \'(?:\' + allowAnywhereFoldCaseAndRenumberGroups(regex) + \')\');\n        }\n\n        return new RegExp(rewritten.join(\'|\'), ignoreCase ? \'gi\' : \'g\');\n      }\n\n\n      /**\n       * Split markup into a string of source code and an array mapping ranges in\n       * that string to the text nodes in which they appear.\n       *\n       * <p>\n       * The HTML DOM structure:</p>\n       * <pre>\n       * (Element   "p"\n       *   (Element "b"\n       *     (Text  "print "))       ; #1\n       *   (Text    "\'Hello \'")      ; #2\n       *   (Element "br")            ; #3\n       *   (Text    "  + \'World\';")) ; #4\n       * </pre>\n       * <p>\n       * corresponds to the HTML\n       * {@code <p><b>print </b>\'Hello \'<br>  + \'World\';</p>}.</p>\n       *\n       * <p>\n       * It will produce the output:</p>\n       * <pre>\n       * {\n       *   sourceCode: "print \'Hello \'\\n  + \'World\';",\n       *   //                     1          2\n       *   //           012345678901234 5678901234567\n       *   spans: [0, #1, 6, #2, 14, #3, 15, #4]\n       * }\n       * </pre>\n       * <p>\n       * where #1 is a reference to the {@code "print "} text node above, and so\n       * on for the other text nodes.\n       * </p>\n       *\n       * <p>\n       * The {@code} spans array is an array of pairs.  Even elements are the start\n       * indices of substrings, and odd elements are the text nodes (or BR elements)\n       * that contain the text for those substrings.\n       * Substrings continue until the next index or the end of the source.\n       * </p>\n       *\n       * @param {Node} node an HTML DOM subtree containing source-code.\n       * @param {boolean|number} isPreformatted truthy if white-space in\n       *    text nodes should be considered significant.\n       * @return {SourceSpansT} source code and the nodes in which they occur.\n       */\n      function extractSourceSpans(node, isPreformatted) {\n        var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n\n        var chunks = [];\n        var length = 0;\n        var spans = [];\n        var k = 0;\n\n        function walk(node) {\n          var type = node.nodeType;\n          if (type == 1) {  // Element\n            if (nocode.test(node.className)) { return; }\n            for (var child = node.firstChild; child; child = child.nextSibling) {\n              walk(child);\n            }\n            var nodeName = node.nodeName.toLowerCase();\n            if (\'br\' === nodeName || \'li\' === nodeName) {\n              chunks[k] = \'\\n\';\n              spans[k << 1] = length++;\n              spans[(k++ << 1) | 1] = node;\n            }\n          } else if (type == 3 || type == 4) {  // Text\n            var text = node.nodeValue;\n            if (text.length) {\n              if (!isPreformatted) {\n                text = text.replace(/[ \\t\\r\\n]+/g, \' \');\n              } else {\n                text = text.replace(/\\r\\n?/g, \'\\n\');  // Normalize newlines.\n              }\n              // TODO: handle tabs here?\n              chunks[k] = text;\n              spans[k << 1] = length;\n              length += text.length;\n              spans[(k++ << 1) | 1] = node;\n            }\n          }\n        }\n\n        walk(node);\n\n        return {\n          sourceCode: chunks.join(\'\').replace(/\\n$/, \'\'),\n          spans: spans\n        };\n      }\n\n\n      /**\n       * Apply the given language handler to sourceCode and add the resulting\n       * decorations to out.\n       * @param {!Element} sourceNode\n       * @param {number} basePos the index of sourceCode within the chunk of source\n       *    whose decorations are already present on out.\n       * @param {string} sourceCode\n       * @param {function(JobT)} langHandler\n       * @param {DecorationsT} out\n       */\n      function appendDecorations(\n          sourceNode, basePos, sourceCode, langHandler, out) {\n        if (!sourceCode) { return; }\n        /** @type {JobT} */\n        var job = {\n          sourceNode: sourceNode,\n          pre: 1,\n          langExtension: null,\n          numberLines: null,\n          sourceCode: sourceCode,\n          spans: null,\n          basePos: basePos,\n          decorations: null\n        };\n        langHandler(job);\n        out.push.apply(out, job.decorations);\n      }\n\n      var notWs = /\\S/;\n\n      /**\n       * Given an element, if it contains only one child element and any text nodes\n       * it contains contain only space characters, return the sole child element.\n       * Otherwise returns undefined.\n       * <p>\n       * This is meant to return the CODE element in {@code <pre><code ...>} when\n       * there is a single child element that contains all the non-space textual\n       * content, but not to return anything where there are multiple child elements\n       * as in {@code <pre><code>...</code><code>...</code></pre>} or when there\n       * is textual content.\n       */\n      function childContentWrapper(element) {\n        var wrapper = undefined;\n        for (var c = element.firstChild; c; c = c.nextSibling) {\n          var type = c.nodeType;\n          wrapper = (type === 1)  // Element Node\n              ? (wrapper ? element : c)\n              : (type === 3)  // Text Node\n              ? (notWs.test(c.nodeValue) ? element : wrapper)\n              : wrapper;\n        }\n        return wrapper === element ? undefined : wrapper;\n      }\n\n      /** Given triples of [style, pattern, context] returns a lexing function,\n        * The lexing function interprets the patterns to find token boundaries and\n        * returns a decoration list of the form\n        * [index_0, style_0, index_1, style_1, ..., index_n, style_n]\n        * where index_n is an index into the sourceCode, and style_n is a style\n        * constant like PR_PLAIN.  index_n-1 <= index_n, and style_n-1 applies to\n        * all characters in sourceCode[index_n-1:index_n].\n        *\n        * The stylePatterns is a list whose elements have the form\n        * [style : string, pattern : RegExp, DEPRECATED, shortcut : string].\n        *\n        * Style is a style constant like PR_PLAIN, or can be a string of the\n        * form \'lang-FOO\', where FOO is a language extension describing the\n        * language of the portion of the token in $1 after pattern executes.\n        * E.g., if style is \'lang-lisp\', and group 1 contains the text\n        * \'(hello (world))\', then that portion of the token will be passed to the\n        * registered lisp handler for formatting.\n        * The text before and after group 1 will be restyled using this decorator\n        * so decorators should take care that this doesn\'t result in infinite\n        * recursion.  For example, the HTML lexer rule for SCRIPT elements looks\n        * something like [\'lang-js\', /<[s]cript>(.+?)<\\/script>/].  This may match\n        * \'<script>foo()<\\/script>\', which would cause the current decorator to\n        * be called with \'<script>\' which would not match the same rule since\n        * group 1 must not be empty, so it would be instead styled as PR_TAG by\n        * the generic tag rule.  The handler registered for the \'js\' extension would\n        * then be called with \'foo()\', and finally, the current decorator would\n        * be called with \'<\\/script>\' which would not match the original rule and\n        * so the generic tag rule would identify it as a tag.\n        *\n        * Pattern must only match prefixes, and if it matches a prefix, then that\n        * match is considered a token with the same style.\n        *\n        * Context is applied to the last non-whitespace, non-comment token\n        * recognized.\n        *\n        * Shortcut is an optional string of characters, any of which, if the first\n        * character, gurantee that this pattern and only this pattern matches.\n        *\n        * @param {Array} shortcutStylePatterns patterns that always start with\n        *   a known character.  Must have a shortcut string.\n        * @param {Array} fallthroughStylePatterns patterns that will be tried in\n        *   order if the shortcut ones fail.  May have shortcuts.\n        *\n        * @return {function (JobT)} a function that takes an undecorated job and\n        *   attaches a list of decorations.\n        */\n      function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) {\n        var shortcuts = {};\n        var tokenizer;\n        (function () {\n          var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns);\n          var allRegexs = [];\n          var regexKeys = {};\n          for (var i = 0, n = allPatterns.length; i < n; ++i) {\n            var patternParts = allPatterns[i];\n            var shortcutChars = patternParts[3];\n            if (shortcutChars) {\n              for (var c = shortcutChars.length; --c >= 0;) {\n                shortcuts[shortcutChars.charAt(c)] = patternParts;\n              }\n            }\n            var regex = patternParts[1];\n            var k = \'\' + regex;\n            if (!regexKeys.hasOwnProperty(k)) {\n              allRegexs.push(regex);\n              regexKeys[k] = null;\n            }\n          }\n          allRegexs.push(/[\\0-\\uffff]/);\n          tokenizer = combinePrefixPatterns(allRegexs);\n        })();\n\n        var nPatterns = fallthroughStylePatterns.length;\n\n        /**\n         * Lexes job.sourceCode and attaches an output array job.decorations of\n         * style classes preceded by the position at which they start in\n         * job.sourceCode in order.\n         *\n         * @type{function (JobT)}\n         */\n        var decorate = function (job) {\n          var sourceCode = job.sourceCode, basePos = job.basePos;\n          var sourceNode = job.sourceNode;\n          /** Even entries are positions in source in ascending order.  Odd enties\n            * are style markers (e.g., PR_COMMENT) that run from that position until\n            * the end.\n            * @type {DecorationsT}\n            */\n          var decorations = [basePos, PR_PLAIN];\n          var pos = 0;  // index into sourceCode\n          var tokens = sourceCode.match(tokenizer) || [];\n          var styleCache = {};\n\n          for (var ti = 0, nTokens = tokens.length; ti < nTokens; ++ti) {\n            var token = tokens[ti];\n            var style = styleCache[token];\n            var match = void 0;\n\n            var isEmbedded;\n            if (typeof style === \'string\') {\n              isEmbedded = false;\n            } else {\n              var patternParts = shortcuts[token.charAt(0)];\n              if (patternParts) {\n                match = token.match(patternParts[1]);\n                style = patternParts[0];\n              } else {\n                for (var i = 0; i < nPatterns; ++i) {\n                  patternParts = fallthroughStylePatterns[i];\n                  match = token.match(patternParts[1]);\n                  if (match) {\n                    style = patternParts[0];\n                    break;\n                  }\n                }\n\n                if (!match) {  // make sure that we make progress\n                  style = PR_PLAIN;\n                }\n              }\n\n              isEmbedded = style.length >= 5 && \'lang-\' === style.substring(0, 5);\n              if (isEmbedded && !(match && typeof match[1] === \'string\')) {\n                isEmbedded = false;\n                style = PR_SOURCE;\n              }\n\n              if (!isEmbedded) { styleCache[token] = style; }\n            }\n\n            var tokenStart = pos;\n            pos += token.length;\n\n            if (!isEmbedded) {\n              decorations.push(basePos + tokenStart, style);\n            } else {  // Treat group 1 as an embedded block of source code.\n              var embeddedSource = match[1];\n              var embeddedSourceStart = token.indexOf(embeddedSource);\n              var embeddedSourceEnd = embeddedSourceStart + embeddedSource.length;\n              if (match[2]) {\n                // If embeddedSource can be blank, then it would match at the\n                // beginning which would cause us to infinitely recurse on the\n                // entire token, so we catch the right context in match[2].\n                embeddedSourceEnd = token.length - match[2].length;\n                embeddedSourceStart = embeddedSourceEnd - embeddedSource.length;\n              }\n              var lang = style.substring(5);\n              // Decorate the left of the embedded source\n              appendDecorations(\n                  sourceNode,\n                  basePos + tokenStart,\n                  token.substring(0, embeddedSourceStart),\n                  decorate, decorations);\n              // Decorate the embedded source\n              appendDecorations(\n                  sourceNode,\n                  basePos + tokenStart + embeddedSourceStart,\n                  embeddedSource,\n                  langHandlerForExtension(lang, embeddedSource),\n                  decorations);\n              // Decorate the right of the embedded section\n              appendDecorations(\n                  sourceNode,\n                  basePos + tokenStart + embeddedSourceEnd,\n                  token.substring(embeddedSourceEnd),\n                  decorate, decorations);\n            }\n          }\n          job.decorations = decorations;\n        };\n        return decorate;\n      }\n\n      /** returns a function that produces a list of decorations from source text.\n        *\n        * This code treats ", \', and ` as string delimiters, and \\ as a string\n        * escape.  It does not recognize perl\'s qq() style strings.\n        * It has no special handling for double delimiter escapes as in basic, or\n        * the tripled delimiters used in python, but should work on those regardless\n        * although in those cases a single string literal may be broken up into\n        * multiple adjacent string literals.\n        *\n        * It recognizes C, C++, and shell style comments.\n        *\n        * @param {Object} options a set of optional parameters.\n        * @return {function (JobT)} a function that examines the source code\n        *     in the input job and builds a decoration list which it attaches to\n        *     the job.\n        */\n      function sourceDecorator(options) {\n        var shortcutStylePatterns = [], fallthroughStylePatterns = [];\n        if (options[\'tripleQuotedStrings\']) {\n          // \'\'\'multi-line-string\'\'\', \'single-line-string\', and double-quoted\n          shortcutStylePatterns.push(\n              [PR_STRING,  /^(?:\\\'\\\'\\\'(?:[^\\\'\\\\]|\\\\[\\s\\S]|\\\'{1,2}(?=[^\\\']))*(?:\\\'\\\'\\\'|$)|\\"\\"\\"(?:[^\\"\\\\]|\\\\[\\s\\S]|\\"{1,2}(?=[^\\"]))*(?:\\"\\"\\"|$)|\\\'(?:[^\\\\\\\']|\\\\[\\s\\S])*(?:\\\'|$)|\\"(?:[^\\\\\\"]|\\\\[\\s\\S])*(?:\\"|$))/,\n               null, \'\\\'"\']);\n        } else if (options[\'multiLineStrings\']) {\n          // \'multi-line-string\', "multi-line-string"\n          shortcutStylePatterns.push(\n              [PR_STRING,  /^(?:\\\'(?:[^\\\\\\\']|\\\\[\\s\\S])*(?:\\\'|$)|\\"(?:[^\\\\\\"]|\\\\[\\s\\S])*(?:\\"|$)|\\`(?:[^\\\\\\`]|\\\\[\\s\\S])*(?:\\`|$))/,\n               null, \'\\\'"`\']);\n        } else {\n          // \'single-line-string\', "single-line-string"\n          shortcutStylePatterns.push(\n              [PR_STRING,\n               /^(?:\\\'(?:[^\\\\\\\'\\r\\n]|\\\\.)*(?:\\\'|$)|\\"(?:[^\\\\\\"\\r\\n]|\\\\.)*(?:\\"|$))/,\n               null, \'"\\\'\']);\n        }\n        if (options[\'verbatimStrings\']) {\n          // verbatim-string-literal production from the C# grammar.  See issue 93.\n          fallthroughStylePatterns.push(\n              [PR_STRING, /^@\\"(?:[^\\"]|\\"\\")*(?:\\"|$)/, null]);\n        }\n        var hc = options[\'hashComments\'];\n        if (hc) {\n          if (options[\'cStyleComments\']) {\n            if (hc > 1) {  // multiline hash comments\n              shortcutStylePatterns.push(\n                  [PR_COMMENT, /^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/, null, \'#\']);\n            } else {\n              // Stop C preprocessor declarations at an unclosed open comment\n              shortcutStylePatterns.push(\n                  [PR_COMMENT, /^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\\b|[^\\r\\n]*)/,\n                   null, \'#\']);\n            }\n            // #include <stdio.h>\n            fallthroughStylePatterns.push(\n                [PR_STRING,\n                 /^<(?:(?:(?:\\.\\.\\/)*|\\/?)(?:[\\w-]+(?:\\/[\\w-]+)+)?[\\w-]+\\.h(?:h|pp|\\+\\+)?|[a-z]\\w*)>/,\n                 null]);\n          } else {\n            shortcutStylePatterns.push([PR_COMMENT, /^#[^\\r\\n]*/, null, \'#\']);\n          }\n        }\n        if (options[\'cStyleComments\']) {\n          fallthroughStylePatterns.push([PR_COMMENT, /^\\/\\/[^\\r\\n]*/, null]);\n          fallthroughStylePatterns.push(\n              [PR_COMMENT, /^\\/\\*[\\s\\S]*?(?:\\*\\/|$)/, null]);\n        }\n        var regexLiterals = options[\'regexLiterals\'];\n        if (regexLiterals) {\n          /**\n           * @const\n           */\n          var regexExcls = regexLiterals > 1\n            ? \'\'  // Multiline regex literals\n            : \'\\n\\r\';\n          /**\n           * @const\n           */\n          var regexAny = regexExcls ? \'.\' : \'[\\\\S\\\\s]\';\n          /**\n           * @const\n           */\n          var REGEX_LITERAL = (\n              // A regular expression literal starts with a slash that is\n              // not followed by * or / so that it is not confused with\n              // comments.\n              \'/(?=[^/*\' + regexExcls + \'])\'\n              // and then contains any number of raw characters,\n              + \'(?:[^/\\\\x5B\\\\x5C\' + regexExcls + \']\'\n              // escape sequences (\\x5C),\n              +    \'|\\\\x5C\' + regexAny\n              // or non-nesting character sets (\\x5B\\x5D);\n              +    \'|\\\\x5B(?:[^\\\\x5C\\\\x5D\' + regexExcls + \']\'\n              +             \'|\\\\x5C\' + regexAny + \')*(?:\\\\x5D|$))+\'\n              // finally closed by a /.\n              + \'/\');\n          fallthroughStylePatterns.push(\n              [\'lang-regex\',\n               RegExp(\'^\' + REGEXP_PRECEDER_PATTERN + \'(\' + REGEX_LITERAL + \')\')\n               ]);\n        }\n\n        var types = options[\'types\'];\n        if (types) {\n          fallthroughStylePatterns.push([PR_TYPE, types]);\n        }\n\n        var keywords = ("" + options[\'keywords\']).replace(/^ | $/g, \'\');\n        if (keywords.length) {\n          fallthroughStylePatterns.push(\n              [PR_KEYWORD,\n               new RegExp(\'^(?:\' + keywords.replace(/[\\s,]+/g, \'|\') + \')\\\\b\'),\n               null]);\n        }\n\n        shortcutStylePatterns.push([PR_PLAIN,       /^\\s+/, null, \' \\r\\n\\t\\xA0\']);\n\n        var punctuation =\n          // The Bash man page says\n\n          // A word is a sequence of characters considered as a single\n          // unit by GRUB. Words are separated by metacharacters,\n          // which are the following plus space, tab, and newline: { }\n          // | & $ ; < >\n          // ...\n\n          // A word beginning with # causes that word and all remaining\n          // characters on that line to be ignored.\n\n          // which means that only a \'#\' after /(?:^|[{}|&$;<>\\s])/ starts a\n          // comment but empirically\n          // $ echo {#}\n          // {#}\n          // $ echo \\$#\n          // $#\n          // $ echo }#\n          // }#\n\n          // so /(?:^|[|&;<>\\s])/ is more appropriate.\n\n          // http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC3\n          // suggests that this definition is compatible with a\n          // default mode that tries to use a single token definition\n          // to recognize both bash/python style comments and C\n          // preprocessor directives.\n\n          // This definition of punctuation does not include # in the list of\n          // follow-on exclusions, so # will not be broken before if preceeded\n          // by a punctuation character.  We could try to exclude # after\n          // [|&;<>] but that doesn\'t seem to cause many major problems.\n          // If that does turn out to be a problem, we should change the below\n          // when hc is truthy to include # in the run of punctuation characters\n          // only when not followint [|&;<>].\n          \'^.[^\\\\s\\\\w.$@\\\'"`/\\\\\\\\]*\';\n        if (options[\'regexLiterals\']) {\n          punctuation += \'(?!\\s*\\/)\';\n        }\n\n        fallthroughStylePatterns.push(\n            // TODO(mikesamuel): recognize non-latin letters and numerals in idents\n            [PR_LITERAL,     /^@[a-z_$][a-z_$@0-9]*/i, null],\n            [PR_TYPE,        /^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\\w+_t\\b)/, null],\n            [PR_PLAIN,       /^[a-z_$][a-z_$@0-9]*/i, null],\n            [PR_LITERAL,\n             new RegExp(\n                 \'^(?:\'\n                 // A hex number\n                 + \'0x[a-f0-9]+\'\n                 // or an octal or decimal number,\n                 + \'|(?:\\\\d(?:_\\\\d+)*\\\\d*(?:\\\\.\\\\d*)?|\\\\.\\\\d\\\\+)\'\n                 // possibly in scientific notation\n                 + \'(?:e[+\\\\-]?\\\\d+)?\'\n                 + \')\'\n                 // with an optional modifier like UL for unsigned long\n                 + \'[a-z]*\', \'i\'),\n             null, \'0123456789\'],\n            // Don\'t treat escaped quotes in bash as starting strings.\n            // See issue 144.\n            [PR_PLAIN,       /^\\\\[\\s\\S]?/, null],\n            [PR_PUNCTUATION, new RegExp(punctuation), null]);\n\n        return createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns);\n      }\n\n      var decorateSource = sourceDecorator({\n            \'keywords\': ALL_KEYWORDS,\n            \'hashComments\': true,\n            \'cStyleComments\': true,\n            \'multiLineStrings\': true,\n            \'regexLiterals\': true\n          });\n\n      /**\n       * Given a DOM subtree, wraps it in a list, and puts each line into its own\n       * list item.\n       *\n       * @param {Node} node modified in place.  Its content is pulled into an\n       *     HTMLOListElement, and each line is moved into a separate list item.\n       *     This requires cloning elements, so the input might not have unique\n       *     IDs after numbering.\n       * @param {number|null|boolean} startLineNum\n       *     If truthy, coerced to an integer which is the 1-indexed line number\n       *     of the first line of code.  The number of the first line will be\n       *     attached to the list.\n       * @param {boolean} isPreformatted true iff white-space in text nodes should\n       *     be treated as significant.\n       */\n      function numberLines(node, startLineNum, isPreformatted) {\n        var nocode = /(?:^|\\s)nocode(?:\\s|$)/;\n        var lineBreak = /\\r\\n?|\\n/;\n\n        var document = node.ownerDocument;\n\n        var li = document.createElement(\'li\');\n        while (node.firstChild) {\n          li.appendChild(node.firstChild);\n        }\n        // An array of lines.  We split below, so this is initialized to one\n        // un-split line.\n        var listItems = [li];\n\n        function walk(node) {\n          var type = node.nodeType;\n          if (type == 1 && !nocode.test(node.className)) {  // Element\n            if (\'br\' === node.nodeName.toLowerCase()) {\n              breakAfter(node);\n              // Discard the <BR> since it is now flush against a </LI>.\n              if (node.parentNode) {\n                node.parentNode.removeChild(node);\n              }\n            } else {\n              for (var child = node.firstChild; child; child = child.nextSibling) {\n                walk(child);\n              }\n            }\n          } else if ((type == 3 || type == 4) && isPreformatted) {  // Text\n            var text = node.nodeValue;\n            var match = text.match(lineBreak);\n            if (match) {\n              var firstLine = text.substring(0, match.index);\n              node.nodeValue = firstLine;\n              var tail = text.substring(match.index + match[0].length);\n              if (tail) {\n                var parent = node.parentNode;\n                parent.insertBefore(\n                  document.createTextNode(tail), node.nextSibling);\n              }\n              breakAfter(node);\n              if (!firstLine) {\n                // Don\'t leave blank text nodes in the DOM.\n                node.parentNode.removeChild(node);\n              }\n            }\n          }\n        }\n\n        // Split a line after the given node.\n        function breakAfter(lineEndNode) {\n          // If there\'s nothing to the right, then we can skip ending the line\n          // here, and move root-wards since splitting just before an end-tag\n          // would require us to create a bunch of empty copies.\n          while (!lineEndNode.nextSibling) {\n            lineEndNode = lineEndNode.parentNode;\n            if (!lineEndNode) { return; }\n          }\n\n          function breakLeftOf(limit, copy) {\n            // Clone shallowly if this node needs to be on both sides of the break.\n            var rightSide = copy ? limit.cloneNode(false) : limit;\n            var parent = limit.parentNode;\n            if (parent) {\n              // We clone the parent chain.\n              // This helps us resurrect important styling elements that cross lines.\n              // E.g. in <i>Foo<br>Bar</i>\n              // should be rewritten to <li><i>Foo</i></li><li><i>Bar</i></li>.\n              var parentClone = breakLeftOf(parent, 1);\n              // Move the clone and everything to the right of the original\n              // onto the cloned parent.\n              var next = limit.nextSibling;\n              parentClone.appendChild(rightSide);\n              for (var sibling = next; sibling; sibling = next) {\n                next = sibling.nextSibling;\n                parentClone.appendChild(sibling);\n              }\n            }\n            return rightSide;\n          }\n\n          var copiedListItem = breakLeftOf(lineEndNode.nextSibling, 0);\n\n          // Walk the parent chain until we reach an unattached LI.\n          for (var parent;\n               // Check nodeType since IE invents document fragments.\n               (parent = copiedListItem.parentNode) && parent.nodeType === 1;) {\n            copiedListItem = parent;\n          }\n          // Put it on the list of lines for later processing.\n          listItems.push(copiedListItem);\n        }\n\n        // Split lines while there are lines left to split.\n        for (var i = 0;  // Number of lines that have been split so far.\n             i < listItems.length;  // length updated by breakAfter calls.\n             ++i) {\n          walk(listItems[i]);\n        }\n\n        // Make sure numeric indices show correctly.\n        if (startLineNum === (startLineNum|0)) {\n          listItems[0].setAttribute(\'value\', startLineNum);\n        }\n\n        var ol = document.createElement(\'ol\');\n        ol.className = \'linenums\';\n        var offset = Math.max(0, ((startLineNum - 1 /* zero index */)) | 0) || 0;\n        for (var i = 0, n = listItems.length; i < n; ++i) {\n          li = listItems[i];\n          // Stick a class on the LIs so that stylesheets can\n          // color odd/even rows, or any other row pattern that\n          // is co-prime with 10.\n          li.className = \'L\' + ((i + offset) % 10);\n          if (!li.firstChild) {\n            li.appendChild(document.createTextNode(\'\\xA0\'));\n          }\n          ol.appendChild(li);\n        }\n\n        node.appendChild(ol);\n      }\n\n\n      /**\n       * Breaks {@code job.sourceCode} around style boundaries in\n       * {@code job.decorations} and modifies {@code job.sourceNode} in place.\n       * @param {JobT} job\n       * @private\n       */\n      function recombineTagsAndDecorations(job) {\n        var isIE8OrEarlier = /\\bMSIE\\s(\\d+)/.exec(navigator.userAgent);\n        isIE8OrEarlier = isIE8OrEarlier && +isIE8OrEarlier[1] <= 8;\n        var newlineRe = /\\n/g;\n\n        var source = job.sourceCode;\n        var sourceLength = source.length;\n        // Index into source after the last code-unit recombined.\n        var sourceIndex = 0;\n\n        var spans = job.spans;\n        var nSpans = spans.length;\n        // Index into spans after the last span which ends at or before sourceIndex.\n        var spanIndex = 0;\n\n        var decorations = job.decorations;\n        var nDecorations = decorations.length;\n        // Index into decorations after the last decoration which ends at or before\n        // sourceIndex.\n        var decorationIndex = 0;\n\n        // Remove all zero-length decorations.\n        decorations[nDecorations] = sourceLength;\n        var decPos, i;\n        for (i = decPos = 0; i < nDecorations;) {\n          if (decorations[i] !== decorations[i + 2]) {\n            decorations[decPos++] = decorations[i++];\n            decorations[decPos++] = decorations[i++];\n          } else {\n            i += 2;\n          }\n        }\n        nDecorations = decPos;\n\n        // Simplify decorations.\n        for (i = decPos = 0; i < nDecorations;) {\n          var startPos = decorations[i];\n          // Conflate all adjacent decorations that use the same style.\n          var startDec = decorations[i + 1];\n          var end = i + 2;\n          while (end + 2 <= nDecorations && decorations[end + 1] === startDec) {\n            end += 2;\n          }\n          decorations[decPos++] = startPos;\n          decorations[decPos++] = startDec;\n          i = end;\n        }\n\n        nDecorations = decorations.length = decPos;\n\n        var sourceNode = job.sourceNode;\n        var oldDisplay = "";\n        if (sourceNode) {\n          oldDisplay = sourceNode.style.display;\n          sourceNode.style.display = \'none\';\n        }\n        try {\n          var decoration = null;\n          while (spanIndex < nSpans) {\n            var spanStart = spans[spanIndex];\n            var spanEnd = /** @type{number} */ (spans[spanIndex + 2])\n                || sourceLength;\n\n            var decEnd = decorations[decorationIndex + 2] || sourceLength;\n\n            var end = Math.min(spanEnd, decEnd);\n\n            var textNode = /** @type{Node} */ (spans[spanIndex + 1]);\n            var styledText;\n            if (textNode.nodeType !== 1  // Don\'t muck with <BR>s or <LI>s\n                // Don\'t introduce spans around empty text nodes.\n                && (styledText = source.substring(sourceIndex, end))) {\n              // This may seem bizarre, and it is.  Emitting LF on IE causes the\n              // code to display with spaces instead of line breaks.\n              // Emitting Windows standard issue linebreaks (CRLF) causes a blank\n              // space to appear at the beginning of every line but the first.\n              // Emitting an old Mac OS 9 line separator makes everything spiffy.\n              if (isIE8OrEarlier) {\n                styledText = styledText.replace(newlineRe, \'\\r\');\n              }\n              textNode.nodeValue = styledText;\n              var document = textNode.ownerDocument;\n              var span = document.createElement(\'span\');\n              span.className = decorations[decorationIndex + 1];\n              var parentNode = textNode.parentNode;\n              parentNode.replaceChild(span, textNode);\n              span.appendChild(textNode);\n              if (sourceIndex < spanEnd) {  // Split off a text node.\n                spans[spanIndex + 1] = textNode\n                    // TODO: Possibly optimize by using \'\' if there\'s no flicker.\n                    = document.createTextNode(source.substring(end, spanEnd));\n                parentNode.insertBefore(textNode, span.nextSibling);\n              }\n            }\n\n            sourceIndex = end;\n\n            if (sourceIndex >= spanEnd) {\n              spanIndex += 2;\n            }\n            if (sourceIndex >= decEnd) {\n              decorationIndex += 2;\n            }\n          }\n        } finally {\n          if (sourceNode) {\n            sourceNode.style.display = oldDisplay;\n          }\n        }\n      }\n\n\n      /** Maps language-specific file extensions to handlers. */\n      var langHandlerRegistry = {};\n      /** Register a language handler for the given file extensions.\n        * @param {function (JobT)} handler a function from source code to a list\n        *      of decorations.  Takes a single argument job which describes the\n        *      state of the computation and attaches the decorations to it.\n        * @param {Array.<string>} fileExtensions\n        */\n      function registerLangHandler(handler, fileExtensions) {\n        for (var i = fileExtensions.length; --i >= 0;) {\n          var ext = fileExtensions[i];\n          if (!langHandlerRegistry.hasOwnProperty(ext)) {\n            langHandlerRegistry[ext] = handler;\n          } else if (win[\'console\']) {\n            console[\'warn\'](\'cannot override language handler %s\', ext);\n          }\n        }\n      }\n      function langHandlerForExtension(extension, source) {\n        if (!(extension && langHandlerRegistry.hasOwnProperty(extension))) {\n          // Treat it as markup if the first non whitespace character is a < and\n          // the last non-whitespace character is a >.\n          extension = /^\\s*</.test(source)\n              ? \'default-markup\'\n              : \'default-code\';\n        }\n        return langHandlerRegistry[extension];\n      }\n      registerLangHandler(decorateSource, [\'default-code\']);\n      registerLangHandler(\n          createSimpleLexer(\n              [],\n              [\n               [PR_PLAIN,       /^[^<?]+/],\n               [PR_DECLARATION, /^<!\\w[^>]*(?:>|$)/],\n               [PR_COMMENT,     /^<\\!--[\\s\\S]*?(?:-\\->|$)/],\n               // Unescaped content in an unknown language\n               [\'lang-\',        /^<\\?([\\s\\S]+?)(?:\\?>|$)/],\n               [\'lang-\',        /^<%([\\s\\S]+?)(?:%>|$)/],\n               [PR_PUNCTUATION, /^(?:<[%?]|[%?]>)/],\n               [\'lang-\',        /^<xmp\\b[^>]*>([\\s\\S]+?)<\\/xmp\\b[^>]*>/i],\n               // Unescaped content in javascript.  (Or possibly vbscript).\n               [\'lang-js\',      /^<script\\b[^>]*>([\\s\\S]*?)(<\\/script\\b[^>]*>)/i],\n               // Contains unescaped stylesheet content\n               [\'lang-css\',     /^<style\\b[^>]*>([\\s\\S]*?)(<\\/style\\b[^>]*>)/i],\n               [\'lang-in.tag\',  /^(<\\/?[a-z][^<>]*>)/i]\n              ]),\n          [\'default-markup\', \'htm\', \'html\', \'mxml\', \'xhtml\', \'xml\', \'xsl\']);\n      registerLangHandler(\n          createSimpleLexer(\n              [\n               [PR_PLAIN,        /^[\\s]+/, null, \' \\t\\r\\n\'],\n               [PR_ATTRIB_VALUE, /^(?:\\"[^\\"]*\\"?|\\\'[^\\\']*\\\'?)/, null, \'\\"\\\'\']\n               ],\n              [\n               [PR_TAG,          /^^<\\/?[a-z](?:[\\w.:-]*\\w)?|\\/?>$/i],\n               [PR_ATTRIB_NAME,  /^(?!style[\\s=]|on)[a-z](?:[\\w:-]*\\w)?/i],\n               [\'lang-uq.val\',   /^=\\s*([^>\\\'\\"\\s]*(?:[^>\\\'\\"\\s\\/]|\\/(?=\\s)))/],\n               [PR_PUNCTUATION,  /^[=<>\\/]+/],\n               [\'lang-js\',       /^on\\w+\\s*=\\s*\\"([^\\"]+)\\"/i],\n               [\'lang-js\',       /^on\\w+\\s*=\\s*\\\'([^\\\']+)\\\'/i],\n               [\'lang-js\',       /^on\\w+\\s*=\\s*([^\\"\\\'>\\s]+)/i],\n               [\'lang-css\',      /^style\\s*=\\s*\\"([^\\"]+)\\"/i],\n               [\'lang-css\',      /^style\\s*=\\s*\\\'([^\\\']+)\\\'/i],\n               [\'lang-css\',      /^style\\s*=\\s*([^\\"\\\'>\\s]+)/i]\n               ]),\n          [\'in.tag\']);\n      registerLangHandler(\n          createSimpleLexer([], [[PR_ATTRIB_VALUE, /^[\\s\\S]+/]]), [\'uq.val\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': CPP_KEYWORDS,\n              \'hashComments\': true,\n              \'cStyleComments\': true,\n              \'types\': C_TYPES\n            }), [\'c\', \'cc\', \'cpp\', \'cxx\', \'cyc\', \'m\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': \'null,true,false\'\n            }), [\'json\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': CSHARP_KEYWORDS,\n              \'hashComments\': true,\n              \'cStyleComments\': true,\n              \'verbatimStrings\': true,\n              \'types\': C_TYPES\n            }), [\'cs\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': JAVA_KEYWORDS,\n              \'cStyleComments\': true\n            }), [\'java\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': SH_KEYWORDS,\n              \'hashComments\': true,\n              \'multiLineStrings\': true\n            }), [\'bash\', \'bsh\', \'csh\', \'sh\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': PYTHON_KEYWORDS,\n              \'hashComments\': true,\n              \'multiLineStrings\': true,\n              \'tripleQuotedStrings\': true\n            }), [\'cv\', \'py\', \'python\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': PERL_KEYWORDS,\n              \'hashComments\': true,\n              \'multiLineStrings\': true,\n              \'regexLiterals\': 2  // multiline regex literals\n            }), [\'perl\', \'pl\', \'pm\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': RUBY_KEYWORDS,\n              \'hashComments\': true,\n              \'multiLineStrings\': true,\n              \'regexLiterals\': true\n            }), [\'rb\', \'ruby\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': JSCRIPT_KEYWORDS,\n              \'cStyleComments\': true,\n              \'regexLiterals\': true\n            }), [\'javascript\', \'js\', \'ts\', \'typescript\']);\n      registerLangHandler(sourceDecorator({\n              \'keywords\': COFFEE_KEYWORDS,\n              \'hashComments\': 3,  // ### style block comments\n              \'cStyleComments\': true,\n              \'multilineStrings\': true,\n              \'tripleQuotedStrings\': true,\n              \'regexLiterals\': true\n            }), [\'coffee\']);\n      registerLangHandler(\n          createSimpleLexer([], [[PR_STRING, /^[\\s\\S]+/]]), [\'regex\']);\n\n      /** @param {JobT} job */\n      function applyDecorator(job) {\n        var opt_langExtension = job.langExtension;\n\n        try {\n          // Extract tags, and convert the source code to plain text.\n          var sourceAndSpans = extractSourceSpans(job.sourceNode, job.pre);\n          /** Plain text. @type {string} */\n          var source = sourceAndSpans.sourceCode;\n          job.sourceCode = source;\n          job.spans = sourceAndSpans.spans;\n          job.basePos = 0;\n\n          // Apply the appropriate language handler\n          langHandlerForExtension(opt_langExtension, source)(job);\n\n          // Integrate the decorations and tags back into the source code,\n          // modifying the sourceNode in place.\n          recombineTagsAndDecorations(job);\n        } catch (e) {\n          if (win[\'console\']) {\n            console[\'log\'](e && e[\'stack\'] || e);\n          }\n        }\n      }\n\n      /**\n       * Pretty print a chunk of code.\n       * @param sourceCodeHtml {string} The HTML to pretty print.\n       * @param opt_langExtension {string} The language name to use.\n       *     Typically, a filename extension like \'cpp\' or \'java\'.\n       * @param opt_numberLines {number|boolean} True to number lines,\n       *     or the 1-indexed number of the first line in sourceCodeHtml.\n       */\n      function $prettyPrintOne(sourceCodeHtml, opt_langExtension, opt_numberLines) {\n        /** @type{number|boolean} */\n        var nl = opt_numberLines || false;\n        /** @type{string|null} */\n        var langExtension = opt_langExtension || null;\n        /** @type{!Element} */\n        var container = document.createElement(\'div\');\n        // This could cause images to load and onload listeners to fire.\n        // E.g. <img onerror="alert(1337)" src="nosuchimage.png">.\n        // We assume that the inner HTML is from a trusted source.\n        // The pre-tag is required for IE8 which strips newlines from innerHTML\n        // when it is injected into a <pre> tag.\n        // http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie\n        // http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript\n        container.innerHTML = \'<pre>\' + sourceCodeHtml + \'</pre>\';\n        container = /** @type{!Element} */(container.firstChild);\n        if (nl) {\n          numberLines(container, nl, true);\n        }\n\n        /** @type{JobT} */\n        var job = {\n          langExtension: langExtension,\n          numberLines: nl,\n          sourceNode: container,\n          pre: 1,\n          sourceCode: null,\n          basePos: null,\n          spans: null,\n          decorations: null\n        };\n        applyDecorator(job);\n        return container.innerHTML;\n      }\n\n       /**\n        * Find all the {@code <pre>} and {@code <code>} tags in the DOM with\n        * {@code class=prettyprint} and prettify them.\n        *\n        * @param {Function} opt_whenDone called when prettifying is done.\n        * @param {HTMLElement|HTMLDocument} opt_root an element or document\n        *   containing all the elements to pretty print.\n        *   Defaults to {@code document.body}.\n        */\n      function $prettyPrint(opt_whenDone, opt_root) {\n        var root = opt_root || document.body;\n        var doc = root.ownerDocument || document;\n        function byTagName(tn) { return root.getElementsByTagName(tn); }\n        // fetch a list of nodes to rewrite\n        var codeSegments = [byTagName(\'pre\'), byTagName(\'code\'), byTagName(\'xmp\')];\n        var elements = [];\n        for (var i = 0; i < codeSegments.length; ++i) {\n          for (var j = 0, n = codeSegments[i].length; j < n; ++j) {\n            elements.push(codeSegments[i][j]);\n          }\n        }\n        codeSegments = null;\n\n        var clock = Date;\n        if (!clock[\'now\']) {\n          clock = { \'now\': function () { return +(new Date); } };\n        }\n\n        // The loop is broken into a series of continuations to make sure that we\n        // don\'t make the browser unresponsive when rewriting a large page.\n        var k = 0;\n\n        var langExtensionRe = /\\blang(?:uage)?-([\\w.]+)(?!\\S)/;\n        var prettyPrintRe = /\\bprettyprint\\b/;\n        var prettyPrintedRe = /\\bprettyprinted\\b/;\n        var preformattedTagNameRe = /pre|xmp/i;\n        var codeRe = /^code$/i;\n        var preCodeXmpRe = /^(?:pre|code|xmp)$/i;\n        var EMPTY = {};\n\n        function doWork() {\n          var endTime = (win[\'PR_SHOULD_USE_CONTINUATION\'] ?\n                         clock[\'now\']() + 250 /* ms */ :\n                         Infinity);\n          for (; k < elements.length && clock[\'now\']() < endTime; k++) {\n            var cs = elements[k];\n\n            // Look for a preceding comment like\n            // <?prettify lang="..." linenums="..."?>\n            var attrs = EMPTY;\n            {\n              for (var preceder = cs; (preceder = preceder.previousSibling);) {\n                var nt = preceder.nodeType;\n                // <?foo?> is parsed by HTML 5 to a comment node (8)\n                // like <!--?foo?-->, but in XML is a processing instruction\n                var value = (nt === 7 || nt === 8) && preceder.nodeValue;\n                if (value\n                    ? !/^\\??prettify\\b/.test(value)\n                    : (nt !== 3 || /\\S/.test(preceder.nodeValue))) {\n                  // Skip over white-space text nodes but not others.\n                  break;\n                }\n                if (value) {\n                  attrs = {};\n                  value.replace(\n                      /\\b(\\w+)=([\\w:.%+-]+)/g,\n                    function (_, name, value) { attrs[name] = value; });\n                  break;\n                }\n              }\n            }\n\n            var className = cs.className;\n            if ((attrs !== EMPTY || prettyPrintRe.test(className))\n                // Don\'t redo this if we\'ve already done it.\n                // This allows recalling pretty print to just prettyprint elements\n                // that have been added to the page since last call.\n                && !prettyPrintedRe.test(className)) {\n\n              // make sure this is not nested in an already prettified element\n              var nested = false;\n              for (var p = cs.parentNode; p; p = p.parentNode) {\n                var tn = p.tagName;\n                if (preCodeXmpRe.test(tn)\n                    && p.className && prettyPrintRe.test(p.className)) {\n                  nested = true;\n                  break;\n                }\n              }\n              if (!nested) {\n                // Mark done.  If we fail to prettyprint for whatever reason,\n                // we shouldn\'t try again.\n                cs.className += \' prettyprinted\';\n\n                // If the classes includes a language extensions, use it.\n                // Language extensions can be specified like\n                //     <pre class="prettyprint lang-cpp">\n                // the language extension "cpp" is used to find a language handler\n                // as passed to PR.registerLangHandler.\n                // HTML5 recommends that a language be specified using "language-"\n                // as the prefix instead.  Google Code Prettify supports both.\n                // http://dev.w3.org/html5/spec-author-view/the-code-element.html\n                var langExtension = attrs[\'lang\'];\n                if (!langExtension) {\n                  langExtension = className.match(langExtensionRe);\n                  // Support <pre class="prettyprint"><code class="language-c">\n                  var wrapper;\n                  if (!langExtension && (wrapper = childContentWrapper(cs))\n                      && codeRe.test(wrapper.tagName)) {\n                    langExtension = wrapper.className.match(langExtensionRe);\n                  }\n\n                  if (langExtension) { langExtension = langExtension[1]; }\n                }\n\n                var preformatted;\n                if (preformattedTagNameRe.test(cs.tagName)) {\n                  preformatted = 1;\n                } else {\n                  var currentStyle = cs[\'currentStyle\'];\n                  var defaultView = doc.defaultView;\n                  var whitespace = (\n                      currentStyle\n                      ? currentStyle[\'whiteSpace\']\n                      : (defaultView\n                         && defaultView.getComputedStyle)\n                      ? defaultView.getComputedStyle(cs, null)\n                      .getPropertyValue(\'white-space\')\n                      : 0);\n                  preformatted = whitespace\n                      && \'pre\' === whitespace.substring(0, 3);\n                }\n\n                // Look for a class like linenums or linenums:<n> where <n> is the\n                // 1-indexed number of the first line.\n                var lineNums = attrs[\'linenums\'];\n                if (!(lineNums = lineNums === \'true\' || +lineNums)) {\n                  lineNums = className.match(/\\blinenums\\b(?::(\\d+))?/);\n                  lineNums =\n                    lineNums\n                    ? lineNums[1] && lineNums[1].length\n                      ? +lineNums[1] : true\n                    : false;\n                }\n                if (lineNums) { numberLines(cs, lineNums, preformatted); }\n\n                // do the pretty printing\n                var prettyPrintingJob = {\n                  langExtension: langExtension,\n                  sourceNode: cs,\n                  numberLines: lineNums,\n                  pre: preformatted,\n                  sourceCode: null,\n                  basePos: null,\n                  spans: null,\n                  decorations: null\n                };\n                applyDecorator(prettyPrintingJob);\n              }\n            }\n          }\n          if (k < elements.length) {\n            // finish up in a continuation\n            win.setTimeout(doWork, 250);\n          } else if (\'function\' === typeof opt_whenDone) {\n            opt_whenDone();\n          }\n        }\n\n        doWork();\n      }\n\n      /**\n       * Contains functions for creating and registering new language handlers.\n       * @type {Object}\n       */\n      var PR = win[\'PR\'] = {\n            \'createSimpleLexer\': createSimpleLexer,\n            \'registerLangHandler\': registerLangHandler,\n            \'sourceDecorator\': sourceDecorator,\n            \'PR_ATTRIB_NAME\': PR_ATTRIB_NAME,\n            \'PR_ATTRIB_VALUE\': PR_ATTRIB_VALUE,\n            \'PR_COMMENT\': PR_COMMENT,\n            \'PR_DECLARATION\': PR_DECLARATION,\n            \'PR_KEYWORD\': PR_KEYWORD,\n            \'PR_LITERAL\': PR_LITERAL,\n            \'PR_NOCODE\': PR_NOCODE,\n            \'PR_PLAIN\': PR_PLAIN,\n            \'PR_PUNCTUATION\': PR_PUNCTUATION,\n            \'PR_SOURCE\': PR_SOURCE,\n            \'PR_STRING\': PR_STRING,\n            \'PR_TAG\': PR_TAG,\n            \'PR_TYPE\': PR_TYPE,\n            \'prettyPrintOne\':\n               IN_GLOBAL_SCOPE\n                 ? (win[\'prettyPrintOne\'] = $prettyPrintOne)\n                 : (prettyPrintOne = $prettyPrintOne),\n            \'prettyPrint\':\n               IN_GLOBAL_SCOPE\n                 ? (win[\'prettyPrint\'] = $prettyPrint)\n                 : (prettyPrint = $prettyPrint)\n          };\n\n      // Make PR available via the Asynchronous Module Definition (AMD) API.\n      // Per https://github.com/amdjs/amdjs-api/wiki/AMD:\n      // The Asynchronous Module Definition (AMD) API specifies a\n      // mechanism for defining modules such that the module and its\n      // dependencies can be asynchronously loaded.\n      // ...\n      // To allow a clear indicator that a global define function (as\n      // needed for script src browser loading) conforms to the AMD API,\n      // any global define function SHOULD have a property called "amd"\n      // whose value is an object. This helps avoid conflict with any\n      // other existing JavaScript code that could have defined a define()\n      // function that does not conform to the AMD API.\n      var define = win[\'define\'];\n      if (typeof define === "function" && define[\'amd\']) {\n        define("google-code-prettify", [], function () {\n          return PR;\n        });\n      }\n    })();\n\n    return prettyPrint;\n  })();\n\n  // If this script is deferred or async and the document is already\n  // loaded we need to wait for language handlers to load before performing\n  // any autorun.\n  function onLangsLoaded() {\n    if (autorun) {\n      contentLoaded(\n        function () {\n          var n = callbacks.length;\n          var callback = n ? function () {\n            for (var i = 0; i < n; ++i) {\n              (function (i) {\n                win.setTimeout(\n                   function () {\n                     win[\'exports\'][callbacks[i]].apply(win, arguments);\n                   }, 0);\n               })(i);\n            }\n          } : void 0;\n          prettyPrint(callback);\n        });\n    }\n  }\n  checkPendingLanguages();\n\n}());\n', 'message': 'patch previous commit into the files of record and rebuild derivatives\n', 'author_name': 'Mike Samuel', 'lang': 'js'}