GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

third-party/showdownjs/1.9.1/showdown.js   F
last analyzed

Complexity

Total Complexity 530
Complexity/F 2.64

Size

Lines of Code 5141
Function Count 201

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3195
dl 0
loc 5141
rs 0.8
c 0
b 0
f 0
wmc 530
mnd 329
bc 329
fnc 201
bpm 1.6368
cpm 2.6368
noi 10

27 Functions

Rating   Name   Duplication   Size   Complexity  
A showdown.js ➔ listen 0 14 4
C showdown.js ➔ getDefaultOpts 0 176 5
A showdown.js ➔ dispatch 0 11 4
D showdown.js ➔ _constructor 0 25 12
B showdown.js ➔ substitutePreCodeTags 0 36 6
C showdown.js ➔ parseConsecutiveLists 0 33 9
F showdown.js ➔ parseInside 0 8 23
A showdown.js ➔ rTrimInputText 0 5 1
A showdown.js ➔ parseCells 0 4 1
D showdown.js ➔ writeImageTag 0 64 12
A showdown.js ➔ writeImageTagBase64 0 4 3
F showdown.js ➔ headerId 0 65 32
F showdown.js ➔ hashHTMLSpan 0 3 105
A showdown.js ➔ styleStartNumber 0 10 3
F showdown.js ➔ processListItems 0 110 31
A showdown.js ➔ parseHeaders 0 11 2
F showdown.js ➔ clean 0 16 15
B showdown.js ➔ legacyExtensionLoading 0 26 6
C showdown.js ➔ parseMetadataContents 0 18 9
F showdown.js ➔ parseTable 0 66 16
F showdown.js ➔ validate 0 101 49
F showdown.js ➔ parseStyles 0 11 14
F showdown.js ➔ escapeCharactersCallback 0 5 19
F showdown.js ➔ padEnd 0 17 38
D showdown.js ➔ _parseExtension 0 58 12
A showdown.js ➔ allOptionsOn 0 11 3
A showdown.js ➔ buildTable 0 19 4

How to fix   Complexity   

Complexity

Complex classes like third-party/showdownjs/1.9.1/showdown.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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