UNPKG

168 kBJavaScriptView Raw
1;/*! showdown v 1.8.2 - 11-11-2017 */
2(function(){
3/**
4 * Created by Tivie on 13-07-2015.
5 */
6
7function getDefaultOpts (simple) {
8 'use strict';
9
10 var defaultOptions = {
11 omitExtraWLInCodeBlocks: {
12 defaultValue: false,
13 describe: 'Omit the default extra whiteline added to code blocks',
14 type: 'boolean'
15 },
16 noHeaderId: {
17 defaultValue: false,
18 describe: 'Turn on/off generated header id',
19 type: 'boolean'
20 },
21 prefixHeaderId: {
22 defaultValue: false,
23 describe: 'Add a prefix to the generated header ids. Passing a string will prefix that string to the header id. Setting to true will add a generic \'section-\' prefix',
24 type: 'string'
25 },
26 rawPrefixHeaderId: {
27 defaultValue: false,
28 describe: 'Setting this option to true will prevent showdown from modifying the prefix. This might result in malformed IDs (if, for instance, the " char is used in the prefix)',
29 type: 'boolean'
30 },
31 ghCompatibleHeaderId: {
32 defaultValue: false,
33 describe: 'Generate header ids compatible with github style (spaces are replaced with dashes, a bunch of non alphanumeric chars are removed)',
34 type: 'boolean'
35 },
36 rawHeaderId: {
37 defaultValue: false,
38 describe: 'Remove only spaces, \' and " from generated header ids (including prefixes), replacing them with dashes (-). WARNING: This might result in malformed ids',
39 type: 'boolean'
40 },
41 headerLevelStart: {
42 defaultValue: false,
43 describe: 'The header blocks level start',
44 type: 'integer'
45 },
46 parseImgDimensions: {
47 defaultValue: false,
48 describe: 'Turn on/off image dimension parsing',
49 type: 'boolean'
50 },
51 simplifiedAutoLink: {
52 defaultValue: false,
53 describe: 'Turn on/off GFM autolink style',
54 type: 'boolean'
55 },
56 excludeTrailingPunctuationFromURLs: {
57 defaultValue: false,
58 describe: 'Excludes trailing punctuation from links generated with autoLinking',
59 type: 'boolean'
60 },
61 literalMidWordUnderscores: {
62 defaultValue: false,
63 describe: 'Parse midword underscores as literal underscores',
64 type: 'boolean'
65 },
66 literalMidWordAsterisks: {
67 defaultValue: false,
68 describe: 'Parse midword asterisks as literal asterisks',
69 type: 'boolean'
70 },
71 strikethrough: {
72 defaultValue: false,
73 describe: 'Turn on/off strikethrough support',
74 type: 'boolean'
75 },
76 tables: {
77 defaultValue: false,
78 describe: 'Turn on/off tables support',
79 type: 'boolean'
80 },
81 tablesHeaderId: {
82 defaultValue: false,
83 describe: 'Add an id to table headers',
84 type: 'boolean'
85 },
86 ghCodeBlocks: {
87 defaultValue: true,
88 describe: 'Turn on/off GFM fenced code blocks support',
89 type: 'boolean'
90 },
91 tasklists: {
92 defaultValue: false,
93 describe: 'Turn on/off GFM tasklist support',
94 type: 'boolean'
95 },
96 smoothLivePreview: {
97 defaultValue: false,
98 describe: 'Prevents weird effects in live previews due to incomplete input',
99 type: 'boolean'
100 },
101 smartIndentationFix: {
102 defaultValue: false,
103 description: 'Tries to smartly fix indentation in es6 strings',
104 type: 'boolean'
105 },
106 disableForced4SpacesIndentedSublists: {
107 defaultValue: false,
108 description: 'Disables the requirement of indenting nested sublists by 4 spaces',
109 type: 'boolean'
110 },
111 simpleLineBreaks: {
112 defaultValue: false,
113 description: 'Parses simple line breaks as <br> (GFM Style)',
114 type: 'boolean'
115 },
116 requireSpaceBeforeHeadingText: {
117 defaultValue: false,
118 description: 'Makes adding a space between `#` and the header text mandatory (GFM Style)',
119 type: 'boolean'
120 },
121 ghMentions: {
122 defaultValue: false,
123 description: 'Enables github @mentions',
124 type: 'boolean'
125 },
126 ghMentionsLink: {
127 defaultValue: 'https://github.com/{u}',
128 description: 'Changes the link generated by @mentions. Only applies if ghMentions option is enabled.',
129 type: 'string'
130 },
131 encodeEmails: {
132 defaultValue: true,
133 description: 'Encode e-mail addresses through the use of Character Entities, transforming ASCII e-mail addresses into its equivalent decimal entities',
134 type: 'boolean'
135 },
136 openLinksInNewWindow: {
137 defaultValue: false,
138 description: 'Open all links in new windows',
139 type: 'boolean'
140 },
141 backslashEscapesHTMLTags: {
142 defaultValue: false,
143 description: 'Support for HTML Tag escaping. ex: \<div>foo\</div>',
144 type: 'boolean'
145 },
146 emoji: {
147 defaultValue: false,
148 description: 'Enable emoji support. Ex: `this is a :smile: emoji`',
149 type: 'boolean'
150 },
151 underline: {
152 defaultValue: false,
153 description: 'Enable support for underline. Syntax is double or triple underscores: `__underline word__`. With this option enabled, underscores no longer parses into `<em>` and `<strong>`',
154 type: 'boolean'
155 }
156 };
157 if (simple === false) {
158 return JSON.parse(JSON.stringify(defaultOptions));
159 }
160 var ret = {};
161 for (var opt in defaultOptions) {
162 if (defaultOptions.hasOwnProperty(opt)) {
163 ret[opt] = defaultOptions[opt].defaultValue;
164 }
165 }
166 return ret;
167}
168
169function allOptionsOn () {
170 'use strict';
171 var options = getDefaultOpts(true),
172 ret = {};
173 for (var opt in options) {
174 if (options.hasOwnProperty(opt)) {
175 ret[opt] = true;
176 }
177 }
178 return ret;
179}
180
181/**
182 * Created by Tivie on 06-01-2015.
183 */
184
185// Private properties
186var showdown = {},
187 parsers = {},
188 extensions = {},
189 globalOptions = getDefaultOpts(true),
190 setFlavor = 'vanilla',
191 flavor = {
192 github: {
193 omitExtraWLInCodeBlocks: true,
194 simplifiedAutoLink: true,
195 excludeTrailingPunctuationFromURLs: true,
196 literalMidWordUnderscores: true,
197 strikethrough: true,
198 tables: true,
199 tablesHeaderId: true,
200 ghCodeBlocks: true,
201 tasklists: true,
202 disableForced4SpacesIndentedSublists: true,
203 simpleLineBreaks: true,
204 requireSpaceBeforeHeadingText: true,
205 ghCompatibleHeaderId: true,
206 ghMentions: true,
207 backslashEscapesHTMLTags: true,
208 emoji: true
209 },
210 original: {
211 noHeaderId: true,
212 ghCodeBlocks: false
213 },
214 ghost: {
215 omitExtraWLInCodeBlocks: true,
216 parseImgDimensions: true,
217 simplifiedAutoLink: true,
218 excludeTrailingPunctuationFromURLs: true,
219 literalMidWordUnderscores: true,
220 strikethrough: true,
221 tables: true,
222 tablesHeaderId: true,
223 ghCodeBlocks: true,
224 tasklists: true,
225 smoothLivePreview: true,
226 simpleLineBreaks: true,
227 requireSpaceBeforeHeadingText: true,
228 ghMentions: false,
229 encodeEmails: true
230 },
231 vanilla: getDefaultOpts(true),
232 allOn: allOptionsOn()
233 };
234
235/**
236 * helper namespace
237 * @type {{}}
238 */
239showdown.helper = {};
240
241/**
242 * TODO LEGACY SUPPORT CODE
243 * @type {{}}
244 */
245showdown.extensions = {};
246
247/**
248 * Set a global option
249 * @static
250 * @param {string} key
251 * @param {*} value
252 * @returns {showdown}
253 */
254showdown.setOption = function (key, value) {
255 'use strict';
256 globalOptions[key] = value;
257 return this;
258};
259
260/**
261 * Get a global option
262 * @static
263 * @param {string} key
264 * @returns {*}
265 */
266showdown.getOption = function (key) {
267 'use strict';
268 return globalOptions[key];
269};
270
271/**
272 * Get the global options
273 * @static
274 * @returns {{}}
275 */
276showdown.getOptions = function () {
277 'use strict';
278 return globalOptions;
279};
280
281/**
282 * Reset global options to the default values
283 * @static
284 */
285showdown.resetOptions = function () {
286 'use strict';
287 globalOptions = getDefaultOpts(true);
288};
289
290/**
291 * Set the flavor showdown should use as default
292 * @param {string} name
293 */
294showdown.setFlavor = function (name) {
295 'use strict';
296 if (!flavor.hasOwnProperty(name)) {
297 throw Error(name + ' flavor was not found');
298 }
299 showdown.resetOptions();
300 var preset = flavor[name];
301 setFlavor = name;
302 for (var option in preset) {
303 if (preset.hasOwnProperty(option)) {
304 globalOptions[option] = preset[option];
305 }
306 }
307};
308
309/**
310 * Get the currently set flavor
311 * @returns {string}
312 */
313showdown.getFlavor = function () {
314 'use strict';
315 return setFlavor;
316};
317
318/**
319 * Get the options of a specified flavor. Returns undefined if the flavor was not found
320 * @param {string} name Name of the flavor
321 * @returns {{}|undefined}
322 */
323showdown.getFlavorOptions = function (name) {
324 'use strict';
325 if (flavor.hasOwnProperty(name)) {
326 return flavor[name];
327 }
328};
329
330/**
331 * Get the default options
332 * @static
333 * @param {boolean} [simple=true]
334 * @returns {{}}
335 */
336showdown.getDefaultOptions = function (simple) {
337 'use strict';
338 return getDefaultOpts(simple);
339};
340
341/**
342 * Get or set a subParser
343 *
344 * subParser(name) - Get a registered subParser
345 * subParser(name, func) - Register a subParser
346 * @static
347 * @param {string} name
348 * @param {function} [func]
349 * @returns {*}
350 */
351showdown.subParser = function (name, func) {
352 'use strict';
353 if (showdown.helper.isString(name)) {
354 if (typeof func !== 'undefined') {
355 parsers[name] = func;
356 } else {
357 if (parsers.hasOwnProperty(name)) {
358 return parsers[name];
359 } else {
360 throw Error('SubParser named ' + name + ' not registered!');
361 }
362 }
363 }
364};
365
366/**
367 * Gets or registers an extension
368 * @static
369 * @param {string} name
370 * @param {object|function=} ext
371 * @returns {*}
372 */
373showdown.extension = function (name, ext) {
374 'use strict';
375
376 if (!showdown.helper.isString(name)) {
377 throw Error('Extension \'name\' must be a string');
378 }
379
380 name = showdown.helper.stdExtName(name);
381
382 // Getter
383 if (showdown.helper.isUndefined(ext)) {
384 if (!extensions.hasOwnProperty(name)) {
385 throw Error('Extension named ' + name + ' is not registered!');
386 }
387 return extensions[name];
388
389 // Setter
390 } else {
391 // Expand extension if it's wrapped in a function
392 if (typeof ext === 'function') {
393 ext = ext();
394 }
395
396 // Ensure extension is an array
397 if (!showdown.helper.isArray(ext)) {
398 ext = [ext];
399 }
400
401 var validExtension = validate(ext, name);
402
403 if (validExtension.valid) {
404 extensions[name] = ext;
405 } else {
406 throw Error(validExtension.error);
407 }
408 }
409};
410
411/**
412 * Gets all extensions registered
413 * @returns {{}}
414 */
415showdown.getAllExtensions = function () {
416 'use strict';
417 return extensions;
418};
419
420/**
421 * Remove an extension
422 * @param {string} name
423 */
424showdown.removeExtension = function (name) {
425 'use strict';
426 delete extensions[name];
427};
428
429/**
430 * Removes all extensions
431 */
432showdown.resetExtensions = function () {
433 'use strict';
434 extensions = {};
435};
436
437/**
438 * Validate extension
439 * @param {array} extension
440 * @param {string} name
441 * @returns {{valid: boolean, error: string}}
442 */
443function validate (extension, name) {
444 'use strict';
445
446 var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
447 ret = {
448 valid: true,
449 error: ''
450 };
451
452 if (!showdown.helper.isArray(extension)) {
453 extension = [extension];
454 }
455
456 for (var i = 0; i < extension.length; ++i) {
457 var baseMsg = errMsg + ' sub-extension ' + i + ': ',
458 ext = extension[i];
459 if (typeof ext !== 'object') {
460 ret.valid = false;
461 ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
462 return ret;
463 }
464
465 if (!showdown.helper.isString(ext.type)) {
466 ret.valid = false;
467 ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
468 return ret;
469 }
470
471 var type = ext.type = ext.type.toLowerCase();
472
473 // normalize extension type
474 if (type === 'language') {
475 type = ext.type = 'lang';
476 }
477
478 if (type === 'html') {
479 type = ext.type = 'output';
480 }
481
482 if (type !== 'lang' && type !== 'output' && type !== 'listener') {
483 ret.valid = false;
484 ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
485 return ret;
486 }
487
488 if (type === 'listener') {
489 if (showdown.helper.isUndefined(ext.listeners)) {
490 ret.valid = false;
491 ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
492 return ret;
493 }
494 } else {
495 if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
496 ret.valid = false;
497 ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
498 return ret;
499 }
500 }
501
502 if (ext.listeners) {
503 if (typeof ext.listeners !== 'object') {
504 ret.valid = false;
505 ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
506 return ret;
507 }
508 for (var ln in ext.listeners) {
509 if (ext.listeners.hasOwnProperty(ln)) {
510 if (typeof ext.listeners[ln] !== 'function') {
511 ret.valid = false;
512 ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
513 ' must be a function but ' + typeof ext.listeners[ln] + ' given';
514 return ret;
515 }
516 }
517 }
518 }
519
520 if (ext.filter) {
521 if (typeof ext.filter !== 'function') {
522 ret.valid = false;
523 ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
524 return ret;
525 }
526 } else if (ext.regex) {
527 if (showdown.helper.isString(ext.regex)) {
528 ext.regex = new RegExp(ext.regex, 'g');
529 }
530 if (!(ext.regex instanceof RegExp)) {
531 ret.valid = false;
532 ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
533 return ret;
534 }
535 if (showdown.helper.isUndefined(ext.replace)) {
536 ret.valid = false;
537 ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
538 return ret;
539 }
540 }
541 }
542 return ret;
543}
544
545/**
546 * Validate extension
547 * @param {object} ext
548 * @returns {boolean}
549 */
550showdown.validateExtension = function (ext) {
551 'use strict';
552
553 var validateExtension = validate(ext, null);
554 if (!validateExtension.valid) {
555 console.warn(validateExtension.error);
556 return false;
557 }
558 return true;
559};
560
561/**
562 * showdownjs helper functions
563 */
564
565if (!showdown.hasOwnProperty('helper')) {
566 showdown.helper = {};
567}
568
569/**
570 * Check if var is string
571 * @static
572 * @param {string} a
573 * @returns {boolean}
574 */
575showdown.helper.isString = function (a) {
576 'use strict';
577 return (typeof a === 'string' || a instanceof String);
578};
579
580/**
581 * Check if var is a function
582 * @static
583 * @param {*} a
584 * @returns {boolean}
585 */
586showdown.helper.isFunction = function (a) {
587 'use strict';
588 var getType = {};
589 return a && getType.toString.call(a) === '[object Function]';
590};
591
592/**
593 * isArray helper function
594 * @static
595 * @param {*} a
596 * @returns {boolean}
597 */
598showdown.helper.isArray = function (a) {
599 'use strict';
600 return Array.isArray(a);
601};
602
603/**
604 * Check if value is undefined
605 * @static
606 * @param {*} value The value to check.
607 * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
608 */
609showdown.helper.isUndefined = function (value) {
610 'use strict';
611 return typeof value === 'undefined';
612};
613
614/**
615 * ForEach helper function
616 * Iterates over Arrays and Objects (own properties only)
617 * @static
618 * @param {*} obj
619 * @param {function} callback Accepts 3 params: 1. value, 2. key, 3. the original array/object
620 */
621showdown.helper.forEach = function (obj, callback) {
622 'use strict';
623 // check if obj is defined
624 if (showdown.helper.isUndefined(obj)) {
625 throw new Error('obj param is required');
626 }
627
628 if (showdown.helper.isUndefined(callback)) {
629 throw new Error('callback param is required');
630 }
631
632 if (!showdown.helper.isFunction(callback)) {
633 throw new Error('callback param must be a function/closure');
634 }
635
636 if (typeof obj.forEach === 'function') {
637 obj.forEach(callback);
638 } else if (showdown.helper.isArray(obj)) {
639 for (var i = 0; i < obj.length; i++) {
640 callback(obj[i], i, obj);
641 }
642 } else if (typeof (obj) === 'object') {
643 for (var prop in obj) {
644 if (obj.hasOwnProperty(prop)) {
645 callback(obj[prop], prop, obj);
646 }
647 }
648 } else {
649 throw new Error('obj does not seem to be an array or an iterable object');
650 }
651};
652
653/**
654 * Standardidize extension name
655 * @static
656 * @param {string} s extension name
657 * @returns {string}
658 */
659showdown.helper.stdExtName = function (s) {
660 'use strict';
661 return s.replace(/[_?*+\/\\.^-]/g, '').replace(/\s/g, '').toLowerCase();
662};
663
664function escapeCharactersCallback (wholeMatch, m1) {
665 'use strict';
666 var charCodeToEscape = m1.charCodeAt(0);
667 return '¨E' + charCodeToEscape + 'E';
668}
669
670/**
671 * Callback used to escape characters when passing through String.replace
672 * @static
673 * @param {string} wholeMatch
674 * @param {string} m1
675 * @returns {string}
676 */
677showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
678
679/**
680 * Escape characters in a string
681 * @static
682 * @param {string} text
683 * @param {string} charsToEscape
684 * @param {boolean} afterBackslash
685 * @returns {XML|string|void|*}
686 */
687showdown.helper.escapeCharacters = function (text, charsToEscape, afterBackslash) {
688 'use strict';
689 // First we have to escape the escape characters so that
690 // we can build a character class out of them
691 var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';
692
693 if (afterBackslash) {
694 regexString = '\\\\' + regexString;
695 }
696
697 var regex = new RegExp(regexString, 'g');
698 text = text.replace(regex, escapeCharactersCallback);
699
700 return text;
701};
702
703var rgxFindMatchPos = function (str, left, right, flags) {
704 'use strict';
705 var f = flags || '',
706 g = f.indexOf('g') > -1,
707 x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
708 l = new RegExp(left, f.replace(/g/g, '')),
709 pos = [],
710 t, s, m, start, end;
711
712 do {
713 t = 0;
714 while ((m = x.exec(str))) {
715 if (l.test(m[0])) {
716 if (!(t++)) {
717 s = x.lastIndex;
718 start = s - m[0].length;
719 }
720 } else if (t) {
721 if (!--t) {
722 end = m.index + m[0].length;
723 var obj = {
724 left: {start: start, end: s},
725 match: {start: s, end: m.index},
726 right: {start: m.index, end: end},
727 wholeMatch: {start: start, end: end}
728 };
729 pos.push(obj);
730 if (!g) {
731 return pos;
732 }
733 }
734 }
735 }
736 } while (t && (x.lastIndex = s));
737
738 return pos;
739};
740
741/**
742 * matchRecursiveRegExp
743 *
744 * (c) 2007 Steven Levithan <stevenlevithan.com>
745 * MIT License
746 *
747 * Accepts a string to search, a left and right format delimiter
748 * as regex patterns, and optional regex flags. Returns an array
749 * of matches, allowing nested instances of left/right delimiters.
750 * Use the "g" flag to return all matches, otherwise only the
751 * first is returned. Be careful to ensure that the left and
752 * right format delimiters produce mutually exclusive matches.
753 * Backreferences are not supported within the right delimiter
754 * due to how it is internally combined with the left delimiter.
755 * When matching strings whose format delimiters are unbalanced
756 * to the left or right, the output is intentionally as a
757 * conventional regex library with recursion support would
758 * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
759 * "<" and ">" as the delimiters (both strings contain a single,
760 * balanced instance of "<x>").
761 *
762 * examples:
763 * matchRecursiveRegExp("test", "\\(", "\\)")
764 * returns: []
765 * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
766 * returns: ["t<<e>><s>", ""]
767 * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
768 * returns: ["test"]
769 */
770showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
771 'use strict';
772
773 var matchPos = rgxFindMatchPos (str, left, right, flags),
774 results = [];
775
776 for (var i = 0; i < matchPos.length; ++i) {
777 results.push([
778 str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
779 str.slice(matchPos[i].match.start, matchPos[i].match.end),
780 str.slice(matchPos[i].left.start, matchPos[i].left.end),
781 str.slice(matchPos[i].right.start, matchPos[i].right.end)
782 ]);
783 }
784 return results;
785};
786
787/**
788 *
789 * @param {string} str
790 * @param {string|function} replacement
791 * @param {string} left
792 * @param {string} right
793 * @param {string} flags
794 * @returns {string}
795 */
796showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
797 'use strict';
798
799 if (!showdown.helper.isFunction(replacement)) {
800 var repStr = replacement;
801 replacement = function () {
802 return repStr;
803 };
804 }
805
806 var matchPos = rgxFindMatchPos(str, left, right, flags),
807 finalStr = str,
808 lng = matchPos.length;
809
810 if (lng > 0) {
811 var bits = [];
812 if (matchPos[0].wholeMatch.start !== 0) {
813 bits.push(str.slice(0, matchPos[0].wholeMatch.start));
814 }
815 for (var i = 0; i < lng; ++i) {
816 bits.push(
817 replacement(
818 str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
819 str.slice(matchPos[i].match.start, matchPos[i].match.end),
820 str.slice(matchPos[i].left.start, matchPos[i].left.end),
821 str.slice(matchPos[i].right.start, matchPos[i].right.end)
822 )
823 );
824 if (i < lng - 1) {
825 bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
826 }
827 }
828 if (matchPos[lng - 1].wholeMatch.end < str.length) {
829 bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
830 }
831 finalStr = bits.join('');
832 }
833 return finalStr;
834};
835
836/**
837 * Returns the index within the passed String object of the first occurrence of the specified regex,
838 * starting the search at fromIndex. Returns -1 if the value is not found.
839 *
840 * @param {string} str string to search
841 * @param {RegExp} regex Regular expression to search
842 * @param {int} [fromIndex = 0] Index to start the search
843 * @returns {Number}
844 * @throws InvalidArgumentError
845 */
846showdown.helper.regexIndexOf = function (str, regex, fromIndex) {
847 'use strict';
848 if (!showdown.helper.isString(str)) {
849 throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';
850 }
851 if (regex instanceof RegExp === false) {
852 throw 'InvalidArgumentError: second parameter of showdown.helper.regexIndexOf function must be an instance of RegExp';
853 }
854 var indexOf = str.substring(fromIndex || 0).search(regex);
855 return (indexOf >= 0) ? (indexOf + (fromIndex || 0)) : indexOf;
856};
857
858/**
859 * Splits the passed string object at the defined index, and returns an array composed of the two substrings
860 * @param {string} str string to split
861 * @param {int} index index to split string at
862 * @returns {[string,string]}
863 * @throws InvalidArgumentError
864 */
865showdown.helper.splitAtIndex = function (str, index) {
866 'use strict';
867 if (!showdown.helper.isString(str)) {
868 throw 'InvalidArgumentError: first parameter of showdown.helper.regexIndexOf function must be a string';
869 }
870 return [str.substring(0, index), str.substring(index)];
871};
872
873/**
874 * Obfuscate an e-mail address through the use of Character Entities,
875 * transforming ASCII characters into their equivalent decimal or hex entities.
876 *
877 * Since it has a random component, subsequent calls to this function produce different results
878 *
879 * @param {string} mail
880 * @returns {string}
881 */
882showdown.helper.encodeEmailAddress = function (mail) {
883 'use strict';
884 var encode = [
885 function (ch) {
886 return '&#' + ch.charCodeAt(0) + ';';
887 },
888 function (ch) {
889 return '&#x' + ch.charCodeAt(0).toString(16) + ';';
890 },
891 function (ch) {
892 return ch;
893 }
894 ];
895
896 mail = mail.replace(/./g, function (ch) {
897 if (ch === '@') {
898 // this *must* be encoded. I insist.
899 ch = encode[Math.floor(Math.random() * 2)](ch);
900 } else {
901 var r = Math.random();
902 // roughly 10% raw, 45% hex, 45% dec
903 ch = (
904 r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
905 );
906 }
907 return ch;
908 });
909
910 return mail;
911};
912
913/**
914 * POLYFILLS
915 */
916// use this instead of builtin is undefined for IE8 compatibility
917if (typeof(console) === 'undefined') {
918 console = {
919 warn: function (msg) {
920 'use strict';
921 alert(msg);
922 },
923 log: function (msg) {
924 'use strict';
925 alert(msg);
926 },
927 error: function (msg) {
928 'use strict';
929 throw msg;
930 }
931 };
932}
933
934/**
935 * Common regexes.
936 * We declare some common regexes to improve performance
937 */
938showdown.helper.regexes = {
939 asteriskDashAndColon: /([*_:~])/g
940};
941
942/**
943 * EMOJIS LIST
944 */
945showdown.helper.emojis = {
946 '+1':'\ud83d\udc4d',
947 '-1':'\ud83d\udc4e',
948 '100':'\ud83d\udcaf',
949 '1234':'\ud83d\udd22',
950 '1st_place_medal':'\ud83e\udd47',
951 '2nd_place_medal':'\ud83e\udd48',
952 '3rd_place_medal':'\ud83e\udd49',
953 '8ball':'\ud83c\udfb1',
954 'a':'\ud83c\udd70\ufe0f',
955 'ab':'\ud83c\udd8e',
956 'abc':'\ud83d\udd24',
957 'abcd':'\ud83d\udd21',
958 'accept':'\ud83c\ude51',
959 'aerial_tramway':'\ud83d\udea1',
960 'airplane':'\u2708\ufe0f',
961 'alarm_clock':'\u23f0',
962 'alembic':'\u2697\ufe0f',
963 'alien':'\ud83d\udc7d',
964 'ambulance':'\ud83d\ude91',
965 'amphora':'\ud83c\udffa',
966 'anchor':'\u2693\ufe0f',
967 'angel':'\ud83d\udc7c',
968 'anger':'\ud83d\udca2',
969 'angry':'\ud83d\ude20',
970 'anguished':'\ud83d\ude27',
971 'ant':'\ud83d\udc1c',
972 'apple':'\ud83c\udf4e',
973 'aquarius':'\u2652\ufe0f',
974 'aries':'\u2648\ufe0f',
975 'arrow_backward':'\u25c0\ufe0f',
976 'arrow_double_down':'\u23ec',
977 'arrow_double_up':'\u23eb',
978 'arrow_down':'\u2b07\ufe0f',
979 'arrow_down_small':'\ud83d\udd3d',
980 'arrow_forward':'\u25b6\ufe0f',
981 'arrow_heading_down':'\u2935\ufe0f',
982 'arrow_heading_up':'\u2934\ufe0f',
983 'arrow_left':'\u2b05\ufe0f',
984 'arrow_lower_left':'\u2199\ufe0f',
985 'arrow_lower_right':'\u2198\ufe0f',
986 'arrow_right':'\u27a1\ufe0f',
987 'arrow_right_hook':'\u21aa\ufe0f',
988 'arrow_up':'\u2b06\ufe0f',
989 'arrow_up_down':'\u2195\ufe0f',
990 'arrow_up_small':'\ud83d\udd3c',
991 'arrow_upper_left':'\u2196\ufe0f',
992 'arrow_upper_right':'\u2197\ufe0f',
993 'arrows_clockwise':'\ud83d\udd03',
994 'arrows_counterclockwise':'\ud83d\udd04',
995 'art':'\ud83c\udfa8',
996 'articulated_lorry':'\ud83d\ude9b',
997 'artificial_satellite':'\ud83d\udef0',
998 'astonished':'\ud83d\ude32',
999 'athletic_shoe':'\ud83d\udc5f',
1000 'atm':'\ud83c\udfe7',
1001 'atom_symbol':'\u269b\ufe0f',
1002 'avocado':'\ud83e\udd51',
1003 'b':'\ud83c\udd71\ufe0f',
1004 'baby':'\ud83d\udc76',
1005 'baby_bottle':'\ud83c\udf7c',
1006 'baby_chick':'\ud83d\udc24',
1007 'baby_symbol':'\ud83d\udebc',
1008 'back':'\ud83d\udd19',
1009 'bacon':'\ud83e\udd53',
1010 'badminton':'\ud83c\udff8',
1011 'baggage_claim':'\ud83d\udec4',
1012 'baguette_bread':'\ud83e\udd56',
1013 'balance_scale':'\u2696\ufe0f',
1014 'balloon':'\ud83c\udf88',
1015 'ballot_box':'\ud83d\uddf3',
1016 'ballot_box_with_check':'\u2611\ufe0f',
1017 'bamboo':'\ud83c\udf8d',
1018 'banana':'\ud83c\udf4c',
1019 'bangbang':'\u203c\ufe0f',
1020 'bank':'\ud83c\udfe6',
1021 'bar_chart':'\ud83d\udcca',
1022 'barber':'\ud83d\udc88',
1023 'baseball':'\u26be\ufe0f',
1024 'basketball':'\ud83c\udfc0',
1025 'basketball_man':'\u26f9\ufe0f',
1026 'basketball_woman':'\u26f9\ufe0f&zwj;\u2640\ufe0f',
1027 'bat':'\ud83e\udd87',
1028 'bath':'\ud83d\udec0',
1029 'bathtub':'\ud83d\udec1',
1030 'battery':'\ud83d\udd0b',
1031 'beach_umbrella':'\ud83c\udfd6',
1032 'bear':'\ud83d\udc3b',
1033 'bed':'\ud83d\udecf',
1034 'bee':'\ud83d\udc1d',
1035 'beer':'\ud83c\udf7a',
1036 'beers':'\ud83c\udf7b',
1037 'beetle':'\ud83d\udc1e',
1038 'beginner':'\ud83d\udd30',
1039 'bell':'\ud83d\udd14',
1040 'bellhop_bell':'\ud83d\udece',
1041 'bento':'\ud83c\udf71',
1042 'biking_man':'\ud83d\udeb4',
1043 'bike':'\ud83d\udeb2',
1044 'biking_woman':'\ud83d\udeb4&zwj;\u2640\ufe0f',
1045 'bikini':'\ud83d\udc59',
1046 'biohazard':'\u2623\ufe0f',
1047 'bird':'\ud83d\udc26',
1048 'birthday':'\ud83c\udf82',
1049 'black_circle':'\u26ab\ufe0f',
1050 'black_flag':'\ud83c\udff4',
1051 'black_heart':'\ud83d\udda4',
1052 'black_joker':'\ud83c\udccf',
1053 'black_large_square':'\u2b1b\ufe0f',
1054 'black_medium_small_square':'\u25fe\ufe0f',
1055 'black_medium_square':'\u25fc\ufe0f',
1056 'black_nib':'\u2712\ufe0f',
1057 'black_small_square':'\u25aa\ufe0f',
1058 'black_square_button':'\ud83d\udd32',
1059 'blonde_man':'\ud83d\udc71',
1060 'blonde_woman':'\ud83d\udc71&zwj;\u2640\ufe0f',
1061 'blossom':'\ud83c\udf3c',
1062 'blowfish':'\ud83d\udc21',
1063 'blue_book':'\ud83d\udcd8',
1064 'blue_car':'\ud83d\ude99',
1065 'blue_heart':'\ud83d\udc99',
1066 'blush':'\ud83d\ude0a',
1067 'boar':'\ud83d\udc17',
1068 'boat':'\u26f5\ufe0f',
1069 'bomb':'\ud83d\udca3',
1070 'book':'\ud83d\udcd6',
1071 'bookmark':'\ud83d\udd16',
1072 'bookmark_tabs':'\ud83d\udcd1',
1073 'books':'\ud83d\udcda',
1074 'boom':'\ud83d\udca5',
1075 'boot':'\ud83d\udc62',
1076 'bouquet':'\ud83d\udc90',
1077 'bowing_man':'\ud83d\ude47',
1078 'bow_and_arrow':'\ud83c\udff9',
1079 'bowing_woman':'\ud83d\ude47&zwj;\u2640\ufe0f',
1080 'bowling':'\ud83c\udfb3',
1081 'boxing_glove':'\ud83e\udd4a',
1082 'boy':'\ud83d\udc66',
1083 'bread':'\ud83c\udf5e',
1084 'bride_with_veil':'\ud83d\udc70',
1085 'bridge_at_night':'\ud83c\udf09',
1086 'briefcase':'\ud83d\udcbc',
1087 'broken_heart':'\ud83d\udc94',
1088 'bug':'\ud83d\udc1b',
1089 'building_construction':'\ud83c\udfd7',
1090 'bulb':'\ud83d\udca1',
1091 'bullettrain_front':'\ud83d\ude85',
1092 'bullettrain_side':'\ud83d\ude84',
1093 'burrito':'\ud83c\udf2f',
1094 'bus':'\ud83d\ude8c',
1095 'business_suit_levitating':'\ud83d\udd74',
1096 'busstop':'\ud83d\ude8f',
1097 'bust_in_silhouette':'\ud83d\udc64',
1098 'busts_in_silhouette':'\ud83d\udc65',
1099 'butterfly':'\ud83e\udd8b',
1100 'cactus':'\ud83c\udf35',
1101 'cake':'\ud83c\udf70',
1102 'calendar':'\ud83d\udcc6',
1103 'call_me_hand':'\ud83e\udd19',
1104 'calling':'\ud83d\udcf2',
1105 'camel':'\ud83d\udc2b',
1106 'camera':'\ud83d\udcf7',
1107 'camera_flash':'\ud83d\udcf8',
1108 'camping':'\ud83c\udfd5',
1109 'cancer':'\u264b\ufe0f',
1110 'candle':'\ud83d\udd6f',
1111 'candy':'\ud83c\udf6c',
1112 'canoe':'\ud83d\udef6',
1113 'capital_abcd':'\ud83d\udd20',
1114 'capricorn':'\u2651\ufe0f',
1115 'car':'\ud83d\ude97',
1116 'card_file_box':'\ud83d\uddc3',
1117 'card_index':'\ud83d\udcc7',
1118 'card_index_dividers':'\ud83d\uddc2',
1119 'carousel_horse':'\ud83c\udfa0',
1120 'carrot':'\ud83e\udd55',
1121 'cat':'\ud83d\udc31',
1122 'cat2':'\ud83d\udc08',
1123 'cd':'\ud83d\udcbf',
1124 'chains':'\u26d3',
1125 'champagne':'\ud83c\udf7e',
1126 'chart':'\ud83d\udcb9',
1127 'chart_with_downwards_trend':'\ud83d\udcc9',
1128 'chart_with_upwards_trend':'\ud83d\udcc8',
1129 'checkered_flag':'\ud83c\udfc1',
1130 'cheese':'\ud83e\uddc0',
1131 'cherries':'\ud83c\udf52',
1132 'cherry_blossom':'\ud83c\udf38',
1133 'chestnut':'\ud83c\udf30',
1134 'chicken':'\ud83d\udc14',
1135 'children_crossing':'\ud83d\udeb8',
1136 'chipmunk':'\ud83d\udc3f',
1137 'chocolate_bar':'\ud83c\udf6b',
1138 'christmas_tree':'\ud83c\udf84',
1139 'church':'\u26ea\ufe0f',
1140 'cinema':'\ud83c\udfa6',
1141 'circus_tent':'\ud83c\udfaa',
1142 'city_sunrise':'\ud83c\udf07',
1143 'city_sunset':'\ud83c\udf06',
1144 'cityscape':'\ud83c\udfd9',
1145 'cl':'\ud83c\udd91',
1146 'clamp':'\ud83d\udddc',
1147 'clap':'\ud83d\udc4f',
1148 'clapper':'\ud83c\udfac',
1149 'classical_building':'\ud83c\udfdb',
1150 'clinking_glasses':'\ud83e\udd42',
1151 'clipboard':'\ud83d\udccb',
1152 'clock1':'\ud83d\udd50',
1153 'clock10':'\ud83d\udd59',
1154 'clock1030':'\ud83d\udd65',
1155 'clock11':'\ud83d\udd5a',
1156 'clock1130':'\ud83d\udd66',
1157 'clock12':'\ud83d\udd5b',
1158 'clock1230':'\ud83d\udd67',
1159 'clock130':'\ud83d\udd5c',
1160 'clock2':'\ud83d\udd51',
1161 'clock230':'\ud83d\udd5d',
1162 'clock3':'\ud83d\udd52',
1163 'clock330':'\ud83d\udd5e',
1164 'clock4':'\ud83d\udd53',
1165 'clock430':'\ud83d\udd5f',
1166 'clock5':'\ud83d\udd54',
1167 'clock530':'\ud83d\udd60',
1168 'clock6':'\ud83d\udd55',
1169 'clock630':'\ud83d\udd61',
1170 'clock7':'\ud83d\udd56',
1171 'clock730':'\ud83d\udd62',
1172 'clock8':'\ud83d\udd57',
1173 'clock830':'\ud83d\udd63',
1174 'clock9':'\ud83d\udd58',
1175 'clock930':'\ud83d\udd64',
1176 'closed_book':'\ud83d\udcd5',
1177 'closed_lock_with_key':'\ud83d\udd10',
1178 'closed_umbrella':'\ud83c\udf02',
1179 'cloud':'\u2601\ufe0f',
1180 'cloud_with_lightning':'\ud83c\udf29',
1181 'cloud_with_lightning_and_rain':'\u26c8',
1182 'cloud_with_rain':'\ud83c\udf27',
1183 'cloud_with_snow':'\ud83c\udf28',
1184 'clown_face':'\ud83e\udd21',
1185 'clubs':'\u2663\ufe0f',
1186 'cocktail':'\ud83c\udf78',
1187 'coffee':'\u2615\ufe0f',
1188 'coffin':'\u26b0\ufe0f',
1189 'cold_sweat':'\ud83d\ude30',
1190 'comet':'\u2604\ufe0f',
1191 'computer':'\ud83d\udcbb',
1192 'computer_mouse':'\ud83d\uddb1',
1193 'confetti_ball':'\ud83c\udf8a',
1194 'confounded':'\ud83d\ude16',
1195 'confused':'\ud83d\ude15',
1196 'congratulations':'\u3297\ufe0f',
1197 'construction':'\ud83d\udea7',
1198 'construction_worker_man':'\ud83d\udc77',
1199 'construction_worker_woman':'\ud83d\udc77&zwj;\u2640\ufe0f',
1200 'control_knobs':'\ud83c\udf9b',
1201 'convenience_store':'\ud83c\udfea',
1202 'cookie':'\ud83c\udf6a',
1203 'cool':'\ud83c\udd92',
1204 'policeman':'\ud83d\udc6e',
1205 'copyright':'\u00a9\ufe0f',
1206 'corn':'\ud83c\udf3d',
1207 'couch_and_lamp':'\ud83d\udecb',
1208 'couple':'\ud83d\udc6b',
1209 'couple_with_heart_woman_man':'\ud83d\udc91',
1210 'couple_with_heart_man_man':'\ud83d\udc68&zwj;\u2764\ufe0f&zwj;\ud83d\udc68',
1211 'couple_with_heart_woman_woman':'\ud83d\udc69&zwj;\u2764\ufe0f&zwj;\ud83d\udc69',
1212 'couplekiss_man_man':'\ud83d\udc68&zwj;\u2764\ufe0f&zwj;\ud83d\udc8b&zwj;\ud83d\udc68',
1213 'couplekiss_man_woman':'\ud83d\udc8f',
1214 'couplekiss_woman_woman':'\ud83d\udc69&zwj;\u2764\ufe0f&zwj;\ud83d\udc8b&zwj;\ud83d\udc69',
1215 'cow':'\ud83d\udc2e',
1216 'cow2':'\ud83d\udc04',
1217 'cowboy_hat_face':'\ud83e\udd20',
1218 'crab':'\ud83e\udd80',
1219 'crayon':'\ud83d\udd8d',
1220 'credit_card':'\ud83d\udcb3',
1221 'crescent_moon':'\ud83c\udf19',
1222 'cricket':'\ud83c\udfcf',
1223 'crocodile':'\ud83d\udc0a',
1224 'croissant':'\ud83e\udd50',
1225 'crossed_fingers':'\ud83e\udd1e',
1226 'crossed_flags':'\ud83c\udf8c',
1227 'crossed_swords':'\u2694\ufe0f',
1228 'crown':'\ud83d\udc51',
1229 'cry':'\ud83d\ude22',
1230 'crying_cat_face':'\ud83d\ude3f',
1231 'crystal_ball':'\ud83d\udd2e',
1232 'cucumber':'\ud83e\udd52',
1233 'cupid':'\ud83d\udc98',
1234 'curly_loop':'\u27b0',
1235 'currency_exchange':'\ud83d\udcb1',
1236 'curry':'\ud83c\udf5b',
1237 'custard':'\ud83c\udf6e',
1238 'customs':'\ud83d\udec3',
1239 'cyclone':'\ud83c\udf00',
1240 'dagger':'\ud83d\udde1',
1241 'dancer':'\ud83d\udc83',
1242 'dancing_women':'\ud83d\udc6f',
1243 'dancing_men':'\ud83d\udc6f&zwj;\u2642\ufe0f',
1244 'dango':'\ud83c\udf61',
1245 'dark_sunglasses':'\ud83d\udd76',
1246 'dart':'\ud83c\udfaf',
1247 'dash':'\ud83d\udca8',
1248 'date':'\ud83d\udcc5',
1249 'deciduous_tree':'\ud83c\udf33',
1250 'deer':'\ud83e\udd8c',
1251 'department_store':'\ud83c\udfec',
1252 'derelict_house':'\ud83c\udfda',
1253 'desert':'\ud83c\udfdc',
1254 'desert_island':'\ud83c\udfdd',
1255 'desktop_computer':'\ud83d\udda5',
1256 'male_detective':'\ud83d\udd75\ufe0f',
1257 'diamond_shape_with_a_dot_inside':'\ud83d\udca0',
1258 'diamonds':'\u2666\ufe0f',
1259 'disappointed':'\ud83d\ude1e',
1260 'disappointed_relieved':'\ud83d\ude25',
1261 'dizzy':'\ud83d\udcab',
1262 'dizzy_face':'\ud83d\ude35',
1263 'do_not_litter':'\ud83d\udeaf',
1264 'dog':'\ud83d\udc36',
1265 'dog2':'\ud83d\udc15',
1266 'dollar':'\ud83d\udcb5',
1267 'dolls':'\ud83c\udf8e',
1268 'dolphin':'\ud83d\udc2c',
1269 'door':'\ud83d\udeaa',
1270 'doughnut':'\ud83c\udf69',
1271 'dove':'\ud83d\udd4a',
1272 'dragon':'\ud83d\udc09',
1273 'dragon_face':'\ud83d\udc32',
1274 'dress':'\ud83d\udc57',
1275 'dromedary_camel':'\ud83d\udc2a',
1276 'drooling_face':'\ud83e\udd24',
1277 'droplet':'\ud83d\udca7',
1278 'drum':'\ud83e\udd41',
1279 'duck':'\ud83e\udd86',
1280 'dvd':'\ud83d\udcc0',
1281 'e-mail':'\ud83d\udce7',
1282 'eagle':'\ud83e\udd85',
1283 'ear':'\ud83d\udc42',
1284 'ear_of_rice':'\ud83c\udf3e',
1285 'earth_africa':'\ud83c\udf0d',
1286 'earth_americas':'\ud83c\udf0e',
1287 'earth_asia':'\ud83c\udf0f',
1288 'egg':'\ud83e\udd5a',
1289 'eggplant':'\ud83c\udf46',
1290 'eight_pointed_black_star':'\u2734\ufe0f',
1291 'eight_spoked_asterisk':'\u2733\ufe0f',
1292 'electric_plug':'\ud83d\udd0c',
1293 'elephant':'\ud83d\udc18',
1294 'email':'\u2709\ufe0f',
1295 'end':'\ud83d\udd1a',
1296 'envelope_with_arrow':'\ud83d\udce9',
1297 'euro':'\ud83d\udcb6',
1298 'european_castle':'\ud83c\udff0',
1299 'european_post_office':'\ud83c\udfe4',
1300 'evergreen_tree':'\ud83c\udf32',
1301 'exclamation':'\u2757\ufe0f',
1302 'expressionless':'\ud83d\ude11',
1303 'eye':'\ud83d\udc41',
1304 'eye_speech_bubble':'\ud83d\udc41&zwj;\ud83d\udde8',
1305 'eyeglasses':'\ud83d\udc53',
1306 'eyes':'\ud83d\udc40',
1307 'face_with_head_bandage':'\ud83e\udd15',
1308 'face_with_thermometer':'\ud83e\udd12',
1309 'fist_oncoming':'\ud83d\udc4a',
1310 'factory':'\ud83c\udfed',
1311 'fallen_leaf':'\ud83c\udf42',
1312 'family_man_woman_boy':'\ud83d\udc6a',
1313 'family_man_boy':'\ud83d\udc68&zwj;\ud83d\udc66',
1314 'family_man_boy_boy':'\ud83d\udc68&zwj;\ud83d\udc66&zwj;\ud83d\udc66',
1315 'family_man_girl':'\ud83d\udc68&zwj;\ud83d\udc67',
1316 'family_man_girl_boy':'\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc66',
1317 'family_man_girl_girl':'\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc67',
1318 'family_man_man_boy':'\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc66',
1319 'family_man_man_boy_boy':'\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc66&zwj;\ud83d\udc66',
1320 'family_man_man_girl':'\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67',
1321 'family_man_man_girl_boy':'\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc66',
1322 'family_man_man_girl_girl':'\ud83d\udc68&zwj;\ud83d\udc68&zwj;\ud83d\udc67&zwj;\ud83d\udc67',
1323 'family_man_woman_boy_boy':'\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66',
1324 'family_man_woman_girl':'\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67',
1325 'family_man_woman_girl_boy':'\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66',
1326 'family_man_woman_girl_girl':'\ud83d\udc68&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67',
1327 'family_woman_boy':'\ud83d\udc69&zwj;\ud83d\udc66',
1328 'family_woman_boy_boy':'\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66',
1329 'family_woman_girl':'\ud83d\udc69&zwj;\ud83d\udc67',
1330 'family_woman_girl_boy':'\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66',
1331 'family_woman_girl_girl':'\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67',
1332 'family_woman_woman_boy':'\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc66',
1333 'family_woman_woman_boy_boy':'\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc66&zwj;\ud83d\udc66',
1334 'family_woman_woman_girl':'\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67',
1335 'family_woman_woman_girl_boy':'\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc66',
1336 'family_woman_woman_girl_girl':'\ud83d\udc69&zwj;\ud83d\udc69&zwj;\ud83d\udc67&zwj;\ud83d\udc67',
1337 'fast_forward':'\u23e9',
1338 'fax':'\ud83d\udce0',
1339 'fearful':'\ud83d\ude28',
1340 'feet':'\ud83d\udc3e',
1341 'female_detective':'\ud83d\udd75\ufe0f&zwj;\u2640\ufe0f',
1342 'ferris_wheel':'\ud83c\udfa1',
1343 'ferry':'\u26f4',
1344 'field_hockey':'\ud83c\udfd1',
1345 'file_cabinet':'\ud83d\uddc4',
1346 'file_folder':'\ud83d\udcc1',
1347 'film_projector':'\ud83d\udcfd',
1348 'film_strip':'\ud83c\udf9e',
1349 'fire':'\ud83d\udd25',
1350 'fire_engine':'\ud83d\ude92',
1351 'fireworks':'\ud83c\udf86',
1352 'first_quarter_moon':'\ud83c\udf13',
1353 'first_quarter_moon_with_face':'\ud83c\udf1b',
1354 'fish':'\ud83d\udc1f',
1355 'fish_cake':'\ud83c\udf65',
1356 'fishing_pole_and_fish':'\ud83c\udfa3',
1357 'fist_raised':'\u270a',
1358 'fist_left':'\ud83e\udd1b',
1359 'fist_right':'\ud83e\udd1c',
1360 'flags':'\ud83c\udf8f',
1361 'flashlight':'\ud83d\udd26',
1362 'fleur_de_lis':'\u269c\ufe0f',
1363 'flight_arrival':'\ud83d\udeec',
1364 'flight_departure':'\ud83d\udeeb',
1365 'floppy_disk':'\ud83d\udcbe',
1366 'flower_playing_cards':'\ud83c\udfb4',
1367 'flushed':'\ud83d\ude33',
1368 'fog':'\ud83c\udf2b',
1369 'foggy':'\ud83c\udf01',
1370 'football':'\ud83c\udfc8',
1371 'footprints':'\ud83d\udc63',
1372 'fork_and_knife':'\ud83c\udf74',
1373 'fountain':'\u26f2\ufe0f',
1374 'fountain_pen':'\ud83d\udd8b',
1375 'four_leaf_clover':'\ud83c\udf40',
1376 'fox_face':'\ud83e\udd8a',
1377 'framed_picture':'\ud83d\uddbc',
1378 'free':'\ud83c\udd93',
1379 'fried_egg':'\ud83c\udf73',
1380 'fried_shrimp':'\ud83c\udf64',
1381 'fries':'\ud83c\udf5f',
1382 'frog':'\ud83d\udc38',
1383 'frowning':'\ud83d\ude26',
1384 'frowning_face':'\u2639\ufe0f',
1385 'frowning_man':'\ud83d\ude4d&zwj;\u2642\ufe0f',
1386 'frowning_woman':'\ud83d\ude4d',
1387 'middle_finger':'\ud83d\udd95',
1388 'fuelpump':'\u26fd\ufe0f',
1389 'full_moon':'\ud83c\udf15',
1390 'full_moon_with_face':'\ud83c\udf1d',
1391 'funeral_urn':'\u26b1\ufe0f',
1392 'game_die':'\ud83c\udfb2',
1393 'gear':'\u2699\ufe0f',
1394 'gem':'\ud83d\udc8e',
1395 'gemini':'\u264a\ufe0f',
1396 'ghost':'\ud83d\udc7b',
1397 'gift':'\ud83c\udf81',
1398 'gift_heart':'\ud83d\udc9d',
1399 'girl':'\ud83d\udc67',
1400 'globe_with_meridians':'\ud83c\udf10',
1401 'goal_net':'\ud83e\udd45',
1402 'goat':'\ud83d\udc10',
1403 'golf':'\u26f3\ufe0f',
1404 'golfing_man':'\ud83c\udfcc\ufe0f',
1405 'golfing_woman':'\ud83c\udfcc\ufe0f&zwj;\u2640\ufe0f',
1406 'gorilla':'\ud83e\udd8d',
1407 'grapes':'\ud83c\udf47',
1408 'green_apple':'\ud83c\udf4f',
1409 'green_book':'\ud83d\udcd7',
1410 'green_heart':'\ud83d\udc9a',
1411 'green_salad':'\ud83e\udd57',
1412 'grey_exclamation':'\u2755',
1413 'grey_question':'\u2754',
1414 'grimacing':'\ud83d\ude2c',
1415 'grin':'\ud83d\ude01',
1416 'grinning':'\ud83d\ude00',
1417 'guardsman':'\ud83d\udc82',
1418 'guardswoman':'\ud83d\udc82&zwj;\u2640\ufe0f',
1419 'guitar':'\ud83c\udfb8',
1420 'gun':'\ud83d\udd2b',
1421 'haircut_woman':'\ud83d\udc87',
1422 'haircut_man':'\ud83d\udc87&zwj;\u2642\ufe0f',
1423 'hamburger':'\ud83c\udf54',
1424 'hammer':'\ud83d\udd28',
1425 'hammer_and_pick':'\u2692',
1426 'hammer_and_wrench':'\ud83d\udee0',
1427 'hamster':'\ud83d\udc39',
1428 'hand':'\u270b',
1429 'handbag':'\ud83d\udc5c',
1430 'handshake':'\ud83e\udd1d',
1431 'hankey':'\ud83d\udca9',
1432 'hatched_chick':'\ud83d\udc25',
1433 'hatching_chick':'\ud83d\udc23',
1434 'headphones':'\ud83c\udfa7',
1435 'hear_no_evil':'\ud83d\ude49',
1436 'heart':'\u2764\ufe0f',
1437 'heart_decoration':'\ud83d\udc9f',
1438 'heart_eyes':'\ud83d\ude0d',
1439 'heart_eyes_cat':'\ud83d\ude3b',
1440 'heartbeat':'\ud83d\udc93',
1441 'heartpulse':'\ud83d\udc97',
1442 'hearts':'\u2665\ufe0f',
1443 'heavy_check_mark':'\u2714\ufe0f',
1444 'heavy_division_sign':'\u2797',
1445 'heavy_dollar_sign':'\ud83d\udcb2',
1446 'heavy_heart_exclamation':'\u2763\ufe0f',
1447 'heavy_minus_sign':'\u2796',
1448 'heavy_multiplication_x':'\u2716\ufe0f',
1449 'heavy_plus_sign':'\u2795',
1450 'helicopter':'\ud83d\ude81',
1451 'herb':'\ud83c\udf3f',
1452 'hibiscus':'\ud83c\udf3a',
1453 'high_brightness':'\ud83d\udd06',
1454 'high_heel':'\ud83d\udc60',
1455 'hocho':'\ud83d\udd2a',
1456 'hole':'\ud83d\udd73',
1457 'honey_pot':'\ud83c\udf6f',
1458 'horse':'\ud83d\udc34',
1459 'horse_racing':'\ud83c\udfc7',
1460 'hospital':'\ud83c\udfe5',
1461 'hot_pepper':'\ud83c\udf36',
1462 'hotdog':'\ud83c\udf2d',
1463 'hotel':'\ud83c\udfe8',
1464 'hotsprings':'\u2668\ufe0f',
1465 'hourglass':'\u231b\ufe0f',
1466 'hourglass_flowing_sand':'\u23f3',
1467 'house':'\ud83c\udfe0',
1468 'house_with_garden':'\ud83c\udfe1',
1469 'houses':'\ud83c\udfd8',
1470 'hugs':'\ud83e\udd17',
1471 'hushed':'\ud83d\ude2f',
1472 'ice_cream':'\ud83c\udf68',
1473 'ice_hockey':'\ud83c\udfd2',
1474 'ice_skate':'\u26f8',
1475 'icecream':'\ud83c\udf66',
1476 'id':'\ud83c\udd94',
1477 'ideograph_advantage':'\ud83c\ude50',
1478 'imp':'\ud83d\udc7f',
1479 'inbox_tray':'\ud83d\udce5',
1480 'incoming_envelope':'\ud83d\udce8',
1481 'tipping_hand_woman':'\ud83d\udc81',
1482 'information_source':'\u2139\ufe0f',
1483 'innocent':'\ud83d\ude07',
1484 'interrobang':'\u2049\ufe0f',
1485 'iphone':'\ud83d\udcf1',
1486 'izakaya_lantern':'\ud83c\udfee',
1487 'jack_o_lantern':'\ud83c\udf83',
1488 'japan':'\ud83d\uddfe',
1489 'japanese_castle':'\ud83c\udfef',
1490 'japanese_goblin':'\ud83d\udc7a',
1491 'japanese_ogre':'\ud83d\udc79',
1492 'jeans':'\ud83d\udc56',
1493 'joy':'\ud83d\ude02',
1494 'joy_cat':'\ud83d\ude39',
1495 'joystick':'\ud83d\udd79',
1496 'kaaba':'\ud83d\udd4b',
1497 'key':'\ud83d\udd11',
1498 'keyboard':'\u2328\ufe0f',
1499 'keycap_ten':'\ud83d\udd1f',
1500 'kick_scooter':'\ud83d\udef4',
1501 'kimono':'\ud83d\udc58',
1502 'kiss':'\ud83d\udc8b',
1503 'kissing':'\ud83d\ude17',
1504 'kissing_cat':'\ud83d\ude3d',
1505 'kissing_closed_eyes':'\ud83d\ude1a',
1506 'kissing_heart':'\ud83d\ude18',
1507 'kissing_smiling_eyes':'\ud83d\ude19',
1508 'kiwi_fruit':'\ud83e\udd5d',
1509 'koala':'\ud83d\udc28',
1510 'koko':'\ud83c\ude01',
1511 'label':'\ud83c\udff7',
1512 'large_blue_circle':'\ud83d\udd35',
1513 'large_blue_diamond':'\ud83d\udd37',
1514 'large_orange_diamond':'\ud83d\udd36',
1515 'last_quarter_moon':'\ud83c\udf17',
1516 'last_quarter_moon_with_face':'\ud83c\udf1c',
1517 'latin_cross':'\u271d\ufe0f',
1518 'laughing':'\ud83d\ude06',
1519 'leaves':'\ud83c\udf43',
1520 'ledger':'\ud83d\udcd2',
1521 'left_luggage':'\ud83d\udec5',
1522 'left_right_arrow':'\u2194\ufe0f',
1523 'leftwards_arrow_with_hook':'\u21a9\ufe0f',
1524 'lemon':'\ud83c\udf4b',
1525 'leo':'\u264c\ufe0f',
1526 'leopard':'\ud83d\udc06',
1527 'level_slider':'\ud83c\udf9a',
1528 'libra':'\u264e\ufe0f',
1529 'light_rail':'\ud83d\ude88',
1530 'link':'\ud83d\udd17',
1531 'lion':'\ud83e\udd81',
1532 'lips':'\ud83d\udc44',
1533 'lipstick':'\ud83d\udc84',
1534 'lizard':'\ud83e\udd8e',
1535 'lock':'\ud83d\udd12',
1536 'lock_with_ink_pen':'\ud83d\udd0f',
1537 'lollipop':'\ud83c\udf6d',
1538 'loop':'\u27bf',
1539 'loud_sound':'\ud83d\udd0a',
1540 'loudspeaker':'\ud83d\udce2',
1541 'love_hotel':'\ud83c\udfe9',
1542 'love_letter':'\ud83d\udc8c',
1543 'low_brightness':'\ud83d\udd05',
1544 'lying_face':'\ud83e\udd25',
1545 'm':'\u24c2\ufe0f',
1546 'mag':'\ud83d\udd0d',
1547 'mag_right':'\ud83d\udd0e',
1548 'mahjong':'\ud83c\udc04\ufe0f',
1549 'mailbox':'\ud83d\udceb',
1550 'mailbox_closed':'\ud83d\udcea',
1551 'mailbox_with_mail':'\ud83d\udcec',
1552 'mailbox_with_no_mail':'\ud83d\udced',
1553 'man':'\ud83d\udc68',
1554 'man_artist':'\ud83d\udc68&zwj;\ud83c\udfa8',
1555 'man_astronaut':'\ud83d\udc68&zwj;\ud83d\ude80',
1556 'man_cartwheeling':'\ud83e\udd38&zwj;\u2642\ufe0f',
1557 'man_cook':'\ud83d\udc68&zwj;\ud83c\udf73',
1558 'man_dancing':'\ud83d\udd7a',
1559 'man_facepalming':'\ud83e\udd26&zwj;\u2642\ufe0f',
1560 'man_factory_worker':'\ud83d\udc68&zwj;\ud83c\udfed',
1561 'man_farmer':'\ud83d\udc68&zwj;\ud83c\udf3e',
1562 'man_firefighter':'\ud83d\udc68&zwj;\ud83d\ude92',
1563 'man_health_worker':'\ud83d\udc68&zwj;\u2695\ufe0f',
1564 'man_in_tuxedo':'\ud83e\udd35',
1565 'man_judge':'\ud83d\udc68&zwj;\u2696\ufe0f',
1566 'man_juggling':'\ud83e\udd39&zwj;\u2642\ufe0f',
1567 'man_mechanic':'\ud83d\udc68&zwj;\ud83d\udd27',
1568 'man_office_worker':'\ud83d\udc68&zwj;\ud83d\udcbc',
1569 'man_pilot':'\ud83d\udc68&zwj;\u2708\ufe0f',
1570 'man_playing_handball':'\ud83e\udd3e&zwj;\u2642\ufe0f',
1571 'man_playing_water_polo':'\ud83e\udd3d&zwj;\u2642\ufe0f',
1572 'man_scientist':'\ud83d\udc68&zwj;\ud83d\udd2c',
1573 'man_shrugging':'\ud83e\udd37&zwj;\u2642\ufe0f',
1574 'man_singer':'\ud83d\udc68&zwj;\ud83c\udfa4',
1575 'man_student':'\ud83d\udc68&zwj;\ud83c\udf93',
1576 'man_teacher':'\ud83d\udc68&zwj;\ud83c\udfeb',
1577 'man_technologist':'\ud83d\udc68&zwj;\ud83d\udcbb',
1578 'man_with_gua_pi_mao':'\ud83d\udc72',
1579 'man_with_turban':'\ud83d\udc73',
1580 'tangerine':'\ud83c\udf4a',
1581 'mans_shoe':'\ud83d\udc5e',
1582 'mantelpiece_clock':'\ud83d\udd70',
1583 'maple_leaf':'\ud83c\udf41',
1584 'martial_arts_uniform':'\ud83e\udd4b',
1585 'mask':'\ud83d\ude37',
1586 'massage_woman':'\ud83d\udc86',
1587 'massage_man':'\ud83d\udc86&zwj;\u2642\ufe0f',
1588 'meat_on_bone':'\ud83c\udf56',
1589 'medal_military':'\ud83c\udf96',
1590 'medal_sports':'\ud83c\udfc5',
1591 'mega':'\ud83d\udce3',
1592 'melon':'\ud83c\udf48',
1593 'memo':'\ud83d\udcdd',
1594 'men_wrestling':'\ud83e\udd3c&zwj;\u2642\ufe0f',
1595 'menorah':'\ud83d\udd4e',
1596 'mens':'\ud83d\udeb9',
1597 'metal':'\ud83e\udd18',
1598 'metro':'\ud83d\ude87',
1599 'microphone':'\ud83c\udfa4',
1600 'microscope':'\ud83d\udd2c',
1601 'milk_glass':'\ud83e\udd5b',
1602 'milky_way':'\ud83c\udf0c',
1603 'minibus':'\ud83d\ude90',
1604 'minidisc':'\ud83d\udcbd',
1605 'mobile_phone_off':'\ud83d\udcf4',
1606 'money_mouth_face':'\ud83e\udd11',
1607 'money_with_wings':'\ud83d\udcb8',
1608 'moneybag':'\ud83d\udcb0',
1609 'monkey':'\ud83d\udc12',
1610 'monkey_face':'\ud83d\udc35',
1611 'monorail':'\ud83d\ude9d',
1612 'moon':'\ud83c\udf14',
1613 'mortar_board':'\ud83c\udf93',
1614 'mosque':'\ud83d\udd4c',
1615 'motor_boat':'\ud83d\udee5',
1616 'motor_scooter':'\ud83d\udef5',
1617 'motorcycle':'\ud83c\udfcd',
1618 'motorway':'\ud83d\udee3',
1619 'mount_fuji':'\ud83d\uddfb',
1620 'mountain':'\u26f0',
1621 'mountain_biking_man':'\ud83d\udeb5',
1622 'mountain_biking_woman':'\ud83d\udeb5&zwj;\u2640\ufe0f',
1623 'mountain_cableway':'\ud83d\udea0',
1624 'mountain_railway':'\ud83d\ude9e',
1625 'mountain_snow':'\ud83c\udfd4',
1626 'mouse':'\ud83d\udc2d',
1627 'mouse2':'\ud83d\udc01',
1628 'movie_camera':'\ud83c\udfa5',
1629 'moyai':'\ud83d\uddff',
1630 'mrs_claus':'\ud83e\udd36',
1631 'muscle':'\ud83d\udcaa',
1632 'mushroom':'\ud83c\udf44',
1633 'musical_keyboard':'\ud83c\udfb9',
1634 'musical_note':'\ud83c\udfb5',
1635 'musical_score':'\ud83c\udfbc',
1636 'mute':'\ud83d\udd07',
1637 'nail_care':'\ud83d\udc85',
1638 'name_badge':'\ud83d\udcdb',
1639 'national_park':'\ud83c\udfde',
1640 'nauseated_face':'\ud83e\udd22',
1641 'necktie':'\ud83d\udc54',
1642 'negative_squared_cross_mark':'\u274e',
1643 'nerd_face':'\ud83e\udd13',
1644 'neutral_face':'\ud83d\ude10',
1645 'new':'\ud83c\udd95',
1646 'new_moon':'\ud83c\udf11',
1647 'new_moon_with_face':'\ud83c\udf1a',
1648 'newspaper':'\ud83d\udcf0',
1649 'newspaper_roll':'\ud83d\uddde',
1650 'next_track_button':'\u23ed',
1651 'ng':'\ud83c\udd96',
1652 'no_good_man':'\ud83d\ude45&zwj;\u2642\ufe0f',
1653 'no_good_woman':'\ud83d\ude45',
1654 'night_with_stars':'\ud83c\udf03',
1655 'no_bell':'\ud83d\udd15',
1656 'no_bicycles':'\ud83d\udeb3',
1657 'no_entry':'\u26d4\ufe0f',
1658 'no_entry_sign':'\ud83d\udeab',
1659 'no_mobile_phones':'\ud83d\udcf5',
1660 'no_mouth':'\ud83d\ude36',
1661 'no_pedestrians':'\ud83d\udeb7',
1662 'no_smoking':'\ud83d\udead',
1663 'non-potable_water':'\ud83d\udeb1',
1664 'nose':'\ud83d\udc43',
1665 'notebook':'\ud83d\udcd3',
1666 'notebook_with_decorative_cover':'\ud83d\udcd4',
1667 'notes':'\ud83c\udfb6',
1668 'nut_and_bolt':'\ud83d\udd29',
1669 'o':'\u2b55\ufe0f',
1670 'o2':'\ud83c\udd7e\ufe0f',
1671 'ocean':'\ud83c\udf0a',
1672 'octopus':'\ud83d\udc19',
1673 'oden':'\ud83c\udf62',
1674 'office':'\ud83c\udfe2',
1675 'oil_drum':'\ud83d\udee2',
1676 'ok':'\ud83c\udd97',
1677 'ok_hand':'\ud83d\udc4c',
1678 'ok_man':'\ud83d\ude46&zwj;\u2642\ufe0f',
1679 'ok_woman':'\ud83d\ude46',
1680 'old_key':'\ud83d\udddd',
1681 'older_man':'\ud83d\udc74',
1682 'older_woman':'\ud83d\udc75',
1683 'om':'\ud83d\udd49',
1684 'on':'\ud83d\udd1b',
1685 'oncoming_automobile':'\ud83d\ude98',
1686 'oncoming_bus':'\ud83d\ude8d',
1687 'oncoming_police_car':'\ud83d\ude94',
1688 'oncoming_taxi':'\ud83d\ude96',
1689 'open_file_folder':'\ud83d\udcc2',
1690 'open_hands':'\ud83d\udc50',
1691 'open_mouth':'\ud83d\ude2e',
1692 'open_umbrella':'\u2602\ufe0f',
1693 'ophiuchus':'\u26ce',
1694 'orange_book':'\ud83d\udcd9',
1695 'orthodox_cross':'\u2626\ufe0f',
1696 'outbox_tray':'\ud83d\udce4',
1697 'owl':'\ud83e\udd89',
1698 'ox':'\ud83d\udc02',
1699 'package':'\ud83d\udce6',
1700 'page_facing_up':'\ud83d\udcc4',
1701 'page_with_curl':'\ud83d\udcc3',
1702 'pager':'\ud83d\udcdf',
1703 'paintbrush':'\ud83d\udd8c',
1704 'palm_tree':'\ud83c\udf34',
1705 'pancakes':'\ud83e\udd5e',
1706 'panda_face':'\ud83d\udc3c',
1707 'paperclip':'\ud83d\udcce',
1708 'paperclips':'\ud83d\udd87',
1709 'parasol_on_ground':'\u26f1',
1710 'parking':'\ud83c\udd7f\ufe0f',
1711 'part_alternation_mark':'\u303d\ufe0f',
1712 'partly_sunny':'\u26c5\ufe0f',
1713 'passenger_ship':'\ud83d\udef3',
1714 'passport_control':'\ud83d\udec2',
1715 'pause_button':'\u23f8',
1716 'peace_symbol':'\u262e\ufe0f',
1717 'peach':'\ud83c\udf51',
1718 'peanuts':'\ud83e\udd5c',
1719 'pear':'\ud83c\udf50',
1720 'pen':'\ud83d\udd8a',
1721 'pencil2':'\u270f\ufe0f',
1722 'penguin':'\ud83d\udc27',
1723 'pensive':'\ud83d\ude14',
1724 'performing_arts':'\ud83c\udfad',
1725 'persevere':'\ud83d\ude23',
1726 'person_fencing':'\ud83e\udd3a',
1727 'pouting_woman':'\ud83d\ude4e',
1728 'phone':'\u260e\ufe0f',
1729 'pick':'\u26cf',
1730 'pig':'\ud83d\udc37',
1731 'pig2':'\ud83d\udc16',
1732 'pig_nose':'\ud83d\udc3d',
1733 'pill':'\ud83d\udc8a',
1734 'pineapple':'\ud83c\udf4d',
1735 'ping_pong':'\ud83c\udfd3',
1736 'pisces':'\u2653\ufe0f',
1737 'pizza':'\ud83c\udf55',
1738 'place_of_worship':'\ud83d\uded0',
1739 'plate_with_cutlery':'\ud83c\udf7d',
1740 'play_or_pause_button':'\u23ef',
1741 'point_down':'\ud83d\udc47',
1742 'point_left':'\ud83d\udc48',
1743 'point_right':'\ud83d\udc49',
1744 'point_up':'\u261d\ufe0f',
1745 'point_up_2':'\ud83d\udc46',
1746 'police_car':'\ud83d\ude93',
1747 'policewoman':'\ud83d\udc6e&zwj;\u2640\ufe0f',
1748 'poodle':'\ud83d\udc29',
1749 'popcorn':'\ud83c\udf7f',
1750 'post_office':'\ud83c\udfe3',
1751 'postal_horn':'\ud83d\udcef',
1752 'postbox':'\ud83d\udcee',
1753 'potable_water':'\ud83d\udeb0',
1754 'potato':'\ud83e\udd54',
1755 'pouch':'\ud83d\udc5d',
1756 'poultry_leg':'\ud83c\udf57',
1757 'pound':'\ud83d\udcb7',
1758 'rage':'\ud83d\ude21',
1759 'pouting_cat':'\ud83d\ude3e',
1760 'pouting_man':'\ud83d\ude4e&zwj;\u2642\ufe0f',
1761 'pray':'\ud83d\ude4f',
1762 'prayer_beads':'\ud83d\udcff',
1763 'pregnant_woman':'\ud83e\udd30',
1764 'previous_track_button':'\u23ee',
1765 'prince':'\ud83e\udd34',
1766 'princess':'\ud83d\udc78',
1767 'printer':'\ud83d\udda8',
1768 'purple_heart':'\ud83d\udc9c',
1769 'purse':'\ud83d\udc5b',
1770 'pushpin':'\ud83d\udccc',
1771 'put_litter_in_its_place':'\ud83d\udeae',
1772 'question':'\u2753',
1773 'rabbit':'\ud83d\udc30',
1774 'rabbit2':'\ud83d\udc07',
1775 'racehorse':'\ud83d\udc0e',
1776 'racing_car':'\ud83c\udfce',
1777 'radio':'\ud83d\udcfb',
1778 'radio_button':'\ud83d\udd18',
1779 'radioactive':'\u2622\ufe0f',
1780 'railway_car':'\ud83d\ude83',
1781 'railway_track':'\ud83d\udee4',
1782 'rainbow':'\ud83c\udf08',
1783 'rainbow_flag':'\ud83c\udff3\ufe0f&zwj;\ud83c\udf08',
1784 'raised_back_of_hand':'\ud83e\udd1a',
1785 'raised_hand_with_fingers_splayed':'\ud83d\udd90',
1786 'raised_hands':'\ud83d\ude4c',
1787 'raising_hand_woman':'\ud83d\ude4b',
1788 'raising_hand_man':'\ud83d\ude4b&zwj;\u2642\ufe0f',
1789 'ram':'\ud83d\udc0f',
1790 'ramen':'\ud83c\udf5c',
1791 'rat':'\ud83d\udc00',
1792 'record_button':'\u23fa',
1793 'recycle':'\u267b\ufe0f',
1794 'red_circle':'\ud83d\udd34',
1795 'registered':'\u00ae\ufe0f',
1796 'relaxed':'\u263a\ufe0f',
1797 'relieved':'\ud83d\ude0c',
1798 'reminder_ribbon':'\ud83c\udf97',
1799 'repeat':'\ud83d\udd01',
1800 'repeat_one':'\ud83d\udd02',
1801 'rescue_worker_helmet':'\u26d1',
1802 'restroom':'\ud83d\udebb',
1803 'revolving_hearts':'\ud83d\udc9e',
1804 'rewind':'\u23ea',
1805 'rhinoceros':'\ud83e\udd8f',
1806 'ribbon':'\ud83c\udf80',
1807 'rice':'\ud83c\udf5a',
1808 'rice_ball':'\ud83c\udf59',
1809 'rice_cracker':'\ud83c\udf58',
1810 'rice_scene':'\ud83c\udf91',
1811 'right_anger_bubble':'\ud83d\uddef',
1812 'ring':'\ud83d\udc8d',
1813 'robot':'\ud83e\udd16',
1814 'rocket':'\ud83d\ude80',
1815 'rofl':'\ud83e\udd23',
1816 'roll_eyes':'\ud83d\ude44',
1817 'roller_coaster':'\ud83c\udfa2',
1818 'rooster':'\ud83d\udc13',
1819 'rose':'\ud83c\udf39',
1820 'rosette':'\ud83c\udff5',
1821 'rotating_light':'\ud83d\udea8',
1822 'round_pushpin':'\ud83d\udccd',
1823 'rowing_man':'\ud83d\udea3',
1824 'rowing_woman':'\ud83d\udea3&zwj;\u2640\ufe0f',
1825 'rugby_football':'\ud83c\udfc9',
1826 'running_man':'\ud83c\udfc3',
1827 'running_shirt_with_sash':'\ud83c\udfbd',
1828 'running_woman':'\ud83c\udfc3&zwj;\u2640\ufe0f',
1829 'sa':'\ud83c\ude02\ufe0f',
1830 'sagittarius':'\u2650\ufe0f',
1831 'sake':'\ud83c\udf76',
1832 'sandal':'\ud83d\udc61',
1833 'santa':'\ud83c\udf85',
1834 'satellite':'\ud83d\udce1',
1835 'saxophone':'\ud83c\udfb7',
1836 'school':'\ud83c\udfeb',
1837 'school_satchel':'\ud83c\udf92',
1838 'scissors':'\u2702\ufe0f',
1839 'scorpion':'\ud83e\udd82',
1840 'scorpius':'\u264f\ufe0f',
1841 'scream':'\ud83d\ude31',
1842 'scream_cat':'\ud83d\ude40',
1843 'scroll':'\ud83d\udcdc',
1844 'seat':'\ud83d\udcba',
1845 'secret':'\u3299\ufe0f',
1846 'see_no_evil':'\ud83d\ude48',
1847 'seedling':'\ud83c\udf31',
1848 'selfie':'\ud83e\udd33',
1849 'shallow_pan_of_food':'\ud83e\udd58',
1850 'shamrock':'\u2618\ufe0f',
1851 'shark':'\ud83e\udd88',
1852 'shaved_ice':'\ud83c\udf67',
1853 'sheep':'\ud83d\udc11',
1854 'shell':'\ud83d\udc1a',
1855 'shield':'\ud83d\udee1',
1856 'shinto_shrine':'\u26e9',
1857 'ship':'\ud83d\udea2',
1858 'shirt':'\ud83d\udc55',
1859 'shopping':'\ud83d\udecd',
1860 'shopping_cart':'\ud83d\uded2',
1861 'shower':'\ud83d\udebf',
1862 'shrimp':'\ud83e\udd90',
1863 'signal_strength':'\ud83d\udcf6',
1864 'six_pointed_star':'\ud83d\udd2f',
1865 'ski':'\ud83c\udfbf',
1866 'skier':'\u26f7',
1867 'skull':'\ud83d\udc80',
1868 'skull_and_crossbones':'\u2620\ufe0f',
1869 'sleeping':'\ud83d\ude34',
1870 'sleeping_bed':'\ud83d\udecc',
1871 'sleepy':'\ud83d\ude2a',
1872 'slightly_frowning_face':'\ud83d\ude41',
1873 'slightly_smiling_face':'\ud83d\ude42',
1874 'slot_machine':'\ud83c\udfb0',
1875 'small_airplane':'\ud83d\udee9',
1876 'small_blue_diamond':'\ud83d\udd39',
1877 'small_orange_diamond':'\ud83d\udd38',
1878 'small_red_triangle':'\ud83d\udd3a',
1879 'small_red_triangle_down':'\ud83d\udd3b',
1880 'smile':'\ud83d\ude04',
1881 'smile_cat':'\ud83d\ude38',
1882 'smiley':'\ud83d\ude03',
1883 'smiley_cat':'\ud83d\ude3a',
1884 'smiling_imp':'\ud83d\ude08',
1885 'smirk':'\ud83d\ude0f',
1886 'smirk_cat':'\ud83d\ude3c',
1887 'smoking':'\ud83d\udeac',
1888 'snail':'\ud83d\udc0c',
1889 'snake':'\ud83d\udc0d',
1890 'sneezing_face':'\ud83e\udd27',
1891 'snowboarder':'\ud83c\udfc2',
1892 'snowflake':'\u2744\ufe0f',
1893 'snowman':'\u26c4\ufe0f',
1894 'snowman_with_snow':'\u2603\ufe0f',
1895 'sob':'\ud83d\ude2d',
1896 'soccer':'\u26bd\ufe0f',
1897 'soon':'\ud83d\udd1c',
1898 'sos':'\ud83c\udd98',
1899 'sound':'\ud83d\udd09',
1900 'space_invader':'\ud83d\udc7e',
1901 'spades':'\u2660\ufe0f',
1902 'spaghetti':'\ud83c\udf5d',
1903 'sparkle':'\u2747\ufe0f',
1904 'sparkler':'\ud83c\udf87',
1905 'sparkles':'\u2728',
1906 'sparkling_heart':'\ud83d\udc96',
1907 'speak_no_evil':'\ud83d\ude4a',
1908 'speaker':'\ud83d\udd08',
1909 'speaking_head':'\ud83d\udde3',
1910 'speech_balloon':'\ud83d\udcac',
1911 'speedboat':'\ud83d\udea4',
1912 'spider':'\ud83d\udd77',
1913 'spider_web':'\ud83d\udd78',
1914 'spiral_calendar':'\ud83d\uddd3',
1915 'spiral_notepad':'\ud83d\uddd2',
1916 'spoon':'\ud83e\udd44',
1917 'squid':'\ud83e\udd91',
1918 'stadium':'\ud83c\udfdf',
1919 'star':'\u2b50\ufe0f',
1920 'star2':'\ud83c\udf1f',
1921 'star_and_crescent':'\u262a\ufe0f',
1922 'star_of_david':'\u2721\ufe0f',
1923 'stars':'\ud83c\udf20',
1924 'station':'\ud83d\ude89',
1925 'statue_of_liberty':'\ud83d\uddfd',
1926 'steam_locomotive':'\ud83d\ude82',
1927 'stew':'\ud83c\udf72',
1928 'stop_button':'\u23f9',
1929 'stop_sign':'\ud83d\uded1',
1930 'stopwatch':'\u23f1',
1931 'straight_ruler':'\ud83d\udccf',
1932 'strawberry':'\ud83c\udf53',
1933 'stuck_out_tongue':'\ud83d\ude1b',
1934 'stuck_out_tongue_closed_eyes':'\ud83d\ude1d',
1935 'stuck_out_tongue_winking_eye':'\ud83d\ude1c',
1936 'studio_microphone':'\ud83c\udf99',
1937 'stuffed_flatbread':'\ud83e\udd59',
1938 'sun_behind_large_cloud':'\ud83c\udf25',
1939 'sun_behind_rain_cloud':'\ud83c\udf26',
1940 'sun_behind_small_cloud':'\ud83c\udf24',
1941 'sun_with_face':'\ud83c\udf1e',
1942 'sunflower':'\ud83c\udf3b',
1943 'sunglasses':'\ud83d\ude0e',
1944 'sunny':'\u2600\ufe0f',
1945 'sunrise':'\ud83c\udf05',
1946 'sunrise_over_mountains':'\ud83c\udf04',
1947 'surfing_man':'\ud83c\udfc4',
1948 'surfing_woman':'\ud83c\udfc4&zwj;\u2640\ufe0f',
1949 'sushi':'\ud83c\udf63',
1950 'suspension_railway':'\ud83d\ude9f',
1951 'sweat':'\ud83d\ude13',
1952 'sweat_drops':'\ud83d\udca6',
1953 'sweat_smile':'\ud83d\ude05',
1954 'sweet_potato':'\ud83c\udf60',
1955 'swimming_man':'\ud83c\udfca',
1956 'swimming_woman':'\ud83c\udfca&zwj;\u2640\ufe0f',
1957 'symbols':'\ud83d\udd23',
1958 'synagogue':'\ud83d\udd4d',
1959 'syringe':'\ud83d\udc89',
1960 'taco':'\ud83c\udf2e',
1961 'tada':'\ud83c\udf89',
1962 'tanabata_tree':'\ud83c\udf8b',
1963 'taurus':'\u2649\ufe0f',
1964 'taxi':'\ud83d\ude95',
1965 'tea':'\ud83c\udf75',
1966 'telephone_receiver':'\ud83d\udcde',
1967 'telescope':'\ud83d\udd2d',
1968 'tennis':'\ud83c\udfbe',
1969 'tent':'\u26fa\ufe0f',
1970 'thermometer':'\ud83c\udf21',
1971 'thinking':'\ud83e\udd14',
1972 'thought_balloon':'\ud83d\udcad',
1973 'ticket':'\ud83c\udfab',
1974 'tickets':'\ud83c\udf9f',
1975 'tiger':'\ud83d\udc2f',
1976 'tiger2':'\ud83d\udc05',
1977 'timer_clock':'\u23f2',
1978 'tipping_hand_man':'\ud83d\udc81&zwj;\u2642\ufe0f',
1979 'tired_face':'\ud83d\ude2b',
1980 'tm':'\u2122\ufe0f',
1981 'toilet':'\ud83d\udebd',
1982 'tokyo_tower':'\ud83d\uddfc',
1983 'tomato':'\ud83c\udf45',
1984 'tongue':'\ud83d\udc45',
1985 'top':'\ud83d\udd1d',
1986 'tophat':'\ud83c\udfa9',
1987 'tornado':'\ud83c\udf2a',
1988 'trackball':'\ud83d\uddb2',
1989 'tractor':'\ud83d\ude9c',
1990 'traffic_light':'\ud83d\udea5',
1991 'train':'\ud83d\ude8b',
1992 'train2':'\ud83d\ude86',
1993 'tram':'\ud83d\ude8a',
1994 'triangular_flag_on_post':'\ud83d\udea9',
1995 'triangular_ruler':'\ud83d\udcd0',
1996 'trident':'\ud83d\udd31',
1997 'triumph':'\ud83d\ude24',
1998 'trolleybus':'\ud83d\ude8e',
1999 'trophy':'\ud83c\udfc6',
2000 'tropical_drink':'\ud83c\udf79',
2001 'tropical_fish':'\ud83d\udc20',
2002 'truck':'\ud83d\ude9a',
2003 'trumpet':'\ud83c\udfba',
2004 'tulip':'\ud83c\udf37',
2005 'tumbler_glass':'\ud83e\udd43',
2006 'turkey':'\ud83e\udd83',
2007 'turtle':'\ud83d\udc22',
2008 'tv':'\ud83d\udcfa',
2009 'twisted_rightwards_arrows':'\ud83d\udd00',
2010 'two_hearts':'\ud83d\udc95',
2011 'two_men_holding_hands':'\ud83d\udc6c',
2012 'two_women_holding_hands':'\ud83d\udc6d',
2013 'u5272':'\ud83c\ude39',
2014 'u5408':'\ud83c\ude34',
2015 'u55b6':'\ud83c\ude3a',
2016 'u6307':'\ud83c\ude2f\ufe0f',
2017 'u6708':'\ud83c\ude37\ufe0f',
2018 'u6709':'\ud83c\ude36',
2019 'u6e80':'\ud83c\ude35',
2020 'u7121':'\ud83c\ude1a\ufe0f',
2021 'u7533':'\ud83c\ude38',
2022 'u7981':'\ud83c\ude32',
2023 'u7a7a':'\ud83c\ude33',
2024 'umbrella':'\u2614\ufe0f',
2025 'unamused':'\ud83d\ude12',
2026 'underage':'\ud83d\udd1e',
2027 'unicorn':'\ud83e\udd84',
2028 'unlock':'\ud83d\udd13',
2029 'up':'\ud83c\udd99',
2030 'upside_down_face':'\ud83d\ude43',
2031 'v':'\u270c\ufe0f',
2032 'vertical_traffic_light':'\ud83d\udea6',
2033 'vhs':'\ud83d\udcfc',
2034 'vibration_mode':'\ud83d\udcf3',
2035 'video_camera':'\ud83d\udcf9',
2036 'video_game':'\ud83c\udfae',
2037 'violin':'\ud83c\udfbb',
2038 'virgo':'\u264d\ufe0f',
2039 'volcano':'\ud83c\udf0b',
2040 'volleyball':'\ud83c\udfd0',
2041 'vs':'\ud83c\udd9a',
2042 'vulcan_salute':'\ud83d\udd96',
2043 'walking_man':'\ud83d\udeb6',
2044 'walking_woman':'\ud83d\udeb6&zwj;\u2640\ufe0f',
2045 'waning_crescent_moon':'\ud83c\udf18',
2046 'waning_gibbous_moon':'\ud83c\udf16',
2047 'warning':'\u26a0\ufe0f',
2048 'wastebasket':'\ud83d\uddd1',
2049 'watch':'\u231a\ufe0f',
2050 'water_buffalo':'\ud83d\udc03',
2051 'watermelon':'\ud83c\udf49',
2052 'wave':'\ud83d\udc4b',
2053 'wavy_dash':'\u3030\ufe0f',
2054 'waxing_crescent_moon':'\ud83c\udf12',
2055 'wc':'\ud83d\udebe',
2056 'weary':'\ud83d\ude29',
2057 'wedding':'\ud83d\udc92',
2058 'weight_lifting_man':'\ud83c\udfcb\ufe0f',
2059 'weight_lifting_woman':'\ud83c\udfcb\ufe0f&zwj;\u2640\ufe0f',
2060 'whale':'\ud83d\udc33',
2061 'whale2':'\ud83d\udc0b',
2062 'wheel_of_dharma':'\u2638\ufe0f',
2063 'wheelchair':'\u267f\ufe0f',
2064 'white_check_mark':'\u2705',
2065 'white_circle':'\u26aa\ufe0f',
2066 'white_flag':'\ud83c\udff3\ufe0f',
2067 'white_flower':'\ud83d\udcae',
2068 'white_large_square':'\u2b1c\ufe0f',
2069 'white_medium_small_square':'\u25fd\ufe0f',
2070 'white_medium_square':'\u25fb\ufe0f',
2071 'white_small_square':'\u25ab\ufe0f',
2072 'white_square_button':'\ud83d\udd33',
2073 'wilted_flower':'\ud83e\udd40',
2074 'wind_chime':'\ud83c\udf90',
2075 'wind_face':'\ud83c\udf2c',
2076 'wine_glass':'\ud83c\udf77',
2077 'wink':'\ud83d\ude09',
2078 'wolf':'\ud83d\udc3a',
2079 'woman':'\ud83d\udc69',
2080 'woman_artist':'\ud83d\udc69&zwj;\ud83c\udfa8',
2081 'woman_astronaut':'\ud83d\udc69&zwj;\ud83d\ude80',
2082 'woman_cartwheeling':'\ud83e\udd38&zwj;\u2640\ufe0f',
2083 'woman_cook':'\ud83d\udc69&zwj;\ud83c\udf73',
2084 'woman_facepalming':'\ud83e\udd26&zwj;\u2640\ufe0f',
2085 'woman_factory_worker':'\ud83d\udc69&zwj;\ud83c\udfed',
2086 'woman_farmer':'\ud83d\udc69&zwj;\ud83c\udf3e',
2087 'woman_firefighter':'\ud83d\udc69&zwj;\ud83d\ude92',
2088 'woman_health_worker':'\ud83d\udc69&zwj;\u2695\ufe0f',
2089 'woman_judge':'\ud83d\udc69&zwj;\u2696\ufe0f',
2090 'woman_juggling':'\ud83e\udd39&zwj;\u2640\ufe0f',
2091 'woman_mechanic':'\ud83d\udc69&zwj;\ud83d\udd27',
2092 'woman_office_worker':'\ud83d\udc69&zwj;\ud83d\udcbc',
2093 'woman_pilot':'\ud83d\udc69&zwj;\u2708\ufe0f',
2094 'woman_playing_handball':'\ud83e\udd3e&zwj;\u2640\ufe0f',
2095 'woman_playing_water_polo':'\ud83e\udd3d&zwj;\u2640\ufe0f',
2096 'woman_scientist':'\ud83d\udc69&zwj;\ud83d\udd2c',
2097 'woman_shrugging':'\ud83e\udd37&zwj;\u2640\ufe0f',
2098 'woman_singer':'\ud83d\udc69&zwj;\ud83c\udfa4',
2099 'woman_student':'\ud83d\udc69&zwj;\ud83c\udf93',
2100 'woman_teacher':'\ud83d\udc69&zwj;\ud83c\udfeb',
2101 'woman_technologist':'\ud83d\udc69&zwj;\ud83d\udcbb',
2102 'woman_with_turban':'\ud83d\udc73&zwj;\u2640\ufe0f',
2103 'womans_clothes':'\ud83d\udc5a',
2104 'womans_hat':'\ud83d\udc52',
2105 'women_wrestling':'\ud83e\udd3c&zwj;\u2640\ufe0f',
2106 'womens':'\ud83d\udeba',
2107 'world_map':'\ud83d\uddfa',
2108 'worried':'\ud83d\ude1f',
2109 'wrench':'\ud83d\udd27',
2110 'writing_hand':'\u270d\ufe0f',
2111 'x':'\u274c',
2112 'yellow_heart':'\ud83d\udc9b',
2113 'yen':'\ud83d\udcb4',
2114 'yin_yang':'\u262f\ufe0f',
2115 'yum':'\ud83d\ude0b',
2116 'zap':'\u26a1\ufe0f',
2117 'zipper_mouth_face':'\ud83e\udd10',
2118 'zzz':'\ud83d\udca4',
2119
2120 /* special emojis :P */
2121 'octocat': '<img width="20" height="20" align="absmiddle" src="data:image/png;base64,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">',
2122 'showdown': '<img width="20" height="20" align="absmiddle" src="data:image/png;base64,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/GMzLdsAAECtaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzA2NyA3OS4xNTc3NDcsIDIwMTUvMDMvMzAtMjM6NDA6NDIgICAgICAgICI+CiAgIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgICAgIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgICAgICAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgICAgICAgICB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC94bXA6Q3JlYXRlRGF0ZT4KICAgICAgICAgPHhtcDpNZXRhZGF0YURhdGU+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwveG1wOk1ldGFkYXRhRGF0ZT4KICAgICAgICAgPHhtcDpNb2RpZnlEYXRlPjIwMTctMTAtMjRUMTM6MzE6MzArMDE6MDA8L3htcDpNb2RpZnlEYXRlPgogICAgICAgICA8cGhvdG9zaG9wOkNvbG9yTW9kZT4zPC9waG90b3Nob3A6Q29sb3JNb2RlPgogICAgICAgICA8cGhvdG9zaG9wOklDQ1Byb2ZpbGU+c1JHQiBJRUM2MTk2Ni0yLjE8L3Bob3Rvc2hvcDpJQ0NQcm9maWxlPgogICAgICAgICA8cGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHBob3Rvc2hvcDpMYXllck5hbWU+UyAtPC9waG90b3Nob3A6TGF5ZXJOYW1lPgogICAgICAgICAgICAgICAgICA8cGhvdG9zaG9wOkxheWVyVGV4dD5TIC08L3Bob3Rvc2hvcDpMYXllclRleHQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgIDwvcGhvdG9zaG9wOlRleHRMYXllcnM+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6N2NkMzQxNzctOWYyZi0yNDRiLWEyYjQtMzU1MzJkY2Y1MWJiPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6M2E1YzgxYmYtYjhiNy0xMWU3LTk0NDktYTQ2MzdlZjJkNjMzPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPHhtcE1NOkhpc3Rvcnk+CiAgICAgICAgICAgIDxyZGY6U2VxPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jcmVhdGVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTUtMDEtMTVUMjE6MDE6MTlaPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ1M2IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPnNhdmVkPC9zdEV2dDphY3Rpb24+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdEV2dDppbnN0YW5jZUlEPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6d2hlbj4yMDE3LTEwLTI0VDEzOjMxOjMwKzAxOjAwPC9zdEV2dDp3aGVuPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6c29mdHdhcmVBZ2VudD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNSAoV2luZG93cyk8L3N0RXZ0OnNvZnR3YXJlQWdlbnQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpjaGFuZ2VkPi88L3N0RXZ0OmNoYW5nZWQ+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5jb252ZXJ0ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+ZnJvbSBhcHBsaWNhdGlvbi92bmQuYWRvYmUucGhvdG9zaG9wIHRvIGltYWdlL3BuZzwvc3RFdnQ6cGFyYW1ldGVycz4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgICAgIDxyZGY6bGkgcmRmOnBhcnNlVHlwZT0iUmVzb3VyY2UiPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6YWN0aW9uPmRlcml2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnBhcmFtZXRlcnM+Y29udmVydGVkIGZyb20gYXBwbGljYXRpb24vdm5kLmFkb2JlLnBob3Rvc2hvcCB0byBpbWFnZS9wbmc8L3N0RXZ0OnBhcmFtZXRlcnM+CiAgICAgICAgICAgICAgIDwvcmRmOmxpPgogICAgICAgICAgICAgICA8cmRmOmxpIHJkZjpwYXJzZVR5cGU9IlJlc291cmNlIj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmFjdGlvbj5zYXZlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOjdjZDM0MTc3LTlmMmYtMjQ0Yi1hMmI0LTM1NTMyZGNmNTFiYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0xMC0yNFQxMzozMTozMCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICAgICA8c3RFdnQ6Y2hhbmdlZD4vPC9zdEV2dDpjaGFuZ2VkPgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgPC9yZGY6U2VxPgogICAgICAgICA8L3htcE1NOkhpc3Rvcnk+CiAgICAgICAgIDx4bXBNTTpEZXJpdmVkRnJvbSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgIDxzdFJlZjppbnN0YW5jZUlEPnhtcC5paWQ6ODZjNjBkMGQtOGY0Yy01ZTRlLWEwMjQtODI4ZWQyNTIwZDc3PC9zdFJlZjppbnN0YW5jZUlEPgogICAgICAgICAgICA8c3RSZWY6ZG9jdW1lbnRJRD54bXAuZGlkOjYwQzVBRTY1RjY5Q0U0MTE5NDVBODU1RTNCQ0E3RUVCPC9zdFJlZjpkb2N1bWVudElEPgogICAgICAgICAgICA8c3RSZWY6b3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6NjBDNUFFNjVGNjlDRTQxMTk0NUE4NTVFM0JDQTdFRUI8L3N0UmVmOm9yaWdpbmFsRG9jdW1lbnRJRD4KICAgICAgICAgPC94bXBNTTpEZXJpdmVkRnJvbT4KICAgICAgICAgPHRpZmY6T3JpZW50YXRpb24+MTwvdGlmZjpPcmllbnRhdGlvbj4KICAgICAgICAgPHRpZmY6WFJlc29sdXRpb24+NzIwMDAwLzEwMDAwPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WVJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDxleGlmOkNvbG9yU3BhY2U+MTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NjQ8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/Pse7bzcAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAA1JJREFUeNrsm1+OmlAUhz+aeS9dwZggJn1AnRUMO6jpBgZXULuC2hWUWUGZBTSxKyiuoA4mfUBMnB04K5g+9DihRBHlyh/lJLwIXLgf99xzzu9etZeXFy7Z3nDh1gBoAFy4XeVtQNO0zNcapmUDfUBPnFoBfhQGq6IBaHmjwD4Ahmk5wAD4kKG5J8CNwsAFaHe6DvA9cc0wCgOv8gDka3vA9RHNPgo0D7hNnJtGYWBXxgV2dH4MfMnRRA+Y1WIO2NJ5F/ikoKm3tYsChmkNFHW+fmHQMC1dfHaXPQP3wM1yMdc2B/AOGALTWobBmI1Shu0UGCwX83XyRBQGawHntTtdG5gUNfxVu4CTNqNv6/wWGL7kCc+1AmCYVisl3I2ydD4GYZUCs7IjoLXrxHIx9w9tLAqDCfBwDrXAY457x+cAoCfuwRGjYFUnAGk+PsjR7s8Dn1VeLWCYVlpDw+VivjVHSHt+u9PVJbzGzZXQWTkAkz0V31fATUaEsjVJlQBs4FeGcteLgzgbAALBA+4y3voAeJL8nA0AHfClnM1qm1HhnYUidCSE+KzvSSJUTwAxCOMcpfETMFYpfRUKIAbCFhC3OTJJJwqDWS0BxED0JZ4Pjix1P2+E0loCSMBwyK4S/xc1ojBwag8gMU84cvTKGgmlAYhngu1O9xAXuVE5J1QCQCz3bwHuHvdQui5QKQAxEO6eEKpsFCgTRSXkvdoxSlBMCxhJJbgrrbZRtHCiShN0pRB6PeQ3ckBw2K0oKXMBVYJIP+Nvh9qulFivGoBt1lLQxowT2ykBXCfnhZIglgYACWmqXQv+baioBYCeiCQHm+QEg1O7RhF7hO4OhSAhcJKSFU7qBGADwZeqMMuXn6TUBw8qlaMrirNb4LdhWlP+SWD+cjFfxTpuS2GUpik+o3jFSEkqbJiWn0P0OMSGqlWiOu0TvD+FRHZKAE+oW+cfRmEwqlsesJJEJs8y91QqP+9UL6lqEtz2gpuNEY5sm9sIHln2DRa2aFKGJtiXkZEMiWtgVvRKUSUFkSKt2S7fAGgAXLYpmQQXf36MUChTZdUa2u8/rkvPA6Tz30r4eH3ybcBS5gJ6SaNXb+aABkA1AMxKenclBZLW/He4cYEGwEXb3wEASelexk6LIIIAAAAASUVORK5CYII=">'
2123};
2124
2125/**
2126 * Created by Estevao on 31-05-2015.
2127 */
2128
2129/**
2130 * Showdown Converter class
2131 * @class
2132 * @param {object} [converterOptions]
2133 * @returns {Converter}
2134 */
2135showdown.Converter = function (converterOptions) {
2136 'use strict';
2137
2138 var
2139 /**
2140 * Options used by this converter
2141 * @private
2142 * @type {{}}
2143 */
2144 options = {},
2145
2146 /**
2147 * Language extensions used by this converter
2148 * @private
2149 * @type {Array}
2150 */
2151 langExtensions = [],
2152
2153 /**
2154 * Output modifiers extensions used by this converter
2155 * @private
2156 * @type {Array}
2157 */
2158 outputModifiers = [],
2159
2160 /**
2161 * Event listeners
2162 * @private
2163 * @type {{}}
2164 */
2165 listeners = {},
2166
2167 /**
2168 * The flavor set in this converter
2169 */
2170 setConvFlavor = setFlavor;
2171
2172 _constructor();
2173
2174 /**
2175 * Converter constructor
2176 * @private
2177 */
2178 function _constructor () {
2179 converterOptions = converterOptions || {};
2180
2181 for (var gOpt in globalOptions) {
2182 if (globalOptions.hasOwnProperty(gOpt)) {
2183 options[gOpt] = globalOptions[gOpt];
2184 }
2185 }
2186
2187 // Merge options
2188 if (typeof converterOptions === 'object') {
2189 for (var opt in converterOptions) {
2190 if (converterOptions.hasOwnProperty(opt)) {
2191 options[opt] = converterOptions[opt];
2192 }
2193 }
2194 } else {
2195 throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
2196 ' was passed instead.');
2197 }
2198
2199 if (options.extensions) {
2200 showdown.helper.forEach(options.extensions, _parseExtension);
2201 }
2202 }
2203
2204 /**
2205 * Parse extension
2206 * @param {*} ext
2207 * @param {string} [name='']
2208 * @private
2209 */
2210 function _parseExtension (ext, name) {
2211
2212 name = name || null;
2213 // If it's a string, the extension was previously loaded
2214 if (showdown.helper.isString(ext)) {
2215 ext = showdown.helper.stdExtName(ext);
2216 name = ext;
2217
2218 // LEGACY_SUPPORT CODE
2219 if (showdown.extensions[ext]) {
2220 console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
2221 'Please inform the developer that the extension should be updated!');
2222 legacyExtensionLoading(showdown.extensions[ext], ext);
2223 return;
2224 // END LEGACY SUPPORT CODE
2225
2226 } else if (!showdown.helper.isUndefined(extensions[ext])) {
2227 ext = extensions[ext];
2228
2229 } else {
2230 throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
2231 }
2232 }
2233
2234 if (typeof ext === 'function') {
2235 ext = ext();
2236 }
2237
2238 if (!showdown.helper.isArray(ext)) {
2239 ext = [ext];
2240 }
2241
2242 var validExt = validate(ext, name);
2243 if (!validExt.valid) {
2244 throw Error(validExt.error);
2245 }
2246
2247 for (var i = 0; i < ext.length; ++i) {
2248 switch (ext[i].type) {
2249
2250 case 'lang':
2251 langExtensions.push(ext[i]);
2252 break;
2253
2254 case 'output':
2255 outputModifiers.push(ext[i]);
2256 break;
2257 }
2258 if (ext[i].hasOwnProperty('listeners')) {
2259 for (var ln in ext[i].listeners) {
2260 if (ext[i].listeners.hasOwnProperty(ln)) {
2261 listen(ln, ext[i].listeners[ln]);
2262 }
2263 }
2264 }
2265 }
2266
2267 }
2268
2269 /**
2270 * LEGACY_SUPPORT
2271 * @param {*} ext
2272 * @param {string} name
2273 */
2274 function legacyExtensionLoading (ext, name) {
2275 if (typeof ext === 'function') {
2276 ext = ext(new showdown.Converter());
2277 }
2278 if (!showdown.helper.isArray(ext)) {
2279 ext = [ext];
2280 }
2281 var valid = validate(ext, name);
2282
2283 if (!valid.valid) {
2284 throw Error(valid.error);
2285 }
2286
2287 for (var i = 0; i < ext.length; ++i) {
2288 switch (ext[i].type) {
2289 case 'lang':
2290 langExtensions.push(ext[i]);
2291 break;
2292 case 'output':
2293 outputModifiers.push(ext[i]);
2294 break;
2295 default:// should never reach here
2296 throw Error('Extension loader error: Type unrecognized!!!');
2297 }
2298 }
2299 }
2300
2301 /**
2302 * Listen to an event
2303 * @param {string} name
2304 * @param {function} callback
2305 */
2306 function listen (name, callback) {
2307 if (!showdown.helper.isString(name)) {
2308 throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
2309 }
2310
2311 if (typeof callback !== 'function') {
2312 throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
2313 }
2314
2315 if (!listeners.hasOwnProperty(name)) {
2316 listeners[name] = [];
2317 }
2318 listeners[name].push(callback);
2319 }
2320
2321 function rTrimInputText (text) {
2322 var rsp = text.match(/^\s*/)[0].length,
2323 rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
2324 return text.replace(rgx, '');
2325 }
2326
2327 /**
2328 * Dispatch an event
2329 * @private
2330 * @param {string} evtName Event name
2331 * @param {string} text Text
2332 * @param {{}} options Converter Options
2333 * @param {{}} globals
2334 * @returns {string}
2335 */
2336 this._dispatch = function dispatch (evtName, text, options, globals) {
2337 if (listeners.hasOwnProperty(evtName)) {
2338 for (var ei = 0; ei < listeners[evtName].length; ++ei) {
2339 var nText = listeners[evtName][ei](evtName, text, this, options, globals);
2340 if (nText && typeof nText !== 'undefined') {
2341 text = nText;
2342 }
2343 }
2344 }
2345 return text;
2346 };
2347
2348 /**
2349 * Listen to an event
2350 * @param {string} name
2351 * @param {function} callback
2352 * @returns {showdown.Converter}
2353 */
2354 this.listen = function (name, callback) {
2355 listen(name, callback);
2356 return this;
2357 };
2358
2359 /**
2360 * Converts a markdown string into HTML
2361 * @param {string} text
2362 * @returns {*}
2363 */
2364 this.makeHtml = function (text) {
2365 //check if text is not falsy
2366 if (!text) {
2367 return text;
2368 }
2369
2370 var globals = {
2371 gHtmlBlocks: [],
2372 gHtmlMdBlocks: [],
2373 gHtmlSpans: [],
2374 gUrls: {},
2375 gTitles: {},
2376 gDimensions: {},
2377 gListLevel: 0,
2378 hashLinkCounts: {},
2379 langExtensions: langExtensions,
2380 outputModifiers: outputModifiers,
2381 converter: this,
2382 ghCodeBlocks: []
2383 };
2384
2385 // This lets us use ¨ trema as an escape char to avoid md5 hashes
2386 // The choice of character is arbitrary; anything that isn't
2387 // magic in Markdown will work.
2388 text = text.replace(/¨/g, '¨T');
2389
2390 // Replace $ with ¨D
2391 // RegExp interprets $ as a special character
2392 // when it's in a replacement string
2393 text = text.replace(/\$/g, '¨D');
2394
2395 // Standardize line endings
2396 text = text.replace(/\r\n/g, '\n'); // DOS to Unix
2397 text = text.replace(/\r/g, '\n'); // Mac to Unix
2398
2399 // Stardardize line spaces (nbsp causes trouble in older browsers and some regex flavors)
2400 text = text.replace(/\u00A0/g, ' ');
2401
2402 if (options.smartIndentationFix) {
2403 text = rTrimInputText(text);
2404 }
2405
2406 // Make sure text begins and ends with a couple of newlines:
2407 text = '\n\n' + text + '\n\n';
2408
2409 // detab
2410 text = showdown.subParser('detab')(text, options, globals);
2411
2412 /**
2413 * Strip any lines consisting only of spaces and tabs.
2414 * This makes subsequent regexs easier to write, because we can
2415 * match consecutive blank lines with /\n+/ instead of something
2416 * contorted like /[ \t]*\n+/
2417 */
2418 text = text.replace(/^[ \t]+$/mg, '');
2419
2420 //run languageExtensions
2421 showdown.helper.forEach(langExtensions, function (ext) {
2422 text = showdown.subParser('runExtension')(ext, text, options, globals);
2423 });
2424
2425 // run the sub parsers
2426 text = showdown.subParser('hashPreCodeTags')(text, options, globals);
2427 text = showdown.subParser('githubCodeBlocks')(text, options, globals);
2428 text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
2429 text = showdown.subParser('hashCodeTags')(text, options, globals);
2430 text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
2431 text = showdown.subParser('blockGamut')(text, options, globals);
2432 text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
2433 text = showdown.subParser('unescapeSpecialChars')(text, options, globals);
2434
2435 // attacklab: Restore dollar signs
2436 text = text.replace(/¨D/g, '$$');
2437
2438 // attacklab: Restore tremas
2439 text = text.replace(/¨T/g, '¨');
2440
2441 // Run output modifiers
2442 showdown.helper.forEach(outputModifiers, function (ext) {
2443 text = showdown.subParser('runExtension')(ext, text, options, globals);
2444 });
2445
2446 return text;
2447 };
2448
2449 /**
2450 * Set an option of this Converter instance
2451 * @param {string} key
2452 * @param {*} value
2453 */
2454 this.setOption = function (key, value) {
2455 options[key] = value;
2456 };
2457
2458 /**
2459 * Get the option of this Converter instance
2460 * @param {string} key
2461 * @returns {*}
2462 */
2463 this.getOption = function (key) {
2464 return options[key];
2465 };
2466
2467 /**
2468 * Get the options of this Converter instance
2469 * @returns {{}}
2470 */
2471 this.getOptions = function () {
2472 return options;
2473 };
2474
2475 /**
2476 * Add extension to THIS converter
2477 * @param {{}} extension
2478 * @param {string} [name=null]
2479 */
2480 this.addExtension = function (extension, name) {
2481 name = name || null;
2482 _parseExtension(extension, name);
2483 };
2484
2485 /**
2486 * Use a global registered extension with THIS converter
2487 * @param {string} extensionName Name of the previously registered extension
2488 */
2489 this.useExtension = function (extensionName) {
2490 _parseExtension(extensionName);
2491 };
2492
2493 /**
2494 * Set the flavor THIS converter should use
2495 * @param {string} name
2496 */
2497 this.setFlavor = function (name) {
2498 if (!flavor.hasOwnProperty(name)) {
2499 throw Error(name + ' flavor was not found');
2500 }
2501 var preset = flavor[name];
2502 setConvFlavor = name;
2503 for (var option in preset) {
2504 if (preset.hasOwnProperty(option)) {
2505 options[option] = preset[option];
2506 }
2507 }
2508 };
2509
2510 /**
2511 * Get the currently set flavor of this converter
2512 * @returns {string}
2513 */
2514 this.getFlavor = function () {
2515 return setConvFlavor;
2516 };
2517
2518 /**
2519 * Remove an extension from THIS converter.
2520 * Note: This is a costly operation. It's better to initialize a new converter
2521 * and specify the extensions you wish to use
2522 * @param {Array} extension
2523 */
2524 this.removeExtension = function (extension) {
2525 if (!showdown.helper.isArray(extension)) {
2526 extension = [extension];
2527 }
2528 for (var a = 0; a < extension.length; ++a) {
2529 var ext = extension[a];
2530 for (var i = 0; i < langExtensions.length; ++i) {
2531 if (langExtensions[i] === ext) {
2532 langExtensions[i].splice(i, 1);
2533 }
2534 }
2535 for (var ii = 0; ii < outputModifiers.length; ++i) {
2536 if (outputModifiers[ii] === ext) {
2537 outputModifiers[ii].splice(i, 1);
2538 }
2539 }
2540 }
2541 };
2542
2543 /**
2544 * Get all extension of THIS converter
2545 * @returns {{language: Array, output: Array}}
2546 */
2547 this.getAllExtensions = function () {
2548 return {
2549 language: langExtensions,
2550 output: outputModifiers
2551 };
2552 };
2553};
2554
2555/**
2556 * Turn Markdown link shortcuts into XHTML <a> tags.
2557 */
2558showdown.subParser('anchors', function (text, options, globals) {
2559 'use strict';
2560
2561 text = globals.converter._dispatch('anchors.before', text, options, globals);
2562
2563 var writeAnchorTag = function (wholeMatch, linkText, linkId, url, m5, m6, title) {
2564 if (showdown.helper.isUndefined(title)) {
2565 title = '';
2566 }
2567 linkId = linkId.toLowerCase();
2568
2569 // Special case for explicit empty url
2570 if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
2571 url = '';
2572 } else if (!url) {
2573 if (!linkId) {
2574 // lower-case and turn embedded newlines into spaces
2575 linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
2576 }
2577 url = '#' + linkId;
2578
2579 if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
2580 url = globals.gUrls[linkId];
2581 if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
2582 title = globals.gTitles[linkId];
2583 }
2584 } else {
2585 return wholeMatch;
2586 }
2587 }
2588
2589 //url = showdown.helper.escapeCharacters(url, '*_', false); // replaced line to improve performance
2590 url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
2591
2592 var result = '<a href="' + url + '"';
2593
2594 if (title !== '' && title !== null) {
2595 title = title.replace(/"/g, '&quot;');
2596 //title = showdown.helper.escapeCharacters(title, '*_', false); // replaced line to improve performance
2597 title = title.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
2598 result += ' title="' + title + '"';
2599 }
2600
2601 // optionLinksInNewWindow only applies
2602 // to external links. Hash links (#) open in same page
2603 if (options.openLinksInNewWindow && !/^#/.test(url)) {
2604 // escaped _
2605 result += ' target="¨E95Eblank"';
2606 }
2607
2608 result += '>' + linkText + '</a>';
2609
2610 return result;
2611 };
2612
2613 // First, handle reference-style links: [link text] [id]
2614 text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)] ?(?:\n *)?\[(.*?)]()()()()/g, writeAnchorTag);
2615
2616 // Next, inline-style links: [link text](url "optional title")
2617 // cases with crazy urls like ./image/cat1).png
2618 text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<([^>]*)>(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
2619 writeAnchorTag);
2620
2621 // normal cases
2622 text = text.replace(/\[((?:\[[^\]]*]|[^\[\]])*)]()[ \t]*\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?:[ \t]*((["'])([^"]*?)\5))?[ \t]?\)/g,
2623 writeAnchorTag);
2624
2625 // handle reference-style shortcuts: [link text]
2626 // These must come last in case you've also got [link test][1]
2627 // or [link test](/foo)
2628 text = text.replace(/\[([^\[\]]+)]()()()()()/g, writeAnchorTag);
2629
2630 // Lastly handle GithubMentions if option is enabled
2631 if (options.ghMentions) {
2632 text = text.replace(/(^|\s)(\\)?(@([a-z\d\-]+))(?=[.!?;,[\]()]|\s|$)/gmi, function (wm, st, escape, mentions, username) {
2633 if (escape === '\\') {
2634 return st + mentions;
2635 }
2636
2637 //check if options.ghMentionsLink is a string
2638 if (!showdown.helper.isString(options.ghMentionsLink)) {
2639 throw new Error('ghMentionsLink option must be a string');
2640 }
2641 var lnk = options.ghMentionsLink.replace(/\{u}/g, username),
2642 target = '';
2643 if (options.openLinksInNewWindow) {
2644 target = ' target="¨E95Eblank"';
2645 }
2646 return st + '<a href="' + lnk + '"' + target + '>' + mentions + '</a>';
2647 });
2648 }
2649
2650 text = globals.converter._dispatch('anchors.after', text, options, globals);
2651 return text;
2652});
2653
2654// url allowed chars [a-z\d_.~:/?#[]@!$&'()*+,;=-]
2655
2656var simpleURLRegex = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+?\.[^'">\s]+?)()(\1)?(?=\s|$)(?!["<>])/gi,
2657 simpleURLRegex2 = /([*~_]+|\b)(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+?)([.!?,()\[\]])?(\1)?(?=\s|$)(?!["<>])/gi,
2658 delimUrlRegex = /()<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)()>()/gi,
2659 simpleMailRegex = /(^|\s)(?:mailto:)?([A-Za-z0-9!#$%&'*+-/=?^_`{|}~.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?=$|\s)/gmi,
2660 delimMailRegex = /<()(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,
2661
2662 replaceLink = function (options) {
2663 'use strict';
2664 return function (wm, leadingMagicChars, link, m2, m3, trailingPunctuation, trailingMagicChars) {
2665 link = link.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
2666 var lnkTxt = link,
2667 append = '',
2668 target = '',
2669 lmc = leadingMagicChars || '',
2670 tmc = trailingMagicChars || '';
2671 if (/^www\./i.test(link)) {
2672 link = link.replace(/^www\./i, 'http://www.');
2673 }
2674 if (options.excludeTrailingPunctuationFromURLs && trailingPunctuation) {
2675 append = trailingPunctuation;
2676 }
2677 if (options.openLinksInNewWindow) {
2678 target = ' target="¨E95Eblank"';
2679 }
2680 return lmc + '<a href="' + link + '"' + target + '>' + lnkTxt + '</a>' + append + tmc;
2681 };
2682 },
2683
2684 replaceMail = function (options, globals) {
2685 'use strict';
2686 return function (wholeMatch, b, mail) {
2687 var href = 'mailto:';
2688 b = b || '';
2689 mail = showdown.subParser('unescapeSpecialChars')(mail, options, globals);
2690 if (options.encodeEmails) {
2691 href = showdown.helper.encodeEmailAddress(href + mail);
2692 mail = showdown.helper.encodeEmailAddress(mail);
2693 } else {
2694 href = href + mail;
2695 }
2696 return b + '<a href="' + href + '">' + mail + '</a>';
2697 };
2698 };
2699
2700showdown.subParser('autoLinks', function (text, options, globals) {
2701 'use strict';
2702
2703 text = globals.converter._dispatch('autoLinks.before', text, options, globals);
2704
2705 text = text.replace(delimUrlRegex, replaceLink(options));
2706 text = text.replace(delimMailRegex, replaceMail(options, globals));
2707
2708 text = globals.converter._dispatch('autoLinks.after', text, options, globals);
2709
2710 return text;
2711});
2712
2713showdown.subParser('simplifiedAutoLinks', function (text, options, globals) {
2714 'use strict';
2715
2716 if (!options.simplifiedAutoLink) {
2717 return text;
2718 }
2719
2720 text = globals.converter._dispatch('simplifiedAutoLinks.before', text, options, globals);
2721
2722 if (options.excludeTrailingPunctuationFromURLs) {
2723 text = text.replace(simpleURLRegex2, replaceLink(options));
2724 } else {
2725 text = text.replace(simpleURLRegex, replaceLink(options));
2726 }
2727 text = text.replace(simpleMailRegex, replaceMail(options, globals));
2728
2729 text = globals.converter._dispatch('simplifiedAutoLinks.after', text, options, globals);
2730
2731 return text;
2732});
2733
2734/**
2735 * These are all the transformations that form block-level
2736 * tags like paragraphs, headers, and list items.
2737 */
2738showdown.subParser('blockGamut', function (text, options, globals) {
2739 'use strict';
2740
2741 text = globals.converter._dispatch('blockGamut.before', text, options, globals);
2742
2743 // we parse blockquotes first so that we can have headings and hrs
2744 // inside blockquotes
2745 text = showdown.subParser('blockQuotes')(text, options, globals);
2746 text = showdown.subParser('headers')(text, options, globals);
2747
2748 // Do Horizontal Rules:
2749 text = showdown.subParser('horizontalRule')(text, options, globals);
2750
2751 text = showdown.subParser('lists')(text, options, globals);
2752 text = showdown.subParser('codeBlocks')(text, options, globals);
2753 text = showdown.subParser('tables')(text, options, globals);
2754
2755 // We already ran _HashHTMLBlocks() before, in Markdown(), but that
2756 // was to escape raw HTML in the original Markdown source. This time,
2757 // we're escaping the markup we've just created, so that we don't wrap
2758 // <p> tags around block-level tags.
2759 text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
2760 text = showdown.subParser('paragraphs')(text, options, globals);
2761
2762 text = globals.converter._dispatch('blockGamut.after', text, options, globals);
2763
2764 return text;
2765});
2766
2767showdown.subParser('blockQuotes', function (text, options, globals) {
2768 'use strict';
2769
2770 text = globals.converter._dispatch('blockQuotes.before', text, options, globals);
2771
2772 text = text.replace(/((^ {0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
2773 var bq = m1;
2774
2775 // attacklab: hack around Konqueror 3.5.4 bug:
2776 // "----------bug".replace(/^-/g,"") == "bug"
2777 bq = bq.replace(/^[ \t]*>[ \t]?/gm, '¨0'); // trim one level of quoting
2778
2779 // attacklab: clean up hack
2780 bq = bq.replace(/¨0/g, '');
2781
2782 bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
2783 bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
2784 bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
2785
2786 bq = bq.replace(/(^|\n)/g, '$1 ');
2787 // These leading spaces screw with <pre> content, so we need to fix that:
2788 bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
2789 var pre = m1;
2790 // attacklab: hack around Konqueror 3.5.4 bug:
2791 pre = pre.replace(/^ /mg, '¨0');
2792 pre = pre.replace(/¨0/g, '');
2793 return pre;
2794 });
2795
2796 return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);
2797 });
2798
2799 text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
2800 return text;
2801});
2802
2803/**
2804 * Process Markdown `<pre><code>` blocks.
2805 */
2806showdown.subParser('codeBlocks', function (text, options, globals) {
2807 'use strict';
2808
2809 text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
2810
2811 // sentinel workarounds for lack of \A and \Z, safari\khtml bug
2812 text += '¨0';
2813
2814 var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=¨0))/g;
2815 text = text.replace(pattern, function (wholeMatch, m1, m2) {
2816 var codeblock = m1,
2817 nextChar = m2,
2818 end = '\n';
2819
2820 codeblock = showdown.subParser('outdent')(codeblock, options, globals);
2821 codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
2822 codeblock = showdown.subParser('detab')(codeblock, options, globals);
2823 codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
2824 codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
2825
2826 if (options.omitExtraWLInCodeBlocks) {
2827 end = '';
2828 }
2829
2830 codeblock = '<pre><code>' + codeblock + end + '</code></pre>';
2831
2832 return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
2833 });
2834
2835 // strip sentinel
2836 text = text.replace(/¨0/, '');
2837
2838 text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
2839 return text;
2840});
2841
2842/**
2843 *
2844 * * Backtick quotes are used for <code></code> spans.
2845 *
2846 * * You can use multiple backticks as the delimiters if you want to
2847 * include literal backticks in the code span. So, this input:
2848 *
2849 * Just type ``foo `bar` baz`` at the prompt.
2850 *
2851 * Will translate to:
2852 *
2853 * <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
2854 *
2855 * There's no arbitrary limit to the number of backticks you
2856 * can use as delimters. If you need three consecutive backticks
2857 * in your code, use four for delimiters, etc.
2858 *
2859 * * You can use spaces to get literal backticks at the edges:
2860 *
2861 * ... type `` `bar` `` ...
2862 *
2863 * Turns to:
2864 *
2865 * ... type <code>`bar`</code> ...
2866 */
2867showdown.subParser('codeSpans', function (text, options, globals) {
2868 'use strict';
2869
2870 text = globals.converter._dispatch('codeSpans.before', text, options, globals);
2871
2872 if (typeof(text) === 'undefined') {
2873 text = '';
2874 }
2875 text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
2876 function (wholeMatch, m1, m2, m3) {
2877 var c = m3;
2878 c = c.replace(/^([ \t]*)/g, ''); // leading whitespace
2879 c = c.replace(/[ \t]*$/g, ''); // trailing whitespace
2880 c = showdown.subParser('encodeCode')(c, options, globals);
2881 return m1 + '<code>' + c + '</code>';
2882 }
2883 );
2884
2885 text = globals.converter._dispatch('codeSpans.after', text, options, globals);
2886 return text;
2887});
2888
2889/**
2890 * Convert all tabs to spaces
2891 */
2892showdown.subParser('detab', function (text, options, globals) {
2893 'use strict';
2894 text = globals.converter._dispatch('detab.before', text, options, globals);
2895
2896 // expand first n-1 tabs
2897 text = text.replace(/\t(?=\t)/g, ' '); // g_tab_width
2898
2899 // replace the nth with two sentinels
2900 text = text.replace(/\t/g, '¨A¨B');
2901
2902 // use the sentinel to anchor our regex so it doesn't explode
2903 text = text.replace(/¨B(.+?)¨A/g, function (wholeMatch, m1) {
2904 var leadingText = m1,
2905 numSpaces = 4 - leadingText.length % 4; // g_tab_width
2906
2907 // there *must* be a better way to do this:
2908 for (var i = 0; i < numSpaces; i++) {
2909 leadingText += ' ';
2910 }
2911
2912 return leadingText;
2913 });
2914
2915 // clean up sentinels
2916 text = text.replace(/¨A/g, ' '); // g_tab_width
2917 text = text.replace(/¨B/g, '');
2918
2919 text = globals.converter._dispatch('detab.after', text, options, globals);
2920 return text;
2921});
2922
2923showdown.subParser('ellipsis', function (text, options, globals) {
2924 'use strict';
2925
2926 text = globals.converter._dispatch('ellipsis.before', text, options, globals);
2927
2928 text = text.replace(/\.\.\./g, '…');
2929
2930 text = globals.converter._dispatch('ellipsis.after', text, options, globals);
2931
2932 return text;
2933});
2934
2935/**
2936 * These are all the transformations that occur *within* block-level
2937 * tags like paragraphs, headers, and list items.
2938 */
2939showdown.subParser('emoji', function (text, options, globals) {
2940 'use strict';
2941
2942 if (!options.emoji) {
2943 return text;
2944 }
2945
2946 text = globals.converter._dispatch('emoji.before', text, options, globals);
2947
2948 var emojiRgx = /:([\S]+?):/g;
2949
2950 text = text.replace(emojiRgx, function (wm, emojiCode) {
2951 if (showdown.helper.emojis.hasOwnProperty(emojiCode)) {
2952 return showdown.helper.emojis[emojiCode];
2953 }
2954 return wm;
2955 });
2956
2957 text = globals.converter._dispatch('emoji.after', text, options, globals);
2958
2959 return text;
2960});
2961
2962/**
2963 * Smart processing for ampersands and angle brackets that need to be encoded.
2964 */
2965showdown.subParser('encodeAmpsAndAngles', function (text, options, globals) {
2966 'use strict';
2967 text = globals.converter._dispatch('encodeAmpsAndAngles.before', text, options, globals);
2968
2969 // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
2970 // http://bumppo.net/projects/amputator/
2971 text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&amp;');
2972
2973 // Encode naked <'s
2974 text = text.replace(/<(?![a-z\/?$!])/gi, '&lt;');
2975
2976 // Encode <
2977 text = text.replace(/</g, '&lt;');
2978
2979 // Encode >
2980 text = text.replace(/>/g, '&gt;');
2981
2982 text = globals.converter._dispatch('encodeAmpsAndAngles.after', text, options, globals);
2983 return text;
2984});
2985
2986/**
2987 * Returns the string, with after processing the following backslash escape sequences.
2988 *
2989 * attacklab: The polite way to do this is with the new escapeCharacters() function:
2990 *
2991 * text = escapeCharacters(text,"\\",true);
2992 * text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
2993 *
2994 * ...but we're sidestepping its use of the (slow) RegExp constructor
2995 * as an optimization for Firefox. This function gets called a LOT.
2996 */
2997showdown.subParser('encodeBackslashEscapes', function (text, options, globals) {
2998 'use strict';
2999 text = globals.converter._dispatch('encodeBackslashEscapes.before', text, options, globals);
3000
3001 text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
3002 text = text.replace(/\\([`*_{}\[\]()>#+.!~=|-])/g, showdown.helper.escapeCharactersCallback);
3003
3004 text = globals.converter._dispatch('encodeBackslashEscapes.after', text, options, globals);
3005 return text;
3006});
3007
3008/**
3009 * Encode/escape certain characters inside Markdown code runs.
3010 * The point is that in code, these characters are literals,
3011 * and lose their special Markdown meanings.
3012 */
3013showdown.subParser('encodeCode', function (text, options, globals) {
3014 'use strict';
3015
3016 text = globals.converter._dispatch('encodeCode.before', text, options, globals);
3017
3018 // Encode all ampersands; HTML entities are not
3019 // entities within a Markdown code span.
3020 text = text
3021 .replace(/&/g, '&amp;')
3022 // Do the angle bracket song and dance:
3023 .replace(/</g, '&lt;')
3024 .replace(/>/g, '&gt;')
3025 // Now, escape characters that are magic in Markdown:
3026 .replace(/([*_{}\[\]\\=~-])/g, showdown.helper.escapeCharactersCallback);
3027
3028 text = globals.converter._dispatch('encodeCode.after', text, options, globals);
3029 return text;
3030});
3031
3032/**
3033 * Within tags -- meaning between < and > -- encode [\ ` * _ ~ =] so they
3034 * don't conflict with their use in Markdown for code, italics and strong.
3035 */
3036showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text, options, globals) {
3037 'use strict';
3038 text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.before', text, options, globals);
3039
3040 // Build a regex to find HTML tags.
3041 var tags = /<\/?[a-z\d_:-]+(?:[\s]+[\s\S]+?)?>/gi,
3042 comments = /<!(--(?:(?:[^>-]|-[^>])(?:[^-]|-[^-])*)--)>/gi;
3043
3044 text = text.replace(tags, function (wholeMatch) {
3045 return wholeMatch
3046 .replace(/(.)<\/?code>(?=.)/g, '$1`')
3047 .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);
3048 });
3049
3050 text = text.replace(comments, function (wholeMatch) {
3051 return wholeMatch
3052 .replace(/([\\`*_~=|])/g, showdown.helper.escapeCharactersCallback);
3053 });
3054
3055 text = globals.converter._dispatch('escapeSpecialCharsWithinTagAttributes.after', text, options, globals);
3056 return text;
3057});
3058
3059/**
3060 * Handle github codeblocks prior to running HashHTML so that
3061 * HTML contained within the codeblock gets escaped properly
3062 * Example:
3063 * ```ruby
3064 * def hello_world(x)
3065 * puts "Hello, #{x}"
3066 * end
3067 * ```
3068 */
3069showdown.subParser('githubCodeBlocks', function (text, options, globals) {
3070 'use strict';
3071
3072 // early exit if option is not enabled
3073 if (!options.ghCodeBlocks) {
3074 return text;
3075 }
3076
3077 text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
3078
3079 text += '¨0';
3080
3081 text = text.replace(/(?:^|\n)(```+|~~~+)([^\s`~]*)\n([\s\S]*?)\n\1/g, function (wholeMatch, delim, language, codeblock) {
3082 var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
3083
3084 // First parse the github code block
3085 codeblock = showdown.subParser('encodeCode')(codeblock, options, globals);
3086 codeblock = showdown.subParser('detab')(codeblock, options, globals);
3087 codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
3088 codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
3089
3090 codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
3091
3092 codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
3093
3094 // Since GHCodeblocks can be false positives, we need to
3095 // store the primitive text and the parsed text in a global var,
3096 // and then return a token
3097 return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
3098 });
3099
3100 // attacklab: strip sentinel
3101 text = text.replace(/¨0/, '');
3102
3103 return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
3104});
3105
3106showdown.subParser('hashBlock', function (text, options, globals) {
3107 'use strict';
3108 text = globals.converter._dispatch('hashBlock.before', text, options, globals);
3109 text = text.replace(/(^\n+|\n+$)/g, '');
3110 text = '\n\n¨K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
3111 text = globals.converter._dispatch('hashBlock.after', text, options, globals);
3112 return text;
3113});
3114
3115/**
3116 * Hash and escape <code> elements that should not be parsed as markdown
3117 */
3118showdown.subParser('hashCodeTags', function (text, options, globals) {
3119 'use strict';
3120 text = globals.converter._dispatch('hashCodeTags.before', text, options, globals);
3121
3122 var repFunc = function (wholeMatch, match, left, right) {
3123 var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
3124 return '¨C' + (globals.gHtmlSpans.push(codeblock) - 1) + 'C';
3125 };
3126
3127 // Hash naked <code>
3128 text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '<code\\b[^>]*>', '</code>', 'gim');
3129
3130 text = globals.converter._dispatch('hashCodeTags.after', text, options, globals);
3131 return text;
3132});
3133
3134showdown.subParser('hashElement', function (text, options, globals) {
3135 'use strict';
3136
3137 return function (wholeMatch, m1) {
3138 var blockText = m1;
3139
3140 // Undo double lines
3141 blockText = blockText.replace(/\n\n/g, '\n');
3142 blockText = blockText.replace(/^\n/, '');
3143
3144 // strip trailing blank lines
3145 blockText = blockText.replace(/\n+$/g, '');
3146
3147 // Replace the element text with a marker ("¨KxK" where x is its key)
3148 blockText = '\n\n¨K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
3149
3150 return blockText;
3151 };
3152});
3153
3154showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
3155 'use strict';
3156 text = globals.converter._dispatch('hashHTMLBlocks.before', text, options, globals);
3157
3158 var blockTags = [
3159 'pre',
3160 'div',
3161 'h1',
3162 'h2',
3163 'h3',
3164 'h4',
3165 'h5',
3166 'h6',
3167 'blockquote',
3168 'table',
3169 'dl',
3170 'ol',
3171 'ul',
3172 'script',
3173 'noscript',
3174 'form',
3175 'fieldset',
3176 'iframe',
3177 'math',
3178 'style',
3179 'section',
3180 'header',
3181 'footer',
3182 'nav',
3183 'article',
3184 'aside',
3185 'address',
3186 'audio',
3187 'canvas',
3188 'figure',
3189 'hgroup',
3190 'output',
3191 'video',
3192 'p'
3193 ],
3194 repFunc = function (wholeMatch, match, left, right) {
3195 var txt = wholeMatch;
3196 // check if this html element is marked as markdown
3197 // if so, it's contents should be parsed as markdown
3198 if (left.search(/\bmarkdown\b/) !== -1) {
3199 txt = left + globals.converter.makeHtml(match) + right;
3200 }
3201 return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
3202 };
3203
3204 if (options.backslashEscapesHTMLTags) {
3205 // encode backslash escaped HTML tags
3206 text = text.replace(/\\<(\/?[^>]+?)>/g, function (wm, inside) {
3207 return '&lt;' + inside + '&gt;';
3208 });
3209 }
3210
3211 // hash HTML Blocks
3212 for (var i = 0; i < blockTags.length; ++i) {
3213
3214 var opTagPos,
3215 rgx1 = new RegExp('^ {0,3}(<' + blockTags[i] + '\\b[^>]*>)', 'im'),
3216 patLeft = '<' + blockTags[i] + '\\b[^>]*>',
3217 patRight = '</' + blockTags[i] + '>';
3218 // 1. Look for the first position of the first opening HTML tag in the text
3219 while ((opTagPos = showdown.helper.regexIndexOf(text, rgx1)) !== -1) {
3220
3221 // if the HTML tag is \ escaped, we need to escape it and break
3222
3223
3224 //2. Split the text in that position
3225 var subTexts = showdown.helper.splitAtIndex(text, opTagPos),
3226 //3. Match recursively
3227 newSubText1 = showdown.helper.replaceRecursiveRegExp(subTexts[1], repFunc, patLeft, patRight, 'im');
3228
3229 // prevent an infinite loop
3230 if (newSubText1 === subTexts[1]) {
3231 break;
3232 }
3233 text = subTexts[0].concat(newSubText1);
3234 }
3235 }
3236 // HR SPECIAL CASE
3237 text = text.replace(/(\n {0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
3238 showdown.subParser('hashElement')(text, options, globals));
3239
3240 // Special case for standalone HTML comments
3241 text = showdown.helper.replaceRecursiveRegExp(text, function (txt) {
3242 return '\n\n¨K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
3243 }, '^ {0,3}<!--', '-->', 'gm');
3244
3245 // PHP and ASP-style processor instructions (<?...?> and <%...%>)
3246 text = text.replace(/(?:\n\n)( {0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
3247 showdown.subParser('hashElement')(text, options, globals));
3248
3249 text = globals.converter._dispatch('hashHTMLBlocks.after', text, options, globals);
3250 return text;
3251});
3252
3253/**
3254 * Hash span elements that should not be parsed as markdown
3255 */
3256showdown.subParser('hashHTMLSpans', function (text, options, globals) {
3257 'use strict';
3258 text = globals.converter._dispatch('hashHTMLSpans.before', text, options, globals);
3259
3260 function hashHTMLSpan (html) {
3261 return '¨C' + (globals.gHtmlSpans.push(html) - 1) + 'C';
3262 }
3263
3264 // Hash Self Closing tags
3265 text = text.replace(/<[^>]+?\/>/gi, function (wm) {
3266 return hashHTMLSpan(wm);
3267 });
3268
3269 // Hash tags without properties
3270 text = text.replace(/<([^>]+?)>[\s\S]*?<\/\1>/g, function (wm) {
3271 return hashHTMLSpan(wm);
3272 });
3273
3274 // Hash tags with properties
3275 text = text.replace(/<([^>]+?)\s[^>]+?>[\s\S]*?<\/\1>/g, function (wm) {
3276 return hashHTMLSpan(wm);
3277 });
3278
3279 // Hash self closing tags without />
3280 text = text.replace(/<[^>]+?>/gi, function (wm) {
3281 return hashHTMLSpan(wm);
3282 });
3283
3284 /*showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');*/
3285
3286 text = globals.converter._dispatch('hashHTMLSpans.after', text, options, globals);
3287 return text;
3288});
3289
3290/**
3291 * Unhash HTML spans
3292 */
3293showdown.subParser('unhashHTMLSpans', function (text, options, globals) {
3294 'use strict';
3295 text = globals.converter._dispatch('unhashHTMLSpans.before', text, options, globals);
3296
3297 for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
3298 var repText = globals.gHtmlSpans[i],
3299 // limiter to prevent infinite loop (assume 10 as limit for recurse)
3300 limit = 0;
3301
3302 while (/¨C(\d+)C/.test(repText)) {
3303 var num = RegExp.$1;
3304 repText = repText.replace('¨C' + num + 'C', globals.gHtmlSpans[num]);
3305 if (limit === 10) {
3306 break;
3307 }
3308 ++limit;
3309 }
3310 text = text.replace('¨C' + i + 'C', repText);
3311 }
3312
3313 text = globals.converter._dispatch('unhashHTMLSpans.after', text, options, globals);
3314 return text;
3315});
3316
3317/**
3318 * Hash and escape <pre><code> elements that should not be parsed as markdown
3319 */
3320showdown.subParser('hashPreCodeTags', function (text, options, globals) {
3321 'use strict';
3322 text = globals.converter._dispatch('hashPreCodeTags.before', text, options, globals);
3323
3324 var repFunc = function (wholeMatch, match, left, right) {
3325 // encode html entities
3326 var codeblock = left + showdown.subParser('encodeCode')(match, options, globals) + right;
3327 return '\n\n¨G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
3328 };
3329
3330 // Hash <pre><code>
3331 text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^ {0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^ {0,3}</code>\\s*</pre>', 'gim');
3332
3333 text = globals.converter._dispatch('hashPreCodeTags.after', text, options, globals);
3334 return text;
3335});
3336
3337showdown.subParser('headers', function (text, options, globals) {
3338 'use strict';
3339
3340 text = globals.converter._dispatch('headers.before', text, options, globals);
3341
3342 var headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
3343
3344 // Set text-style headers:
3345 // Header 1
3346 // ========
3347 //
3348 // Header 2
3349 // --------
3350 //
3351 setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
3352 setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
3353
3354 text = text.replace(setextRegexH1, function (wholeMatch, m1) {
3355
3356 var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
3357 hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
3358 hLevel = headerLevelStart,
3359 hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
3360 return showdown.subParser('hashBlock')(hashBlock, options, globals);
3361 });
3362
3363 text = text.replace(setextRegexH2, function (matchFound, m1) {
3364 var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
3365 hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
3366 hLevel = headerLevelStart + 1,
3367 hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
3368 return showdown.subParser('hashBlock')(hashBlock, options, globals);
3369 });
3370
3371 // atx-style headers:
3372 // # Header 1
3373 // ## Header 2
3374 // ## Header 2 with closing hashes ##
3375 // ...
3376 // ###### Header 6
3377 //
3378 var atxStyle = (options.requireSpaceBeforeHeadingText) ? /^(#{1,6})[ \t]+(.+?)[ \t]*#*\n+/gm : /^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm;
3379
3380 text = text.replace(atxStyle, function (wholeMatch, m1, m2) {
3381 var hText = m2;
3382 if (options.customizedHeaderId) {
3383 hText = m2.replace(/\s?\{([^{]+?)}\s*$/, '');
3384 }
3385
3386 var span = showdown.subParser('spanGamut')(hText, options, globals),
3387 hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
3388 hLevel = headerLevelStart - 1 + m1.length,
3389 header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';
3390
3391 return showdown.subParser('hashBlock')(header, options, globals);
3392 });
3393
3394 function headerId (m) {
3395 var title,
3396 prefix;
3397
3398 // It is separate from other options to allow combining prefix and customized
3399 if (options.customizedHeaderId) {
3400 var match = m.match(/\{([^{]+?)}\s*$/);
3401 if (match && match[1]) {
3402 m = match[1];
3403 }
3404 }
3405
3406 title = m;
3407
3408 // Prefix id to prevent causing inadvertent pre-existing style matches.
3409 if (showdown.helper.isString(options.prefixHeaderId)) {
3410 prefix = options.prefixHeaderId;
3411 } else if (options.prefixHeaderId === true) {
3412 prefix = 'section-';
3413 } else {
3414 prefix = '';
3415 }
3416
3417 if (!options.rawPrefixHeaderId) {
3418 title = prefix + title;
3419 }
3420
3421 if (options.ghCompatibleHeaderId) {
3422 title = title
3423 .replace(/ /g, '-')
3424 // replace previously escaped chars (&, ¨ and $)
3425 .replace(/&amp;/g, '')
3426 .replace(/¨T/g, '')
3427 .replace(/¨D/g, '')
3428 // replace rest of the chars (&~$ are repeated as they might have been escaped)
3429 // borrowed from github's redcarpet (some they should produce similar results)
3430 .replace(/[&+$,\/:;=?@"#{}|^¨~\[\]`\\*)(%.!'<>]/g, '')
3431 .toLowerCase();
3432 } else if (options.rawHeaderId) {
3433 title = title
3434 .replace(/ /g, '-')
3435 // replace previously escaped chars (&, ¨ and $)
3436 .replace(/&amp;/g, '&')
3437 .replace(/¨T/g, '¨')
3438 .replace(/¨D/g, '$')
3439 // replace " and '
3440 .replace(/["']/g, '-')
3441 .toLowerCase();
3442 } else {
3443 title = title
3444 .replace(/[^\w]/g, '')
3445 .toLowerCase();
3446 }
3447
3448 if (options.rawPrefixHeaderId) {
3449 title = prefix + title;
3450 }
3451
3452 if (globals.hashLinkCounts[title]) {
3453 title = title + '-' + (globals.hashLinkCounts[title]++);
3454 } else {
3455 globals.hashLinkCounts[title] = 1;
3456 }
3457 return title;
3458 }
3459
3460 text = globals.converter._dispatch('headers.after', text, options, globals);
3461 return text;
3462});
3463
3464/**
3465 * Turn Markdown link shortcuts into XHTML <a> tags.
3466 */
3467showdown.subParser('horizontalRule', function (text, options, globals) {
3468 'use strict';
3469 text = globals.converter._dispatch('horizontalRule.before', text, options, globals);
3470
3471 var key = showdown.subParser('hashBlock')('<hr />', options, globals);
3472 text = text.replace(/^ {0,2}( ?-){3,}[ \t]*$/gm, key);
3473 text = text.replace(/^ {0,2}( ?\*){3,}[ \t]*$/gm, key);
3474 text = text.replace(/^ {0,2}( ?_){3,}[ \t]*$/gm, key);
3475
3476 text = globals.converter._dispatch('horizontalRule.after', text, options, globals);
3477 return text;
3478});
3479
3480/**
3481 * Turn Markdown image shortcuts into <img> tags.
3482 */
3483showdown.subParser('images', function (text, options, globals) {
3484 'use strict';
3485
3486 text = globals.converter._dispatch('images.before', text, options, globals);
3487
3488 var inlineRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<?([\S]+?(?:\([\S]*?\)[\S]*?)?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
3489 crazyRegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<([^>]*)>(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(?:(["'])([^"]*?)\6))?[ \t]?\)/g,
3490 base64RegExp = /!\[([^\]]*?)][ \t]*()\([ \t]?<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(["'])([^"]*?)\6)?[ \t]?\)/g,
3491 referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[([\s\S]*?)]()()()()()/g,
3492 refShortcutRegExp = /!\[([^\[\]]+)]()()()()()/g;
3493
3494 function writeImageTagBase64 (wholeMatch, altText, linkId, url, width, height, m5, title) {
3495 url = url.replace(/\s/g, '');
3496 return writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title);
3497 }
3498
3499 function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
3500
3501 var gUrls = globals.gUrls,
3502 gTitles = globals.gTitles,
3503 gDims = globals.gDimensions;
3504
3505 linkId = linkId.toLowerCase();
3506
3507 if (!title) {
3508 title = '';
3509 }
3510 // Special case for explicit empty url
3511 if (wholeMatch.search(/\(<?\s*>? ?(['"].*['"])?\)$/m) > -1) {
3512 url = '';
3513
3514 } else if (url === '' || url === null) {
3515 if (linkId === '' || linkId === null) {
3516 // lower-case and turn embedded newlines into spaces
3517 linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
3518 }
3519 url = '#' + linkId;
3520
3521 if (!showdown.helper.isUndefined(gUrls[linkId])) {
3522 url = gUrls[linkId];
3523 if (!showdown.helper.isUndefined(gTitles[linkId])) {
3524 title = gTitles[linkId];
3525 }
3526 if (!showdown.helper.isUndefined(gDims[linkId])) {
3527 width = gDims[linkId].width;
3528 height = gDims[linkId].height;
3529 }
3530 } else {
3531 return wholeMatch;
3532 }
3533 }
3534
3535 altText = altText
3536 .replace(/"/g, '&quot;')
3537 //altText = showdown.helper.escapeCharacters(altText, '*_', false);
3538 .replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
3539 //url = showdown.helper.escapeCharacters(url, '*_', false);
3540 url = url.replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
3541 var result = '<img src="' + url + '" alt="' + altText + '"';
3542
3543 if (title) {
3544 title = title
3545 .replace(/"/g, '&quot;')
3546 //title = showdown.helper.escapeCharacters(title, '*_', false);
3547 .replace(showdown.helper.regexes.asteriskDashAndColon, showdown.helper.escapeCharactersCallback);
3548 result += ' title="' + title + '"';
3549 }
3550
3551 if (width && height) {
3552 width = (width === '*') ? 'auto' : width;
3553 height = (height === '*') ? 'auto' : height;
3554
3555 result += ' width="' + width + '"';
3556 result += ' height="' + height + '"';
3557 }
3558
3559 result += ' />';
3560
3561 return result;
3562 }
3563
3564 // First, handle reference-style labeled images: ![alt text][id]
3565 text = text.replace(referenceRegExp, writeImageTag);
3566
3567 // Next, handle inline images: ![alt text](url =<width>x<height> "optional title")
3568
3569 // base64 encoded images
3570 text = text.replace(base64RegExp, writeImageTagBase64);
3571
3572 // cases with crazy urls like ./image/cat1).png
3573 text = text.replace(crazyRegExp, writeImageTag);
3574
3575 // normal cases
3576 text = text.replace(inlineRegExp, writeImageTag);
3577
3578 // handle reference-style shortcuts: ![img text]
3579 text = text.replace(refShortcutRegExp, writeImageTag);
3580
3581 text = globals.converter._dispatch('images.after', text, options, globals);
3582 return text;
3583});
3584
3585showdown.subParser('italicsAndBold', function (text, options, globals) {
3586 'use strict';
3587
3588 text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
3589
3590 // it's faster to have 3 separate regexes for each case than have just one
3591 // because of backtracing, in some cases, it could lead to an exponential effect
3592 // called "catastrophic backtrace". Ominous!
3593
3594 function parseInside (txt, left, right) {
3595 /*
3596 if (options.simplifiedAutoLink) {
3597 txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);
3598 }
3599 */
3600 return left + txt + right;
3601 }
3602
3603 // Parse underscores
3604 if (options.literalMidWordUnderscores) {
3605 text = text.replace(/\b___(\S[\s\S]*)___\b/g, function (wm, txt) {
3606 return parseInside (txt, '<strong><em>', '</em></strong>');
3607 });
3608 text = text.replace(/\b__(\S[\s\S]*)__\b/g, function (wm, txt) {
3609 return parseInside (txt, '<strong>', '</strong>');
3610 });
3611 text = text.replace(/\b_(\S[\s\S]*?)_\b/g, function (wm, txt) {
3612 return parseInside (txt, '<em>', '</em>');
3613 });
3614 } else {
3615 text = text.replace(/___(\S[\s\S]*?)___/g, function (wm, m) {
3616 return (/\S$/.test(m)) ? parseInside (m, '<strong><em>', '</em></strong>') : wm;
3617 });
3618 text = text.replace(/__(\S[\s\S]*?)__/g, function (wm, m) {
3619 return (/\S$/.test(m)) ? parseInside (m, '<strong>', '</strong>') : wm;
3620 });
3621 text = text.replace(/_([^\s_][\s\S]*?)_/g, function (wm, m) {
3622 // !/^_[^_]/.test(m) - test if it doesn't start with __ (since it seems redundant, we removed it)
3623 return (/\S$/.test(m)) ? parseInside (m, '<em>', '</em>') : wm;
3624 });
3625 }
3626
3627 // Now parse asterisks
3628 if (options.literalMidWordAsterisks) {
3629 text = text.trim().replace(/(^| )\*{3}(\S[\s\S]*?)\*{3}([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
3630 return parseInside (txt, lead + '<strong><em>', '</em></strong>' + trail);
3631 });
3632 text = text.trim().replace(/(^| )\*{2}(\S[\s\S]*?)\*{2}([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
3633 return parseInside (txt, lead + '<strong>', '</strong>' + trail);
3634 });
3635 text = text.trim().replace(/(^| )\*(\S[\s\S]*?)\*([ ,;!?.]|$)/g, function (wm, lead, txt, trail) {
3636 return parseInside (txt, lead + '<em>', '</em>' + trail);
3637 });
3638 } else {
3639 text = text.replace(/\*\*\*(\S[\s\S]*?)\*\*\*/g, function (wm, m) {
3640 return (/\S$/.test(m)) ? parseInside (m, '<strong><em>', '</em></strong>') : wm;
3641 });
3642 text = text.replace(/\*\*(\S[\s\S]*?)\*\*/g, function (wm, m) {
3643 return (/\S$/.test(m)) ? parseInside (m, '<strong>', '</strong>') : wm;
3644 });
3645 text = text.replace(/\*([^\s*][\s\S]*?)\*/g, function (wm, m) {
3646 // !/^\*[^*]/.test(m) - test if it doesn't start with ** (since it seems redundant, we removed it)
3647 return (/\S$/.test(m)) ? parseInside (m, '<em>', '</em>') : wm;
3648 });
3649 }
3650
3651
3652 text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
3653 return text;
3654});
3655
3656/**
3657 * Form HTML ordered (numbered) and unordered (bulleted) lists.
3658 */
3659showdown.subParser('lists', function (text, options, globals) {
3660 'use strict';
3661
3662 /**
3663 * Process the contents of a single ordered or unordered list, splitting it
3664 * into individual list items.
3665 * @param {string} listStr
3666 * @param {boolean} trimTrailing
3667 * @returns {string}
3668 */
3669 function processListItems (listStr, trimTrailing) {
3670 // The $g_list_level global keeps track of when we're inside a list.
3671 // Each time we enter a list, we increment it; when we leave a list,
3672 // we decrement. If it's zero, we're not in a list anymore.
3673 //
3674 // We do this because when we're not inside a list, we want to treat
3675 // something like this:
3676 //
3677 // I recommend upgrading to version
3678 // 8. Oops, now this line is treated
3679 // as a sub-list.
3680 //
3681 // As a single paragraph, despite the fact that the second line starts
3682 // with a digit-period-space sequence.
3683 //
3684 // Whereas when we're inside a list (or sub-list), that line will be
3685 // treated as the start of a sub-list. What a kludge, huh? This is
3686 // an aspect of Markdown's syntax that's hard to parse perfectly
3687 // without resorting to mind-reading. Perhaps the solution is to
3688 // change the syntax rules such that sub-lists must start with a
3689 // starting cardinal number; e.g. "1." or "a.".
3690 globals.gListLevel++;
3691
3692 // trim trailing blank lines:
3693 listStr = listStr.replace(/\n{2,}$/, '\n');
3694
3695 // attacklab: add sentinel to emulate \z
3696 listStr += '¨0';
3697
3698 var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
3699 isParagraphed = (/\n[ \t]*\n(?!¨0)/.test(listStr));
3700
3701 // Since version 1.5, nesting sublists requires 4 spaces (or 1 tab) indentation,
3702 // which is a syntax breaking change
3703 // activating this option reverts to old behavior
3704 if (options.disableForced4SpacesIndentedSublists) {
3705 rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(¨0|\2([*+-]|\d+[.])[ \t]+))/gm;
3706 }
3707
3708 listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
3709 checked = (checked && checked.trim() !== '');
3710
3711 var item = showdown.subParser('outdent')(m4, options, globals),
3712 bulletStyle = '';
3713
3714 // Support for github tasklists
3715 if (taskbtn && options.tasklists) {
3716 bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
3717 item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
3718 var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
3719 if (checked) {
3720 otp += ' checked';
3721 }
3722 otp += '>';
3723 return otp;
3724 });
3725 }
3726
3727 // ISSUE #312
3728 // This input: - - - a
3729 // causes trouble to the parser, since it interprets it as:
3730 // <ul><li><li><li>a</li></li></li></ul>
3731 // instead of:
3732 // <ul><li>- - a</li></ul>
3733 // So, to prevent it, we will put a marker (¨A)in the beginning of the line
3734 // Kind of hackish/monkey patching, but seems more effective than overcomplicating the list parser
3735 item = item.replace(/^([-*+]|\d\.)[ \t]+[\S\n ]*/g, function (wm2) {
3736 return '¨A' + wm2;
3737 });
3738
3739 // m1 - Leading line or
3740 // Has a double return (multi paragraph) or
3741 // Has sublist
3742 if (m1 || (item.search(/\n{2,}/) > -1)) {
3743 item = showdown.subParser('githubCodeBlocks')(item, options, globals);
3744 item = showdown.subParser('blockGamut')(item, options, globals);
3745 } else {
3746 // Recursion for sub-lists:
3747 item = showdown.subParser('lists')(item, options, globals);
3748 item = item.replace(/\n$/, ''); // chomp(item)
3749 item = showdown.subParser('hashHTMLBlocks')(item, options, globals);
3750
3751 // Colapse double linebreaks
3752 item = item.replace(/\n\n+/g, '\n\n');
3753 if (isParagraphed) {
3754 item = showdown.subParser('paragraphs')(item, options, globals);
3755 } else {
3756 item = showdown.subParser('spanGamut')(item, options, globals);
3757 }
3758 }
3759
3760 // now we need to remove the marker (¨A)
3761 item = item.replace('¨A', '');
3762 // we can finally wrap the line in list item tags
3763 item = '<li' + bulletStyle + '>' + item + '</li>\n';
3764
3765 return item;
3766 });
3767
3768 // attacklab: strip sentinel
3769 listStr = listStr.replace(/¨0/g, '');
3770
3771 globals.gListLevel--;
3772
3773 if (trimTrailing) {
3774 listStr = listStr.replace(/\s+$/, '');
3775 }
3776
3777 return listStr;
3778 }
3779
3780 function styleStartNumber (list, listType) {
3781 // check if ol and starts by a number different than 1
3782 if (listType === 'ol') {
3783 var res = list.match(/^ *(\d+)\./);
3784 if (res && res[1] !== '1') {
3785 return ' start="' + res[1] + '"';
3786 }
3787 }
3788 return '';
3789 }
3790
3791 /**
3792 * Check and parse consecutive lists (better fix for issue #142)
3793 * @param {string} list
3794 * @param {string} listType
3795 * @param {boolean} trimTrailing
3796 * @returns {string}
3797 */
3798 function parseConsecutiveLists (list, listType, trimTrailing) {
3799 // check if we caught 2 or more consecutive lists by mistake
3800 // we use the counterRgx, meaning if listType is UL we look for OL and vice versa
3801 var olRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?\d+\.[ \t]/gm : /^ {0,3}\d+\.[ \t]/gm,
3802 ulRgx = (options.disableForced4SpacesIndentedSublists) ? /^ ?[*+-][ \t]/gm : /^ {0,3}[*+-][ \t]/gm,
3803 counterRxg = (listType === 'ul') ? olRgx : ulRgx,
3804 result = '';
3805
3806 if (list.search(counterRxg) !== -1) {
3807 (function parseCL (txt) {
3808 var pos = txt.search(counterRxg),
3809 style = styleStartNumber(list, listType);
3810 if (pos !== -1) {
3811 // slice
3812 result += '\n<' + listType + style + '>\n' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n';
3813
3814 // invert counterType and listType
3815 listType = (listType === 'ul') ? 'ol' : 'ul';
3816 counterRxg = (listType === 'ul') ? olRgx : ulRgx;
3817
3818 //recurse
3819 parseCL(txt.slice(pos));
3820 } else {
3821 result += '\n<' + listType + style + '>\n' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n';
3822 }
3823 })(list);
3824 } else {
3825 var style = styleStartNumber(list, listType);
3826 result = '\n<' + listType + style + '>\n' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n';
3827 }
3828
3829 return result;
3830 }
3831
3832 /** Start of list parsing **/
3833 text = globals.converter._dispatch('lists.before', text, options, globals);
3834 // add sentinel to hack around khtml/safari bug:
3835 // http://bugs.webkit.org/show_bug.cgi?id=11231
3836 text += '¨0';
3837
3838 if (globals.gListLevel) {
3839 text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
3840 function (wholeMatch, list, m2) {
3841 var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
3842 return parseConsecutiveLists(list, listType, true);
3843 }
3844 );
3845 } else {
3846 text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(¨0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
3847 function (wholeMatch, m1, list, m3) {
3848 var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
3849 return parseConsecutiveLists(list, listType, false);
3850 }
3851 );
3852 }
3853
3854 // strip sentinel
3855 text = text.replace(/¨0/, '');
3856 text = globals.converter._dispatch('lists.after', text, options, globals);
3857 return text;
3858});
3859
3860/**
3861 * Remove one level of line-leading tabs or spaces
3862 */
3863showdown.subParser('outdent', function (text, options, globals) {
3864 'use strict';
3865 text = globals.converter._dispatch('outdent.before', text, options, globals);
3866
3867 // attacklab: hack around Konqueror 3.5.4 bug:
3868 // "----------bug".replace(/^-/g,"") == "bug"
3869 text = text.replace(/^(\t|[ ]{1,4})/gm, '¨0'); // attacklab: g_tab_width
3870
3871 // attacklab: clean up hack
3872 text = text.replace(/¨0/g, '');
3873
3874 text = globals.converter._dispatch('outdent.after', text, options, globals);
3875 return text;
3876});
3877
3878/**
3879 *
3880 */
3881showdown.subParser('paragraphs', function (text, options, globals) {
3882 'use strict';
3883
3884 text = globals.converter._dispatch('paragraphs.before', text, options, globals);
3885 // Strip leading and trailing lines:
3886 text = text.replace(/^\n+/g, '');
3887 text = text.replace(/\n+$/g, '');
3888
3889 var grafs = text.split(/\n{2,}/g),
3890 grafsOut = [],
3891 end = grafs.length; // Wrap <p> tags
3892
3893 for (var i = 0; i < end; i++) {
3894 var str = grafs[i];
3895 // if this is an HTML marker, copy it
3896 if (str.search(/¨(K|G)(\d+)\1/g) >= 0) {
3897 grafsOut.push(str);
3898
3899 // test for presence of characters to prevent empty lines being parsed
3900 // as paragraphs (resulting in undesired extra empty paragraphs)
3901 } else if (str.search(/\S/) >= 0) {
3902 str = showdown.subParser('spanGamut')(str, options, globals);
3903 str = str.replace(/^([ \t]*)/g, '<p>');
3904 str += '</p>';
3905 grafsOut.push(str);
3906 }
3907 }
3908
3909 /** Unhashify HTML blocks */
3910 end = grafsOut.length;
3911 for (i = 0; i < end; i++) {
3912 var blockText = '',
3913 grafsOutIt = grafsOut[i],
3914 codeFlag = false;
3915 // if this is a marker for an html block...
3916 // use RegExp.test instead of string.search because of QML bug
3917 while (/¨(K|G)(\d+)\1/.test(grafsOutIt)) {
3918 var delim = RegExp.$1,
3919 num = RegExp.$2;
3920
3921 if (delim === 'K') {
3922 blockText = globals.gHtmlBlocks[num];
3923 } else {
3924 // we need to check if ghBlock is a false positive
3925 if (codeFlag) {
3926 // use encoded version of all text
3927 blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text, options, globals);
3928 } else {
3929 blockText = globals.ghCodeBlocks[num].codeblock;
3930 }
3931 }
3932 blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
3933
3934 grafsOutIt = grafsOutIt.replace(/(\n\n)?¨(K|G)\d+\2(\n\n)?/, blockText);
3935 // Check if grafsOutIt is a pre->code
3936 if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
3937 codeFlag = true;
3938 }
3939 }
3940 grafsOut[i] = grafsOutIt;
3941 }
3942 text = grafsOut.join('\n');
3943 // Strip leading and trailing lines:
3944 text = text.replace(/^\n+/g, '');
3945 text = text.replace(/\n+$/g, '');
3946 return globals.converter._dispatch('paragraphs.after', text, options, globals);
3947});
3948
3949/**
3950 * Run extension
3951 */
3952showdown.subParser('runExtension', function (ext, text, options, globals) {
3953 'use strict';
3954
3955 if (ext.filter) {
3956 text = ext.filter(text, globals.converter, options);
3957
3958 } else if (ext.regex) {
3959 // TODO remove this when old extension loading mechanism is deprecated
3960 var re = ext.regex;
3961 if (!(re instanceof RegExp)) {
3962 re = new RegExp(re, 'g');
3963 }
3964 text = text.replace(re, ext.replace);
3965 }
3966
3967 return text;
3968});
3969
3970/**
3971 * These are all the transformations that occur *within* block-level
3972 * tags like paragraphs, headers, and list items.
3973 */
3974showdown.subParser('spanGamut', function (text, options, globals) {
3975 'use strict';
3976
3977 text = globals.converter._dispatch('spanGamut.before', text, options, globals);
3978 text = showdown.subParser('codeSpans')(text, options, globals);
3979 text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
3980 text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
3981
3982 // Process anchor and image tags. Images must come first,
3983 // because ![foo][f] looks like an anchor.
3984 text = showdown.subParser('images')(text, options, globals);
3985 text = showdown.subParser('anchors')(text, options, globals);
3986
3987 // Make links out of things like `<http://example.com/>`
3988 // Must come after anchors, because you can use < and >
3989 // delimiters in inline links like [this](<url>).
3990 text = showdown.subParser('autoLinks')(text, options, globals);
3991 text = showdown.subParser('simplifiedAutoLinks')(text, options, globals);
3992 text = showdown.subParser('emoji')(text, options, globals);
3993 text = showdown.subParser('underline')(text, options, globals);
3994 text = showdown.subParser('italicsAndBold')(text, options, globals);
3995 text = showdown.subParser('strikethrough')(text, options, globals);
3996 text = showdown.subParser('ellipsis')(text, options, globals);
3997
3998 // we need to hash HTML tags inside spans
3999 text = showdown.subParser('hashHTMLSpans')(text, options, globals);
4000
4001 // now we encode amps and angles
4002 text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
4003
4004 // Do hard breaks
4005 if (options.simpleLineBreaks) {
4006 // GFM style hard breaks
4007 // only add line breaks if the text does not contain a block (special case for lists)
4008 if (!/\n\n¨K/.test(text)) {
4009 text = text.replace(/\n+/g, '<br />\n');
4010 }
4011 } else {
4012 // Vanilla hard breaks
4013 text = text.replace(/ +\n/g, '<br />\n');
4014 }
4015
4016 text = globals.converter._dispatch('spanGamut.after', text, options, globals);
4017 return text;
4018});
4019
4020showdown.subParser('strikethrough', function (text, options, globals) {
4021 'use strict';
4022
4023 function parseInside (txt) {
4024 if (options.simplifiedAutoLink) {
4025 txt = showdown.subParser('simplifiedAutoLinks')(txt, options, globals);
4026 }
4027 return '<del>' + txt + '</del>';
4028 }
4029
4030 if (options.strikethrough) {
4031 text = globals.converter._dispatch('strikethrough.before', text, options, globals);
4032 text = text.replace(/(?:~){2}([\s\S]+?)(?:~){2}/g, function (wm, txt) { return parseInside(txt); });
4033 text = globals.converter._dispatch('strikethrough.after', text, options, globals);
4034 }
4035
4036 return text;
4037});
4038
4039/**
4040 * Strips link definitions from text, stores the URLs and titles in
4041 * hash references.
4042 * Link defs are in the form: ^[id]: url "optional title"
4043 */
4044showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
4045 'use strict';
4046
4047 var regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?([^>\s]+)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n+|(?=¨0))/gm,
4048 base64Regex = /^ {0,3}\[(.+)]:[ \t]*\n?[ \t]*<?(data:.+?\/.+?;base64,[A-Za-z0-9+/=\n]+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*\n?[ \t]*(?:(\n*)["|'(](.+?)["|')][ \t]*)?(?:\n\n|(?=¨0)|(?=\n\[))/gm;
4049
4050 // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
4051 text += '¨0';
4052
4053 var replaceFunc = function (wholeMatch, linkId, url, width, height, blankLines, title) {
4054 linkId = linkId.toLowerCase();
4055 if (url.match(/^data:.+?\/.+?;base64,/)) {
4056 // remove newlines
4057 globals.gUrls[linkId] = url.replace(/\s/g, '');
4058 } else {
4059 globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url, options, globals); // Link IDs are case-insensitive
4060 }
4061
4062 if (blankLines) {
4063 // Oops, found blank lines, so it's not a title.
4064 // Put back the parenthetical statement we stole.
4065 return blankLines + title;
4066
4067 } else {
4068 if (title) {
4069 globals.gTitles[linkId] = title.replace(/"|'/g, '&quot;');
4070 }
4071 if (options.parseImgDimensions && width && height) {
4072 globals.gDimensions[linkId] = {
4073 width: width,
4074 height: height
4075 };
4076 }
4077 }
4078 // Completely remove the definition from the text
4079 return '';
4080 };
4081
4082 // first we try to find base64 link references
4083 text = text.replace(base64Regex, replaceFunc);
4084
4085 text = text.replace(regex, replaceFunc);
4086
4087 // attacklab: strip sentinel
4088 text = text.replace(/¨0/, '');
4089
4090 return text;
4091});
4092
4093showdown.subParser('tables', function (text, options, globals) {
4094 'use strict';
4095
4096 if (!options.tables) {
4097 return text;
4098 }
4099
4100 var tableRgx = /^ {0,3}\|?.+\|.+\n {0,3}\|?[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:[-=]){2,}[\s\S]+?(?:\n\n|<ol|<ul|¨0)/gm,
4101 //singeColTblRgx = /^ {0,3}\|.+\|\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n(?: {0,3}\|.+\|\n)+(?:\n\n|¨0)/gm;
4102 singeColTblRgx = /^ {0,3}\|.+\|[ \t]*\n {0,3}\|[ \t]*:?[ \t]*(?:[-=]){2,}[ \t]*:?[ \t]*\|[ \t]*\n( {0,3}\|.+\|[ \t]*\n)*(?:\n|<ol|<ul|¨0)/gm;
4103
4104 function parseStyles (sLine) {
4105 if (/^:[ \t]*--*$/.test(sLine)) {
4106 return ' style="text-align:left;"';
4107 } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
4108 return ' style="text-align:right;"';
4109 } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
4110 return ' style="text-align:center;"';
4111 } else {
4112 return '';
4113 }
4114 }
4115
4116 function parseHeaders (header, style) {
4117 var id = '';
4118 header = header.trim();
4119 // support both tablesHeaderId and tableHeaderId due to error in documention so we don't break backwards compatibility
4120 if (options.tablesHeaderId || options.tableHeaderId) {
4121 id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
4122 }
4123 header = showdown.subParser('spanGamut')(header, options, globals);
4124
4125 return '<th' + id + style + '>' + header + '</th>\n';
4126 }
4127
4128 function parseCells (cell, style) {
4129 var subText = showdown.subParser('spanGamut')(cell, options, globals);
4130 return '<td' + style + '>' + subText + '</td>\n';
4131 }
4132
4133 function buildTable (headers, cells) {
4134 var tb = '<table>\n<thead>\n<tr>\n',
4135 tblLgn = headers.length;
4136
4137 for (var i = 0; i < tblLgn; ++i) {
4138 tb += headers[i];
4139 }
4140 tb += '</tr>\n</thead>\n<tbody>\n';
4141
4142 for (i = 0; i < cells.length; ++i) {
4143 tb += '<tr>\n';
4144 for (var ii = 0; ii < tblLgn; ++ii) {
4145 tb += cells[i][ii];
4146 }
4147 tb += '</tr>\n';
4148 }
4149 tb += '</tbody>\n</table>\n';
4150 return tb;
4151 }
4152
4153 function parseTable (rawTable) {
4154 var i, tableLines = rawTable.split('\n');
4155
4156 // strip wrong first and last column if wrapped tables are used
4157 for (i = 0; i < tableLines.length; ++i) {
4158 if (/^ {0,3}\|/.test(tableLines[i])) {
4159 tableLines[i] = tableLines[i].replace(/^ {0,3}\|/, '');
4160 }
4161 if (/\|[ \t]*$/.test(tableLines[i])) {
4162 tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
4163 }
4164 }
4165
4166 var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
4167 rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
4168 rawCells = [],
4169 headers = [],
4170 styles = [],
4171 cells = [];
4172
4173 tableLines.shift();
4174 tableLines.shift();
4175
4176 for (i = 0; i < tableLines.length; ++i) {
4177 if (tableLines[i].trim() === '') {
4178 continue;
4179 }
4180 rawCells.push(
4181 tableLines[i]
4182 .split('|')
4183 .map(function (s) {
4184 return s.trim();
4185 })
4186 );
4187 }
4188
4189 if (rawHeaders.length < rawStyles.length) {
4190 return rawTable;
4191 }
4192
4193 for (i = 0; i < rawStyles.length; ++i) {
4194 styles.push(parseStyles(rawStyles[i]));
4195 }
4196
4197 for (i = 0; i < rawHeaders.length; ++i) {
4198 if (showdown.helper.isUndefined(styles[i])) {
4199 styles[i] = '';
4200 }
4201 headers.push(parseHeaders(rawHeaders[i], styles[i]));
4202 }
4203
4204 for (i = 0; i < rawCells.length; ++i) {
4205 var row = [];
4206 for (var ii = 0; ii < headers.length; ++ii) {
4207 if (showdown.helper.isUndefined(rawCells[i][ii])) {
4208
4209 }
4210 row.push(parseCells(rawCells[i][ii], styles[ii]));
4211 }
4212 cells.push(row);
4213 }
4214
4215 return buildTable(headers, cells);
4216 }
4217
4218 function hackFixTableFollowedByList (rawTable) {
4219 var lastChars = rawTable.slice(-3);
4220 if (lastChars === '<ol' || lastChars === '<ul') {
4221 rawTable = rawTable.slice(0, -3) + '\n\n' + rawTable.slice(-3);
4222 }
4223 return rawTable;
4224 }
4225
4226 text = globals.converter._dispatch('tables.before', text, options, globals);
4227
4228 // find escaped pipe characters
4229 text = text.replace(/\\(\|)/g, showdown.helper.escapeCharactersCallback);
4230
4231 // hackfix issue #443. Due to lists only having a linebreak before them, we need to manually insert a linebreak to prevent
4232 // tables not being parsed when followed by a list
4233 text = text.replace(tableRgx, hackFixTableFollowedByList);
4234 text = text.replace(singeColTblRgx, hackFixTableFollowedByList);
4235
4236 // parse multi column tables
4237 text = text.replace(tableRgx, parseTable);
4238
4239 // parse one column tables
4240 text = text.replace(singeColTblRgx, parseTable);
4241
4242 text = globals.converter._dispatch('tables.after', text, options, globals);
4243
4244 return text;
4245});
4246
4247showdown.subParser('underline', function (text, options, globals) {
4248 'use strict';
4249
4250 if (!options.underline) {
4251 return text;
4252 }
4253
4254 text = globals.converter._dispatch('underline.before', text, options, globals);
4255
4256 if (options.literalMidWordUnderscores) {
4257 text = text.replace(/\b_?__(\S[\s\S]*)___?\b/g, function (wm, txt) {
4258 return '<u>' + txt + '</u>';
4259 });
4260 } else {
4261 text = text.replace(/_?__(\S[\s\S]*?)___?/g, function (wm, m) {
4262 return (/\S$/.test(m)) ? '<u>' + m + '</u>' : wm;
4263 });
4264 }
4265
4266 // escape remaining underscores to prevent them being parsed by italic and bold
4267 text = text.replace(/(_)/g, showdown.helper.escapeCharactersCallback);
4268
4269 text = globals.converter._dispatch('underline.after', text, options, globals);
4270
4271 return text;
4272});
4273
4274/**
4275 * Swap back in all the special characters we've hidden.
4276 */
4277showdown.subParser('unescapeSpecialChars', function (text, options, globals) {
4278 'use strict';
4279 text = globals.converter._dispatch('unescapeSpecialChars.before', text, options, globals);
4280
4281 text = text.replace(/¨E(\d+)E/g, function (wholeMatch, m1) {
4282 var charCodeToReplace = parseInt(m1);
4283 return String.fromCharCode(charCodeToReplace);
4284 });
4285
4286 text = globals.converter._dispatch('unescapeSpecialChars.after', text, options, globals);
4287 return text;
4288});
4289
4290var root = this;
4291
4292// AMD Loader
4293if (typeof define === 'function' && define.amd) {
4294 define(function () {
4295 'use strict';
4296 return showdown;
4297 });
4298
4299// CommonJS/nodeJS Loader
4300} else if (typeof module !== 'undefined' && module.exports) {
4301 module.exports = showdown;
4302
4303// Regular Browser loader
4304} else {
4305 root.showdown = showdown;
4306}
4307}).call(this);
4308
4309//# sourceMappingURL=showdown.js.map