1/* http://prismjs.com/download.html?themes=prism-coy&languages=clike+c&plugins=line-highlight+line-numbers */ 2var _self = (typeof window !== 'undefined') 3 ? window // if in browser 4 : ( 5 (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) 6 ? self // if in worker 7 : {} // if in node js 8 ); 9 10/** 11 * Prism: Lightweight, robust, elegant syntax highlighting 12 * MIT license http://www.opensource.org/licenses/mit-license.php/ 13 * @author Lea Verou http://lea.verou.me 14 */ 15 16var Prism = (function(){ 17 18// Private helper vars 19var lang = /\blang(?:uage)?-(\w+)\b/i; 20var uniqueId = 0; 21 22var _ = _self.Prism = { 23 manual: _self.Prism && _self.Prism.manual, 24 util: { 25 encode: function (tokens) { 26 if (tokens instanceof Token) { 27 return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); 28 } else if (_.util.type(tokens) === 'Array') { 29 return tokens.map(_.util.encode); 30 } else { 31 return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); 32 } 33 }, 34 35 type: function (o) { 36 return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1]; 37 }, 38 39 objId: function (obj) { 40 if (!obj['__id']) { 41 Object.defineProperty(obj, '__id', { value: ++uniqueId }); 42 } 43 return obj['__id']; 44 }, 45 46 // Deep clone a language definition (e.g. to extend it) 47 clone: function (o) { 48 var type = _.util.type(o); 49 50 switch (type) { 51 case 'Object': 52 var clone = {}; 53 54 for (var key in o) { 55 if (o.hasOwnProperty(key)) { 56 clone[key] = _.util.clone(o[key]); 57 } 58 } 59 60 return clone; 61 62 case 'Array': 63 // Check for existence for IE8 64 return o.map && o.map(function(v) { return _.util.clone(v); }); 65 } 66 67 return o; 68 } 69 }, 70 71 languages: { 72 extend: function (id, redef) { 73 var lang = _.util.clone(_.languages[id]); 74 75 for (var key in redef) { 76 lang[key] = redef[key]; 77 } 78 79 return lang; 80 }, 81 82 /** 83 * Insert a token before another token in a language literal 84 * As this needs to recreate the object (we cannot actually insert before keys in object literals), 85 * we cannot just provide an object, we need anobject and a key. 86 * @param inside The key (or language id) of the parent 87 * @param before The key to insert before. If not provided, the function appends instead. 88 * @param insert Object with the key/value pairs to insert 89 * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted. 90 */ 91 insertBefore: function (inside, before, insert, root) { 92 root = root || _.languages; 93 var grammar = root[inside]; 94 95 if (arguments.length == 2) { 96 insert = arguments[1]; 97 98 for (var newToken in insert) { 99 if (insert.hasOwnProperty(newToken)) { 100 grammar[newToken] = insert[newToken]; 101 } 102 } 103 104 return grammar; 105 } 106 107 var ret = {}; 108 109 for (var token in grammar) { 110 111 if (grammar.hasOwnProperty(token)) { 112 113 if (token == before) { 114 115 for (var newToken in insert) { 116 117 if (insert.hasOwnProperty(newToken)) { 118 ret[newToken] = insert[newToken]; 119 } 120 } 121 } 122 123 ret[token] = grammar[token]; 124 } 125 } 126 127 // Update references in other language definitions 128 _.languages.DFS(_.languages, function(key, value) { 129 if (value === root[inside] && key != inside) { 130 this[key] = ret; 131 } 132 }); 133 134 return root[inside] = ret; 135 }, 136 137 // Traverse a language definition with Depth First Search 138 DFS: function(o, callback, type, visited) { 139 visited = visited || {}; 140 for (var i in o) { 141 if (o.hasOwnProperty(i)) { 142 callback.call(o, i, o[i], type || i); 143 144 if (_.util.type(o[i]) === 'Object' && !visited[_.util.objId(o[i])]) { 145 visited[_.util.objId(o[i])] = true; 146 _.languages.DFS(o[i], callback, null, visited); 147 } 148 else if (_.util.type(o[i]) === 'Array' && !visited[_.util.objId(o[i])]) { 149 visited[_.util.objId(o[i])] = true; 150 _.languages.DFS(o[i], callback, i, visited); 151 } 152 } 153 } 154 } 155 }, 156 plugins: {}, 157 158 highlightAll: function(async, callback) { 159 var env = { 160 callback: callback, 161 selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code' 162 }; 163 164 _.hooks.run("before-highlightall", env); 165 166 var elements = env.elements || document.querySelectorAll(env.selector); 167 168 for (var i=0, element; element = elements[i++];) { 169 _.highlightElement(element, async === true, env.callback); 170 } 171 }, 172 173 highlightElement: function(element, async, callback) { 174 // Find language 175 var language, grammar, parent = element; 176 177 while (parent && !lang.test(parent.className)) { 178 parent = parent.parentNode; 179 } 180 181 if (parent) { 182 language = (parent.className.match(lang) || [,''])[1].toLowerCase(); 183 grammar = _.languages[language]; 184 } 185 186 // Set language on the element, if not present 187 element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; 188 189 // Set language on the parent, for styling 190 parent = element.parentNode; 191 192 if (/pre/i.test(parent.nodeName)) { 193 parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; 194 } 195 196 var code = element.textContent; 197 198 var env = { 199 element: element, 200 language: language, 201 grammar: grammar, 202 code: code 203 }; 204 205 _.hooks.run('before-sanity-check', env); 206 207 if (!env.code || !env.grammar) { 208 if (env.code) { 209 _.hooks.run('before-highlight', env); 210 env.element.textContent = env.code; 211 _.hooks.run('after-highlight', env); 212 } 213 _.hooks.run('complete', env); 214 return; 215 } 216 217 _.hooks.run('before-highlight', env); 218 219 if (async && _self.Worker) { 220 var worker = new Worker(_.filename); 221 222 worker.onmessage = function(evt) { 223 env.highlightedCode = evt.data; 224 225 _.hooks.run('before-insert', env); 226 227 env.element.innerHTML = env.highlightedCode; 228 229 callback && callback.call(env.element); 230 _.hooks.run('after-highlight', env); 231 _.hooks.run('complete', env); 232 }; 233 234 worker.postMessage(JSON.stringify({ 235 language: env.language, 236 code: env.code, 237 immediateClose: true 238 })); 239 } 240 else { 241 env.highlightedCode = _.highlight(env.code, env.grammar, env.language); 242 243 _.hooks.run('before-insert', env); 244 245 env.element.innerHTML = env.highlightedCode; 246 247 callback && callback.call(element); 248 249 _.hooks.run('after-highlight', env); 250 _.hooks.run('complete', env); 251 } 252 }, 253 254 highlight: function (text, grammar, language) { 255 var tokens = _.tokenize(text, grammar); 256 return Token.stringify(_.util.encode(tokens), language); 257 }, 258 259 matchGrammar: function (text, strarr, grammar, index, startPos, oneshot, target) { 260 var Token = _.Token; 261 262 for (var token in grammar) { 263 if(!grammar.hasOwnProperty(token) || !grammar[token]) { 264 continue; 265 } 266 267 if (token == target) { 268 return; 269 } 270 271 var patterns = grammar[token]; 272 patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns]; 273 274 for (var j = 0; j < patterns.length; ++j) { 275 var pattern = patterns[j], 276 inside = pattern.inside, 277 lookbehind = !!pattern.lookbehind, 278 greedy = !!pattern.greedy, 279 lookbehindLength = 0, 280 alias = pattern.alias; 281 282 if (greedy && !pattern.pattern.global) { 283 // Without the global flag, lastIndex won't work 284 var flags = pattern.pattern.toString().match(/[imuy]*$/)[0]; 285 pattern.pattern = RegExp(pattern.pattern.source, flags + "g"); 286 } 287 288 pattern = pattern.pattern || pattern; 289 290 // Don’t cache length as it changes during the loop 291 for (var i = index, pos = startPos; i < strarr.length; pos += strarr[i].length, ++i) { 292 293 var str = strarr[i]; 294 295 if (strarr.length > text.length) { 296 // Something went terribly wrong, ABORT, ABORT! 297 return; 298 } 299 300 if (str instanceof Token) { 301 continue; 302 } 303 304 pattern.lastIndex = 0; 305 306 var match = pattern.exec(str), 307 delNum = 1; 308 309 // Greedy patterns can override/remove up to two previously matched tokens 310 if (!match && greedy && i != strarr.length - 1) { 311 pattern.lastIndex = pos; 312 match = pattern.exec(text); 313 if (!match) { 314 break; 315 } 316 317 var from = match.index + (lookbehind ? match[1].length : 0), 318 to = match.index + match[0].length, 319 k = i, 320 p = pos; 321 322 for (var len = strarr.length; k < len && (p < to || (!strarr[k].type && !strarr[k - 1].greedy)); ++k) { 323 p += strarr[k].length; 324 // Move the index i to the element in strarr that is closest to from 325 if (from >= p) { 326 ++i; 327 pos = p; 328 } 329 } 330 331 /* 332 * If strarr[i] is a Token, then the match starts inside another Token, which is invalid 333 * If strarr[k - 1] is greedy we are in conflict with another greedy pattern 334 */ 335 if (strarr[i] instanceof Token || strarr[k - 1].greedy) { 336 continue; 337 } 338 339 // Number of tokens to delete and replace with the new match 340 delNum = k - i; 341 str = text.slice(pos, p); 342 match.index -= pos; 343 } 344 345 if (!match) { 346 if (oneshot) { 347 break; 348 } 349 350 continue; 351 } 352 353 if(lookbehind) { 354 lookbehindLength = match[1].length; 355 } 356 357 var from = match.index + lookbehindLength, 358 match = match[0].slice(lookbehindLength), 359 to = from + match.length, 360 before = str.slice(0, from), 361 after = str.slice(to); 362 363 var args = [i, delNum]; 364 365 if (before) { 366 ++i; 367 pos += before.length; 368 args.push(before); 369 } 370 371 var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy); 372 373 args.push(wrapped); 374 375 if (after) { 376 args.push(after); 377 } 378 379 Array.prototype.splice.apply(strarr, args); 380 381 if (delNum != 1) 382 _.matchGrammar(text, strarr, grammar, i, pos, true, token); 383 384 if (oneshot) 385 break; 386 } 387 } 388 } 389 }, 390 391 tokenize: function(text, grammar, language) { 392 var strarr = [text]; 393 394 var rest = grammar.rest; 395 396 if (rest) { 397 for (var token in rest) { 398 grammar[token] = rest[token]; 399 } 400 401 delete grammar.rest; 402 } 403 404 _.matchGrammar(text, strarr, grammar, 0, 0, false); 405 406 return strarr; 407 }, 408 409 hooks: { 410 all: {}, 411 412 add: function (name, callback) { 413 var hooks = _.hooks.all; 414 415 hooks[name] = hooks[name] || []; 416 417 hooks[name].push(callback); 418 }, 419 420 run: function (name, env) { 421 var callbacks = _.hooks.all[name]; 422 423 if (!callbacks || !callbacks.length) { 424 return; 425 } 426 427 for (var i=0, callback; callback = callbacks[i++];) { 428 callback(env); 429 } 430 } 431 } 432}; 433 434var Token = _.Token = function(type, content, alias, matchedStr, greedy) { 435 this.type = type; 436 this.content = content; 437 this.alias = alias; 438 // Copy of the full string this token was created from 439 this.length = (matchedStr || "").length|0; 440 this.greedy = !!greedy; 441}; 442 443Token.stringify = function(o, language, parent) { 444 if (typeof o == 'string') { 445 return o; 446 } 447 448 if (_.util.type(o) === 'Array') { 449 return o.map(function(element) { 450 return Token.stringify(element, language, o); 451 }).join(''); 452 } 453 454 var env = { 455 type: o.type, 456 content: Token.stringify(o.content, language, parent), 457 tag: 'span', 458 classes: ['token', o.type], 459 attributes: {}, 460 language: language, 461 parent: parent 462 }; 463 464 if (env.type == 'comment') { 465 env.attributes['spellcheck'] = 'true'; 466 } 467 468 if (o.alias) { 469 var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; 470 Array.prototype.push.apply(env.classes, aliases); 471 } 472 473 _.hooks.run('wrap', env); 474 475 var attributes = Object.keys(env.attributes).map(function(name) { 476 return name + '="' + (env.attributes[name] || '').replace(/"/g, '"') + '"'; 477 }).join(' '); 478 479 return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + '</' + env.tag + '>'; 480 481}; 482 483if (!_self.document) { 484 if (!_self.addEventListener) { 485 // in Node.js 486 return _self.Prism; 487 } 488 // In worker 489 _self.addEventListener('message', function(evt) { 490 var message = JSON.parse(evt.data), 491 lang = message.language, 492 code = message.code, 493 immediateClose = message.immediateClose; 494 495 _self.postMessage(_.highlight(code, _.languages[lang], lang)); 496 if (immediateClose) { 497 _self.close(); 498 } 499 }, false); 500 501 return _self.Prism; 502} 503 504//Get current script and highlight 505var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop(); 506 507if (script) { 508 _.filename = script.src; 509 510 if (document.addEventListener && !_.manual && !script.hasAttribute('data-manual')) { 511 if(document.readyState !== "loading") { 512 if (window.requestAnimationFrame) { 513 window.requestAnimationFrame(_.highlightAll); 514 } else { 515 window.setTimeout(_.highlightAll, 16); 516 } 517 } 518 else { 519 document.addEventListener('DOMContentLoaded', _.highlightAll); 520 } 521 } 522} 523 524return _self.Prism; 525 526})(); 527 528if (typeof module !== 'undefined' && module.exports) { 529 module.exports = Prism; 530} 531 532// hack for components to work correctly in node.js 533if (typeof global !== 'undefined') { 534 global.Prism = Prism; 535} 536; 537Prism.languages.clike = { 538 'comment': [ 539 { 540 pattern: /(^|[^\\])\/\*[\s\S]*?\*\//, 541 lookbehind: true 542 }, 543 { 544 pattern: /(^|[^\\:])\/\/.*/, 545 lookbehind: true 546 } 547 ], 548 'string': { 549 pattern: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/, 550 greedy: true 551 }, 552 'class-name': { 553 pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i, 554 lookbehind: true, 555 inside: { 556 punctuation: /(\.|\\)/ 557 } 558 }, 559 'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/, 560 'boolean': /\b(true|false)\b/, 561 'function': /[a-z0-9_]+(?=\()/i, 562 'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i, 563 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/, 564 'punctuation': /[{}[\];(),.:]/ 565}; 566 567Prism.languages.c = Prism.languages.extend('clike', { 568 'keyword': /\b(asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while)\b/, 569 'operator': /\-[>-]?|\+\+?|!=?|<<?=?|>>?=?|==?|&&?|\|?\||[~^%?*\/]/, 570 'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)[ful]*\b/i 571}); 572 573Prism.languages.insertBefore('c', 'string', { 574 'macro': { 575 // allow for multiline macro definitions 576 // spaces after the # character compile fine with gcc 577 pattern: /(^\s*)#\s*[a-z]+([^\r\n\\]|\\.|\\(?:\r\n?|\n))*/im, 578 lookbehind: true, 579 alias: 'property', 580 inside: { 581 // highlight the path of the include statement as a string 582 'string': { 583 pattern: /(#\s*include\s*)(<.+?>|("|')(\\?.)+?\3)/, 584 lookbehind: true 585 }, 586 // highlight macro directives as keywords 587 'directive': { 588 pattern: /(#\s*)\b(define|elif|else|endif|error|ifdef|ifndef|if|import|include|line|pragma|undef|using)\b/, 589 lookbehind: true, 590 alias: 'keyword' 591 } 592 } 593 }, 594 // highlight predefined macros as constants 595 'constant': /\b(__FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|stdin|stdout|stderr)\b/ 596}); 597 598delete Prism.languages.c['class-name']; 599delete Prism.languages.c['boolean']; 600 601(function(){ 602 603if (typeof self === 'undefined' || !self.Prism || !self.document || !document.querySelector) { 604 return; 605} 606 607function $$(expr, con) { 608 return Array.prototype.slice.call((con || document).querySelectorAll(expr)); 609} 610 611function hasClass(element, className) { 612 className = " " + className + " "; 613 return (" " + element.className + " ").replace(/[\n\t]/g, " ").indexOf(className) > -1 614} 615 616// Some browsers round the line-height, others don't. 617// We need to test for it to position the elements properly. 618var isLineHeightRounded = (function() { 619 var res; 620 return function() { 621 if(typeof res === 'undefined') { 622 var d = document.createElement('div'); 623 d.style.fontSize = '13px'; 624 d.style.lineHeight = '1.5'; 625 d.style.padding = 0; 626 d.style.border = 0; 627 d.innerHTML = ' <br /> '; 628 document.body.appendChild(d); 629 // Browsers that round the line-height should have offsetHeight === 38 630 // The others should have 39. 631 res = d.offsetHeight === 38; 632 document.body.removeChild(d); 633 } 634 return res; 635 } 636}()); 637 638function getOffsetById(id) { 639 var element = document.getElementById(id); 640 var bodyRect = document.body.getBoundingClientRect(); 641 var elemRect = element.getBoundingClientRect(); 642 var elementOffset = elemRect.top - bodyRect.top; 643 return elementOffset; 644} 645 646function highlightLines(pre, lines, classes) { 647 var ranges = lines.replace(/\s+/g, '').split(','); 648 var offset = getOffsetById('browsing_file'); 649 650 var parseMethod = isLineHeightRounded() ? parseInt : parseFloat; 651 var lineHeight = parseMethod(getComputedStyle(pre).lineHeight); 652 653 for (var i=0, range; range = ranges[i++];) { 654 range = range.split('-'); 655 656 var start = +range[0], 657 end = +range[1] || start; 658 659 var line = document.createElement('div'); 660 661 line.textContent = Array(end - start + 2).join(' \n'); 662 line.setAttribute('aria-hidden', 'true'); 663 line.className = (classes || '') + ' line-highlight'; 664 665 //if the line-numbers plugin is enabled, then there is no reason for this plugin to display the line numbers 666 if(!hasClass(pre, 'line-numbers')) { 667 line.setAttribute('data-start', start); 668 669 if(end > start) { 670 line.setAttribute('data-end', end); 671 } 672 } 673 674 line.style.top = (getOffsetById('line_no' + start) - offset) + 'px'; 675 676 //allow this to play nicely with the line-numbers plugin 677 if(hasClass(pre, 'line-numbers')) { 678 //need to attack to pre as when line-numbers is enabled, the code tag is relatively which screws up the positioning 679 pre.appendChild(line); 680 } else { 681 (pre.querySelector('code') || pre).appendChild(line); 682 } 683 } 684} 685 686function applyHash() { 687 var hash = location.hash.slice(1); 688 689 // Remove pre-existing temporary lines 690 $$('.temporary.line-highlight').forEach(function (line) { 691 line.parentNode.removeChild(line); 692 }); 693 694 var range = (hash.match(/\.([\d,-]+)$/) || [,''])[1]; 695 696 if (!range || document.getElementById(hash)) { 697 return; 698 } 699 700 var id = hash.slice(0, hash.lastIndexOf('.')), 701 pre = document.getElementById(id); 702 703 if (!pre) { 704 return; 705 } 706 707 if (!pre.hasAttribute('data-line')) { 708 pre.setAttribute('data-line', ''); 709 } 710 711 highlightLines(pre, range, 'temporary '); 712 713 document.querySelector('.temporary.line-highlight').scrollIntoView(); 714} 715 716var fakeTimer = 0; // Hack to limit the number of times applyHash() runs 717 718Prism.hooks.add('before-sanity-check', function(env) { 719 var pre = env.element.parentNode; 720 var lines = pre && pre.getAttribute('data-line'); 721 722 if (!pre || !lines || !/pre/i.test(pre.nodeName)) { 723 return; 724 } 725 726 /* 727 * Cleanup for other plugins (e.g. autoloader). 728 * 729 * Sometimes <code> blocks are highlighted multiple times. It is necessary 730 * to cleanup any left-over tags, because the whitespace inside of the <div> 731 * tags change the content of the <code> tag. 732 */ 733 var num = 0; 734 $$('.line-highlight', pre).forEach(function (line) { 735 num += line.textContent.length; 736 line.parentNode.removeChild(line); 737 }); 738 739 // Remove extra whitespace 740 if (num && /^( \n)+$/.test(env.code.slice(-num))) { 741 env.code = env.code.slice(0, -num); 742 } 743}); 744 745Prism.hooks.add('complete', function (env) { 746 if (!env.code) { 747 return; 748 } 749 750 // works only for <code> wrapped inside <pre> (not inline) 751 var pre = env.element.parentNode; 752 var clsReg = /\s*\bline-numbers\b\s*/; 753 if ( 754 !pre || !/pre/i.test(pre.nodeName) || 755 // Abort only if nor the <pre> nor the <code> have the class 756 (!clsReg.test(pre.className) && !clsReg.test(env.element.className)) 757 ) { 758 return; 759 } 760 761 if (env.element.querySelector(".line-numbers-rows")) { 762 // Abort if line numbers already exists 763 return; 764 } 765 766 if (clsReg.test(env.element.className)) { 767 // Remove the class "line-numbers" from the <code> 768 env.element.className = env.element.className.replace(clsReg, ''); 769 } 770 if (!clsReg.test(pre.className)) { 771 // Add the class "line-numbers" to the <pre> 772 pre.className += ' line-numbers'; 773 } 774 775 var match = env.code.match(/\n(?!$)/g); 776 var linesNum = match ? match.length + 1 : 1; 777 var lineNumbersWrapper; 778 779 var lines = ''; 780 for (let i = 1; i < linesNum + 1; i++) { 781 lines += '<span id="line_no' + i + '"></span>'; 782 } 783 784 lineNumbersWrapper = document.createElement('span'); 785 lineNumbersWrapper.setAttribute('aria-hidden', 'true'); 786 lineNumbersWrapper.className = 'line-numbers-rows'; 787 lineNumbersWrapper.innerHTML = lines; 788 789 if (pre.hasAttribute('data-start')) { 790 pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1); 791 } 792 793 env.element.appendChild(lineNumbersWrapper); 794 795}); 796 797Prism.hooks.add('complete', function(env) { 798 var pre = env.element.parentNode; 799 var lines = pre && pre.getAttribute('data-line'); 800 801 if (!pre || !lines || !/pre/i.test(pre.nodeName)) { 802 return; 803 } 804 805 clearTimeout(fakeTimer); 806 807 highlightLines(pre, lines); 808 809 fakeTimer = setTimeout(applyHash, 1); 810}); 811 812if(window.addEventListener) { 813 window.addEventListener('hashchange', applyHash); 814} 815 816})(); 817 818(function() { 819 820if (typeof self === 'undefined' || !self.Prism || !self.document) { 821 return; 822} 823 824}()); 825