| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532 | 
							- /**
 
-  * 
 
-  * showdown: https://github.com/showdownjs/showdown
 
-  * 
 
-  * author: Di (微信小程序开发工程师)
 
-  * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com)
 
-  *               垂直微信小程序开发交流社区
 
-  * 
 
-  * github地址: https://github.com/icindy/wxParse
 
-  * 
 
-  * for: 微信小程序富文本解析
 
-  * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184
 
-  */
 
- function getDefaultOpts(simple) {
 
-   'use strict';
 
-   var defaultOptions = {
 
-     omitExtraWLInCodeBlocks: {
 
-       defaultValue: false,
 
-       describe: 'Omit the default extra whiteline added to code blocks',
 
-       type: 'boolean'
 
-     },
 
-     noHeaderId: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off generated header id',
 
-       type: 'boolean'
 
-     },
 
-     prefixHeaderId: {
 
-       defaultValue: false,
 
-       describe: 'Specify a prefix to generated header ids',
 
-       type: 'string'
 
-     },
 
-     headerLevelStart: {
 
-       defaultValue: false,
 
-       describe: 'The header blocks level start',
 
-       type: 'integer'
 
-     },
 
-     parseImgDimensions: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off image dimension parsing',
 
-       type: 'boolean'
 
-     },
 
-     simplifiedAutoLink: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off GFM autolink style',
 
-       type: 'boolean'
 
-     },
 
-     literalMidWordUnderscores: {
 
-       defaultValue: false,
 
-       describe: 'Parse midword underscores as literal underscores',
 
-       type: 'boolean'
 
-     },
 
-     strikethrough: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off strikethrough support',
 
-       type: 'boolean'
 
-     },
 
-     tables: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off tables support',
 
-       type: 'boolean'
 
-     },
 
-     tablesHeaderId: {
 
-       defaultValue: false,
 
-       describe: 'Add an id to table headers',
 
-       type: 'boolean'
 
-     },
 
-     ghCodeBlocks: {
 
-       defaultValue: true,
 
-       describe: 'Turn on/off GFM fenced code blocks support',
 
-       type: 'boolean'
 
-     },
 
-     tasklists: {
 
-       defaultValue: false,
 
-       describe: 'Turn on/off GFM tasklist support',
 
-       type: 'boolean'
 
-     },
 
-     smoothLivePreview: {
 
-       defaultValue: false,
 
-       describe: 'Prevents weird effects in live previews due to incomplete input',
 
-       type: 'boolean'
 
-     },
 
-     smartIndentationFix: {
 
-       defaultValue: false,
 
-       description: 'Tries to smartly fix identation in es6 strings',
 
-       type: 'boolean'
 
-     }
 
-   };
 
-   if (simple === false) {
 
-     return JSON.parse(JSON.stringify(defaultOptions));
 
-   }
 
-   var ret = {};
 
-   for (var opt in defaultOptions) {
 
-     if (defaultOptions.hasOwnProperty(opt)) {
 
-       ret[opt] = defaultOptions[opt].defaultValue;
 
-     }
 
-   }
 
-   return ret;
 
- }
 
- /**
 
-  * Created by Tivie on 06-01-2015.
 
-  */
 
- // Private properties
 
- var showdown = {},
 
-     parsers = {},
 
-     extensions = {},
 
-     globalOptions = getDefaultOpts(true),
 
-     flavor = {
 
-       github: {
 
-         omitExtraWLInCodeBlocks:   true,
 
-         prefixHeaderId:            'user-content-',
 
-         simplifiedAutoLink:        true,
 
-         literalMidWordUnderscores: true,
 
-         strikethrough:             true,
 
-         tables:                    true,
 
-         tablesHeaderId:            true,
 
-         ghCodeBlocks:              true,
 
-         tasklists:                 true
 
-       },
 
-       vanilla: getDefaultOpts(true)
 
-     };
 
- /**
 
-  * helper namespace
 
-  * @type {{}}
 
-  */
 
- showdown.helper = {};
 
- /**
 
-  * TODO LEGACY SUPPORT CODE
 
-  * @type {{}}
 
-  */
 
- showdown.extensions = {};
 
- /**
 
-  * Set a global option
 
-  * @static
 
-  * @param {string} key
 
-  * @param {*} value
 
-  * @returns {showdown}
 
-  */
 
- showdown.setOption = function (key, value) {
 
-   'use strict';
 
-   globalOptions[key] = value;
 
-   return this;
 
- };
 
- /**
 
-  * Get a global option
 
-  * @static
 
-  * @param {string} key
 
-  * @returns {*}
 
-  */
 
- showdown.getOption = function (key) {
 
-   'use strict';
 
-   return globalOptions[key];
 
- };
 
- /**
 
-  * Get the global options
 
-  * @static
 
-  * @returns {{}}
 
-  */
 
- showdown.getOptions = function () {
 
-   'use strict';
 
-   return globalOptions;
 
- };
 
- /**
 
-  * Reset global options to the default values
 
-  * @static
 
-  */
 
- showdown.resetOptions = function () {
 
-   'use strict';
 
-   globalOptions = getDefaultOpts(true);
 
- };
 
- /**
 
-  * Set the flavor showdown should use as default
 
-  * @param {string} name
 
-  */
 
- showdown.setFlavor = function (name) {
 
-   'use strict';
 
-   if (flavor.hasOwnProperty(name)) {
 
-     var preset = flavor[name];
 
-     for (var option in preset) {
 
-       if (preset.hasOwnProperty(option)) {
 
-         globalOptions[option] = preset[option];
 
-       }
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Get the default options
 
-  * @static
 
-  * @param {boolean} [simple=true]
 
-  * @returns {{}}
 
-  */
 
- showdown.getDefaultOptions = function (simple) {
 
-   'use strict';
 
-   return getDefaultOpts(simple);
 
- };
 
- /**
 
-  * Get or set a subParser
 
-  *
 
-  * subParser(name)       - Get a registered subParser
 
-  * subParser(name, func) - Register a subParser
 
-  * @static
 
-  * @param {string} name
 
-  * @param {function} [func]
 
-  * @returns {*}
 
-  */
 
- showdown.subParser = function (name, func) {
 
-   'use strict';
 
-   if (showdown.helper.isString(name)) {
 
-     if (typeof func !== 'undefined') {
 
-       parsers[name] = func;
 
-     } else {
 
-       if (parsers.hasOwnProperty(name)) {
 
-         return parsers[name];
 
-       } else {
 
-         throw Error('SubParser named ' + name + ' not registered!');
 
-       }
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Gets or registers an extension
 
-  * @static
 
-  * @param {string} name
 
-  * @param {object|function=} ext
 
-  * @returns {*}
 
-  */
 
- showdown.extension = function (name, ext) {
 
-   'use strict';
 
-   if (!showdown.helper.isString(name)) {
 
-     throw Error('Extension \'name\' must be a string');
 
-   }
 
-   name = showdown.helper.stdExtName(name);
 
-   // Getter
 
-   if (showdown.helper.isUndefined(ext)) {
 
-     if (!extensions.hasOwnProperty(name)) {
 
-       throw Error('Extension named ' + name + ' is not registered!');
 
-     }
 
-     return extensions[name];
 
-     // Setter
 
-   } else {
 
-     // Expand extension if it's wrapped in a function
 
-     if (typeof ext === 'function') {
 
-       ext = ext();
 
-     }
 
-     // Ensure extension is an array
 
-     if (!showdown.helper.isArray(ext)) {
 
-       ext = [ext];
 
-     }
 
-     var validExtension = validate(ext, name);
 
-     if (validExtension.valid) {
 
-       extensions[name] = ext;
 
-     } else {
 
-       throw Error(validExtension.error);
 
-     }
 
-   }
 
- };
 
- /**
 
-  * Gets all extensions registered
 
-  * @returns {{}}
 
-  */
 
- showdown.getAllExtensions = function () {
 
-   'use strict';
 
-   return extensions;
 
- };
 
- /**
 
-  * Remove an extension
 
-  * @param {string} name
 
-  */
 
- showdown.removeExtension = function (name) {
 
-   'use strict';
 
-   delete extensions[name];
 
- };
 
- /**
 
-  * Removes all extensions
 
-  */
 
- showdown.resetExtensions = function () {
 
-   'use strict';
 
-   extensions = {};
 
- };
 
- /**
 
-  * Validate extension
 
-  * @param {array} extension
 
-  * @param {string} name
 
-  * @returns {{valid: boolean, error: string}}
 
-  */
 
- function validate(extension, name) {
 
-   'use strict';
 
-   var errMsg = (name) ? 'Error in ' + name + ' extension->' : 'Error in unnamed extension',
 
-     ret = {
 
-       valid: true,
 
-       error: ''
 
-     };
 
-   if (!showdown.helper.isArray(extension)) {
 
-     extension = [extension];
 
-   }
 
-   for (var i = 0; i < extension.length; ++i) {
 
-     var baseMsg = errMsg + ' sub-extension ' + i + ': ',
 
-         ext = extension[i];
 
-     if (typeof ext !== 'object') {
 
-       ret.valid = false;
 
-       ret.error = baseMsg + 'must be an object, but ' + typeof ext + ' given';
 
-       return ret;
 
-     }
 
-     if (!showdown.helper.isString(ext.type)) {
 
-       ret.valid = false;
 
-       ret.error = baseMsg + 'property "type" must be a string, but ' + typeof ext.type + ' given';
 
-       return ret;
 
-     }
 
-     var type = ext.type = ext.type.toLowerCase();
 
-     // normalize extension type
 
-     if (type === 'language') {
 
-       type = ext.type = 'lang';
 
-     }
 
-     if (type === 'html') {
 
-       type = ext.type = 'output';
 
-     }
 
-     if (type !== 'lang' && type !== 'output' && type !== 'listener') {
 
-       ret.valid = false;
 
-       ret.error = baseMsg + 'type ' + type + ' is not recognized. Valid values: "lang/language", "output/html" or "listener"';
 
-       return ret;
 
-     }
 
-     if (type === 'listener') {
 
-       if (showdown.helper.isUndefined(ext.listeners)) {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + '. Extensions of type "listener" must have a property called "listeners"';
 
-         return ret;
 
-       }
 
-     } else {
 
-       if (showdown.helper.isUndefined(ext.filter) && showdown.helper.isUndefined(ext.regex)) {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + type + ' extensions must define either a "regex" property or a "filter" method';
 
-         return ret;
 
-       }
 
-     }
 
-     if (ext.listeners) {
 
-       if (typeof ext.listeners !== 'object') {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + '"listeners" property must be an object but ' + typeof ext.listeners + ' given';
 
-         return ret;
 
-       }
 
-       for (var ln in ext.listeners) {
 
-         if (ext.listeners.hasOwnProperty(ln)) {
 
-           if (typeof ext.listeners[ln] !== 'function') {
 
-             ret.valid = false;
 
-             ret.error = baseMsg + '"listeners" property must be an hash of [event name]: [callback]. listeners.' + ln +
 
-               ' must be a function but ' + typeof ext.listeners[ln] + ' given';
 
-             return ret;
 
-           }
 
-         }
 
-       }
 
-     }
 
-     if (ext.filter) {
 
-       if (typeof ext.filter !== 'function') {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + '"filter" must be a function, but ' + typeof ext.filter + ' given';
 
-         return ret;
 
-       }
 
-     } else if (ext.regex) {
 
-       if (showdown.helper.isString(ext.regex)) {
 
-         ext.regex = new RegExp(ext.regex, 'g');
 
-       }
 
-       if (!ext.regex instanceof RegExp) {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + '"regex" property must either be a string or a RegExp object, but ' + typeof ext.regex + ' given';
 
-         return ret;
 
-       }
 
-       if (showdown.helper.isUndefined(ext.replace)) {
 
-         ret.valid = false;
 
-         ret.error = baseMsg + '"regex" extensions must implement a replace string or function';
 
-         return ret;
 
-       }
 
-     }
 
-   }
 
-   return ret;
 
- }
 
- /**
 
-  * Validate extension
 
-  * @param {object} ext
 
-  * @returns {boolean}
 
-  */
 
- showdown.validateExtension = function (ext) {
 
-   'use strict';
 
-   var validateExtension = validate(ext, null);
 
-   if (!validateExtension.valid) {
 
-     console.warn(validateExtension.error);
 
-     return false;
 
-   }
 
-   return true;
 
- };
 
- /**
 
-  * showdownjs helper functions
 
-  */
 
- if (!showdown.hasOwnProperty('helper')) {
 
-   showdown.helper = {};
 
- }
 
- /**
 
-  * Check if var is string
 
-  * @static
 
-  * @param {string} a
 
-  * @returns {boolean}
 
-  */
 
- showdown.helper.isString = function isString(a) {
 
-   'use strict';
 
-   return (typeof a === 'string' || a instanceof String);
 
- };
 
- /**
 
-  * Check if var is a function
 
-  * @static
 
-  * @param {string} a
 
-  * @returns {boolean}
 
-  */
 
- showdown.helper.isFunction = function isFunction(a) {
 
-   'use strict';
 
-   var getType = {};
 
-   return a && getType.toString.call(a) === '[object Function]';
 
- };
 
- /**
 
-  * ForEach helper function
 
-  * @static
 
-  * @param {*} obj
 
-  * @param {function} callback
 
-  */
 
- showdown.helper.forEach = function forEach(obj, callback) {
 
-   'use strict';
 
-   if (typeof obj.forEach === 'function') {
 
-     obj.forEach(callback);
 
-   } else {
 
-     for (var i = 0; i < obj.length; i++) {
 
-       callback(obj[i], i, obj);
 
-     }
 
-   }
 
- };
 
- /**
 
-  * isArray helper function
 
-  * @static
 
-  * @param {*} a
 
-  * @returns {boolean}
 
-  */
 
- showdown.helper.isArray = function isArray(a) {
 
-   'use strict';
 
-   return a.constructor === Array;
 
- };
 
- /**
 
-  * Check if value is undefined
 
-  * @static
 
-  * @param {*} value The value to check.
 
-  * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
 
-  */
 
- showdown.helper.isUndefined = function isUndefined(value) {
 
-   'use strict';
 
-   return typeof value === 'undefined';
 
- };
 
- /**
 
-  * Standardidize extension name
 
-  * @static
 
-  * @param {string} s extension name
 
-  * @returns {string}
 
-  */
 
- showdown.helper.stdExtName = function (s) {
 
-   'use strict';
 
-   return s.replace(/[_-]||\s/g, '').toLowerCase();
 
- };
 
- function escapeCharactersCallback(wholeMatch, m1) {
 
-   'use strict';
 
-   var charCodeToEscape = m1.charCodeAt(0);
 
-   return '~E' + charCodeToEscape + 'E';
 
- }
 
- /**
 
-  * Callback used to escape characters when passing through String.replace
 
-  * @static
 
-  * @param {string} wholeMatch
 
-  * @param {string} m1
 
-  * @returns {string}
 
-  */
 
- showdown.helper.escapeCharactersCallback = escapeCharactersCallback;
 
- /**
 
-  * Escape characters in a string
 
-  * @static
 
-  * @param {string} text
 
-  * @param {string} charsToEscape
 
-  * @param {boolean} afterBackslash
 
-  * @returns {XML|string|void|*}
 
-  */
 
- showdown.helper.escapeCharacters = function escapeCharacters(text, charsToEscape, afterBackslash) {
 
-   'use strict';
 
-   // First we have to escape the escape characters so that
 
-   // we can build a character class out of them
 
-   var regexString = '([' + charsToEscape.replace(/([\[\]\\])/g, '\\$1') + '])';
 
-   if (afterBackslash) {
 
-     regexString = '\\\\' + regexString;
 
-   }
 
-   var regex = new RegExp(regexString, 'g');
 
-   text = text.replace(regex, escapeCharactersCallback);
 
-   return text;
 
- };
 
- var rgxFindMatchPos = function (str, left, right, flags) {
 
-   'use strict';
 
-   var f = flags || '',
 
-     g = f.indexOf('g') > -1,
 
-     x = new RegExp(left + '|' + right, 'g' + f.replace(/g/g, '')),
 
-     l = new RegExp(left, f.replace(/g/g, '')),
 
-     pos = [],
 
-     t, s, m, start, end;
 
-   do {
 
-     t = 0;
 
-     while ((m = x.exec(str))) {
 
-       if (l.test(m[0])) {
 
-         if (!(t++)) {
 
-           s = x.lastIndex;
 
-           start = s - m[0].length;
 
-         }
 
-       } else if (t) {
 
-         if (!--t) {
 
-           end = m.index + m[0].length;
 
-           var obj = {
 
-             left: {start: start, end: s},
 
-             match: {start: s, end: m.index},
 
-             right: {start: m.index, end: end},
 
-             wholeMatch: {start: start, end: end}
 
-           };
 
-           pos.push(obj);
 
-           if (!g) {
 
-             return pos;
 
-           }
 
-         }
 
-       }
 
-     }
 
-   } while (t && (x.lastIndex = s));
 
-   return pos;
 
- };
 
- /**
 
-  * matchRecursiveRegExp
 
-  *
 
-  * (c) 2007 Steven Levithan <stevenlevithan.com>
 
-  * MIT License
 
-  *
 
-  * Accepts a string to search, a left and right format delimiter
 
-  * as regex patterns, and optional regex flags. Returns an array
 
-  * of matches, allowing nested instances of left/right delimiters.
 
-  * Use the "g" flag to return all matches, otherwise only the
 
-  * first is returned. Be careful to ensure that the left and
 
-  * right format delimiters produce mutually exclusive matches.
 
-  * Backreferences are not supported within the right delimiter
 
-  * due to how it is internally combined with the left delimiter.
 
-  * When matching strings whose format delimiters are unbalanced
 
-  * to the left or right, the output is intentionally as a
 
-  * conventional regex library with recursion support would
 
-  * produce, e.g. "<<x>" and "<x>>" both produce ["x"] when using
 
-  * "<" and ">" as the delimiters (both strings contain a single,
 
-  * balanced instance of "<x>").
 
-  *
 
-  * examples:
 
-  * matchRecursiveRegExp("test", "\\(", "\\)")
 
-  * returns: []
 
-  * matchRecursiveRegExp("<t<<e>><s>>t<>", "<", ">", "g")
 
-  * returns: ["t<<e>><s>", ""]
 
-  * matchRecursiveRegExp("<div id=\"x\">test</div>", "<div\\b[^>]*>", "</div>", "gi")
 
-  * returns: ["test"]
 
-  */
 
- showdown.helper.matchRecursiveRegExp = function (str, left, right, flags) {
 
-   'use strict';
 
-   var matchPos = rgxFindMatchPos (str, left, right, flags),
 
-     results = [];
 
-   for (var i = 0; i < matchPos.length; ++i) {
 
-     results.push([
 
-       str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
 
-       str.slice(matchPos[i].match.start, matchPos[i].match.end),
 
-       str.slice(matchPos[i].left.start, matchPos[i].left.end),
 
-       str.slice(matchPos[i].right.start, matchPos[i].right.end)
 
-     ]);
 
-   }
 
-   return results;
 
- };
 
- /**
 
-  *
 
-  * @param {string} str
 
-  * @param {string|function} replacement
 
-  * @param {string} left
 
-  * @param {string} right
 
-  * @param {string} flags
 
-  * @returns {string}
 
-  */
 
- showdown.helper.replaceRecursiveRegExp = function (str, replacement, left, right, flags) {
 
-   'use strict';
 
-   if (!showdown.helper.isFunction(replacement)) {
 
-     var repStr = replacement;
 
-     replacement = function () {
 
-       return repStr;
 
-     };
 
-   }
 
-   var matchPos = rgxFindMatchPos(str, left, right, flags),
 
-       finalStr = str,
 
-       lng = matchPos.length;
 
-   if (lng > 0) {
 
-     var bits = [];
 
-     if (matchPos[0].wholeMatch.start !== 0) {
 
-       bits.push(str.slice(0, matchPos[0].wholeMatch.start));
 
-     }
 
-     for (var i = 0; i < lng; ++i) {
 
-       bits.push(
 
-         replacement(
 
-           str.slice(matchPos[i].wholeMatch.start, matchPos[i].wholeMatch.end),
 
-           str.slice(matchPos[i].match.start, matchPos[i].match.end),
 
-           str.slice(matchPos[i].left.start, matchPos[i].left.end),
 
-           str.slice(matchPos[i].right.start, matchPos[i].right.end)
 
-         )
 
-       );
 
-       if (i < lng - 1) {
 
-         bits.push(str.slice(matchPos[i].wholeMatch.end, matchPos[i + 1].wholeMatch.start));
 
-       }
 
-     }
 
-     if (matchPos[lng - 1].wholeMatch.end < str.length) {
 
-       bits.push(str.slice(matchPos[lng - 1].wholeMatch.end));
 
-     }
 
-     finalStr = bits.join('');
 
-   }
 
-   return finalStr;
 
- };
 
- /**
 
-  * POLYFILLS
 
-  */
 
- if (showdown.helper.isUndefined(console)) {
 
-   console = {
 
-     warn: function (msg) {
 
-       'use strict';
 
-       alert(msg);
 
-     },
 
-     log: function (msg) {
 
-       'use strict';
 
-       alert(msg);
 
-     },
 
-     error: function (msg) {
 
-       'use strict';
 
-       throw msg;
 
-     }
 
-   };
 
- }
 
- /**
 
-  * Created by Estevao on 31-05-2015.
 
-  */
 
- /**
 
-  * Showdown Converter class
 
-  * @class
 
-  * @param {object} [converterOptions]
 
-  * @returns {Converter}
 
-  */
 
- showdown.Converter = function (converterOptions) {
 
-   'use strict';
 
-   var
 
-       /**
 
-        * Options used by this converter
 
-        * @private
 
-        * @type {{}}
 
-        */
 
-       options = {},
 
-       /**
 
-        * Language extensions used by this converter
 
-        * @private
 
-        * @type {Array}
 
-        */
 
-       langExtensions = [],
 
-       /**
 
-        * Output modifiers extensions used by this converter
 
-        * @private
 
-        * @type {Array}
 
-        */
 
-       outputModifiers = [],
 
-       /**
 
-        * Event listeners
 
-        * @private
 
-        * @type {{}}
 
-        */
 
-       listeners = {};
 
-   _constructor();
 
-   /**
 
-    * Converter constructor
 
-    * @private
 
-    */
 
-   function _constructor() {
 
-     converterOptions = converterOptions || {};
 
-     for (var gOpt in globalOptions) {
 
-       if (globalOptions.hasOwnProperty(gOpt)) {
 
-         options[gOpt] = globalOptions[gOpt];
 
-       }
 
-     }
 
-     // Merge options
 
-     if (typeof converterOptions === 'object') {
 
-       for (var opt in converterOptions) {
 
-         if (converterOptions.hasOwnProperty(opt)) {
 
-           options[opt] = converterOptions[opt];
 
-         }
 
-       }
 
-     } else {
 
-       throw Error('Converter expects the passed parameter to be an object, but ' + typeof converterOptions +
 
-       ' was passed instead.');
 
-     }
 
-     if (options.extensions) {
 
-       showdown.helper.forEach(options.extensions, _parseExtension);
 
-     }
 
-   }
 
-   /**
 
-    * Parse extension
 
-    * @param {*} ext
 
-    * @param {string} [name='']
 
-    * @private
 
-    */
 
-   function _parseExtension(ext, name) {
 
-     name = name || null;
 
-     // If it's a string, the extension was previously loaded
 
-     if (showdown.helper.isString(ext)) {
 
-       ext = showdown.helper.stdExtName(ext);
 
-       name = ext;
 
-       // LEGACY_SUPPORT CODE
 
-       if (showdown.extensions[ext]) {
 
-         console.warn('DEPRECATION WARNING: ' + ext + ' is an old extension that uses a deprecated loading method.' +
 
-           'Please inform the developer that the extension should be updated!');
 
-         legacyExtensionLoading(showdown.extensions[ext], ext);
 
-         return;
 
-       // END LEGACY SUPPORT CODE
 
-       } else if (!showdown.helper.isUndefined(extensions[ext])) {
 
-         ext = extensions[ext];
 
-       } else {
 
-         throw Error('Extension "' + ext + '" could not be loaded. It was either not found or is not a valid extension.');
 
-       }
 
-     }
 
-     if (typeof ext === 'function') {
 
-       ext = ext();
 
-     }
 
-     if (!showdown.helper.isArray(ext)) {
 
-       ext = [ext];
 
-     }
 
-     var validExt = validate(ext, name);
 
-     if (!validExt.valid) {
 
-       throw Error(validExt.error);
 
-     }
 
-     for (var i = 0; i < ext.length; ++i) {
 
-       switch (ext[i].type) {
 
-         case 'lang':
 
-           langExtensions.push(ext[i]);
 
-           break;
 
-         case 'output':
 
-           outputModifiers.push(ext[i]);
 
-           break;
 
-       }
 
-       if (ext[i].hasOwnProperty(listeners)) {
 
-         for (var ln in ext[i].listeners) {
 
-           if (ext[i].listeners.hasOwnProperty(ln)) {
 
-             listen(ln, ext[i].listeners[ln]);
 
-           }
 
-         }
 
-       }
 
-     }
 
-   }
 
-   /**
 
-    * LEGACY_SUPPORT
 
-    * @param {*} ext
 
-    * @param {string} name
 
-    */
 
-   function legacyExtensionLoading(ext, name) {
 
-     if (typeof ext === 'function') {
 
-       ext = ext(new showdown.Converter());
 
-     }
 
-     if (!showdown.helper.isArray(ext)) {
 
-       ext = [ext];
 
-     }
 
-     var valid = validate(ext, name);
 
-     if (!valid.valid) {
 
-       throw Error(valid.error);
 
-     }
 
-     for (var i = 0; i < ext.length; ++i) {
 
-       switch (ext[i].type) {
 
-         case 'lang':
 
-           langExtensions.push(ext[i]);
 
-           break;
 
-         case 'output':
 
-           outputModifiers.push(ext[i]);
 
-           break;
 
-         default:// should never reach here
 
-           throw Error('Extension loader error: Type unrecognized!!!');
 
-       }
 
-     }
 
-   }
 
-   /**
 
-    * Listen to an event
 
-    * @param {string} name
 
-    * @param {function} callback
 
-    */
 
-   function listen(name, callback) {
 
-     if (!showdown.helper.isString(name)) {
 
-       throw Error('Invalid argument in converter.listen() method: name must be a string, but ' + typeof name + ' given');
 
-     }
 
-     if (typeof callback !== 'function') {
 
-       throw Error('Invalid argument in converter.listen() method: callback must be a function, but ' + typeof callback + ' given');
 
-     }
 
-     if (!listeners.hasOwnProperty(name)) {
 
-       listeners[name] = [];
 
-     }
 
-     listeners[name].push(callback);
 
-   }
 
-   function rTrimInputText(text) {
 
-     var rsp = text.match(/^\s*/)[0].length,
 
-         rgx = new RegExp('^\\s{0,' + rsp + '}', 'gm');
 
-     return text.replace(rgx, '');
 
-   }
 
-   /**
 
-    * Dispatch an event
 
-    * @private
 
-    * @param {string} evtName Event name
 
-    * @param {string} text Text
 
-    * @param {{}} options Converter Options
 
-    * @param {{}} globals
 
-    * @returns {string}
 
-    */
 
-   this._dispatch = function dispatch (evtName, text, options, globals) {
 
-     if (listeners.hasOwnProperty(evtName)) {
 
-       for (var ei = 0; ei < listeners[evtName].length; ++ei) {
 
-         var nText = listeners[evtName][ei](evtName, text, this, options, globals);
 
-         if (nText && typeof nText !== 'undefined') {
 
-           text = nText;
 
-         }
 
-       }
 
-     }
 
-     return text;
 
-   };
 
-   /**
 
-    * Listen to an event
 
-    * @param {string} name
 
-    * @param {function} callback
 
-    * @returns {showdown.Converter}
 
-    */
 
-   this.listen = function (name, callback) {
 
-     listen(name, callback);
 
-     return this;
 
-   };
 
-   /**
 
-    * Converts a markdown string into HTML
 
-    * @param {string} text
 
-    * @returns {*}
 
-    */
 
-   this.makeHtml = function (text) {
 
-     //check if text is not falsy
 
-     if (!text) {
 
-       return text;
 
-     }
 
-     var globals = {
 
-       gHtmlBlocks:     [],
 
-       gHtmlMdBlocks:   [],
 
-       gHtmlSpans:      [],
 
-       gUrls:           {},
 
-       gTitles:         {},
 
-       gDimensions:     {},
 
-       gListLevel:      0,
 
-       hashLinkCounts:  {},
 
-       langExtensions:  langExtensions,
 
-       outputModifiers: outputModifiers,
 
-       converter:       this,
 
-       ghCodeBlocks:    []
 
-     };
 
-     // attacklab: Replace ~ with ~T
 
-     // This lets us use tilde as an escape char to avoid md5 hashes
 
-     // The choice of character is arbitrary; anything that isn't
 
-     // magic in Markdown will work.
 
-     text = text.replace(/~/g, '~T');
 
-     // attacklab: Replace $ with ~D
 
-     // RegExp interprets $ as a special character
 
-     // when it's in a replacement string
 
-     text = text.replace(/\$/g, '~D');
 
-     // Standardize line endings
 
-     text = text.replace(/\r\n/g, '\n'); // DOS to Unix
 
-     text = text.replace(/\r/g, '\n'); // Mac to Unix
 
-     if (options.smartIndentationFix) {
 
-       text = rTrimInputText(text);
 
-     }
 
-     // Make sure text begins and ends with a couple of newlines:
 
-     //text = '\n\n' + text + '\n\n';
 
-     text = text;
 
-     // detab
 
-     text = showdown.subParser('detab')(text, options, globals);
 
-     // stripBlankLines
 
-     text = showdown.subParser('stripBlankLines')(text, options, globals);
 
-     //run languageExtensions
 
-     showdown.helper.forEach(langExtensions, function (ext) {
 
-       text = showdown.subParser('runExtension')(ext, text, options, globals);
 
-     });
 
-     // run the sub parsers
 
-     text = showdown.subParser('hashPreCodeTags')(text, options, globals);
 
-     text = showdown.subParser('githubCodeBlocks')(text, options, globals);
 
-     text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
 
-     text = showdown.subParser('hashHTMLSpans')(text, options, globals);
 
-     text = showdown.subParser('stripLinkDefinitions')(text, options, globals);
 
-     text = showdown.subParser('blockGamut')(text, options, globals);
 
-     text = showdown.subParser('unhashHTMLSpans')(text, options, globals);
 
-     text = showdown.subParser('unescapeSpecialChars')(text, options, globals);
 
-     // attacklab: Restore dollar signs
 
-     text = text.replace(/~D/g, '$$');
 
-     // attacklab: Restore tildes
 
-     text = text.replace(/~T/g, '~');
 
-     // Run output modifiers
 
-     showdown.helper.forEach(outputModifiers, function (ext) {
 
-       text = showdown.subParser('runExtension')(ext, text, options, globals);
 
-     });
 
-     return text;
 
-   };
 
-   /**
 
-    * Set an option of this Converter instance
 
-    * @param {string} key
 
-    * @param {*} value
 
-    */
 
-   this.setOption = function (key, value) {
 
-     options[key] = value;
 
-   };
 
-   /**
 
-    * Get the option of this Converter instance
 
-    * @param {string} key
 
-    * @returns {*}
 
-    */
 
-   this.getOption = function (key) {
 
-     return options[key];
 
-   };
 
-   /**
 
-    * Get the options of this Converter instance
 
-    * @returns {{}}
 
-    */
 
-   this.getOptions = function () {
 
-     return options;
 
-   };
 
-   /**
 
-    * Add extension to THIS converter
 
-    * @param {{}} extension
 
-    * @param {string} [name=null]
 
-    */
 
-   this.addExtension = function (extension, name) {
 
-     name = name || null;
 
-     _parseExtension(extension, name);
 
-   };
 
-   /**
 
-    * Use a global registered extension with THIS converter
 
-    * @param {string} extensionName Name of the previously registered extension
 
-    */
 
-   this.useExtension = function (extensionName) {
 
-     _parseExtension(extensionName);
 
-   };
 
-   /**
 
-    * Set the flavor THIS converter should use
 
-    * @param {string} name
 
-    */
 
-   this.setFlavor = function (name) {
 
-     if (flavor.hasOwnProperty(name)) {
 
-       var preset = flavor[name];
 
-       for (var option in preset) {
 
-         if (preset.hasOwnProperty(option)) {
 
-           options[option] = preset[option];
 
-         }
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Remove an extension from THIS converter.
 
-    * Note: This is a costly operation. It's better to initialize a new converter
 
-    * and specify the extensions you wish to use
 
-    * @param {Array} extension
 
-    */
 
-   this.removeExtension = function (extension) {
 
-     if (!showdown.helper.isArray(extension)) {
 
-       extension = [extension];
 
-     }
 
-     for (var a = 0; a < extension.length; ++a) {
 
-       var ext = extension[a];
 
-       for (var i = 0; i < langExtensions.length; ++i) {
 
-         if (langExtensions[i] === ext) {
 
-           langExtensions[i].splice(i, 1);
 
-         }
 
-       }
 
-       for (var ii = 0; ii < outputModifiers.length; ++i) {
 
-         if (outputModifiers[ii] === ext) {
 
-           outputModifiers[ii].splice(i, 1);
 
-         }
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Get all extension of THIS converter
 
-    * @returns {{language: Array, output: Array}}
 
-    */
 
-   this.getAllExtensions = function () {
 
-     return {
 
-       language: langExtensions,
 
-       output: outputModifiers
 
-     };
 
-   };
 
- };
 
- /**
 
-  * Turn Markdown link shortcuts into XHTML <a> tags.
 
-  */
 
- showdown.subParser('anchors', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('anchors.before', text, options, globals);
 
-   var writeAnchorTag = function (wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
 
-     if (showdown.helper.isUndefined(m7)) {
 
-       m7 = '';
 
-     }
 
-     wholeMatch = m1;
 
-     var linkText = m2,
 
-         linkId = m3.toLowerCase(),
 
-         url = m4,
 
-         title = m7;
 
-     if (!url) {
 
-       if (!linkId) {
 
-         // lower-case and turn embedded newlines into spaces
 
-         linkId = linkText.toLowerCase().replace(/ ?\n/g, ' ');
 
-       }
 
-       url = '#' + linkId;
 
-       if (!showdown.helper.isUndefined(globals.gUrls[linkId])) {
 
-         url = globals.gUrls[linkId];
 
-         if (!showdown.helper.isUndefined(globals.gTitles[linkId])) {
 
-           title = globals.gTitles[linkId];
 
-         }
 
-       } else {
 
-         if (wholeMatch.search(/\(\s*\)$/m) > -1) {
 
-           // Special case for explicit empty url
 
-           url = '';
 
-         } else {
 
-           return wholeMatch;
 
-         }
 
-       }
 
-     }
 
-     url = showdown.helper.escapeCharacters(url, '*_', false);
 
-     var result = '<a href="' + url + '"';
 
-     if (title !== '' && title !== null) {
 
-       title = title.replace(/"/g, '"');
 
-       title = showdown.helper.escapeCharacters(title, '*_', false);
 
-       result += ' title="' + title + '"';
 
-     }
 
-     result += '>' + linkText + '</a>';
 
-     return result;
 
-   };
 
-   // First, handle reference-style links: [link text] [id]
 
-   /*
 
-    text = text.replace(/
 
-    (							// wrap whole match in $1
 
-    \[
 
-    (
 
-    (?:
 
-    \[[^\]]*\]		// allow brackets nested one level
 
-    |
 
-    [^\[]			// or anything else
 
-    )*
 
-    )
 
-    \]
 
-    [ ]?					// one optional space
 
-    (?:\n[ ]*)?				// one optional newline followed by spaces
 
-    \[
 
-    (.*?)					// id = $3
 
-    \]
 
-    )()()()()					// pad remaining backreferences
 
-    /g,_DoAnchors_callback);
 
-    */
 
-   text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)][ ]?(?:\n[ ]*)?\[(.*?)])()()()()/g, writeAnchorTag);
 
-   //
 
-   // Next, inline-style links: [link text](url "optional title")
 
-   //
 
-   /*
 
-    text = text.replace(/
 
-    (						// wrap whole match in $1
 
-    \[
 
-    (
 
-    (?:
 
-    \[[^\]]*\]	// allow brackets nested one level
 
-    |
 
-    [^\[\]]			// or anything else
 
-    )
 
-    )
 
-    \]
 
-    \(						// literal paren
 
-    [ \t]*
 
-    ()						// no id, so leave $3 empty
 
-    <?(.*?)>?				// href = $4
 
-    [ \t]*
 
-    (						// $5
 
-    (['"])				// quote char = $6
 
-    (.*?)				// Title = $7
 
-    \6					// matching quote
 
-    [ \t]*				// ignore any spaces/tabs between closing quote and )
 
-    )?						// title is optional
 
-    \)
 
-    )
 
-    /g,writeAnchorTag);
 
-    */
 
-   text = text.replace(/(\[((?:\[[^\]]*]|[^\[\]])*)]\([ \t]*()<?(.*?(?:\(.*?\).*?)?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,
 
-                       writeAnchorTag);
 
-   //
 
-   // Last, handle reference-style shortcuts: [link text]
 
-   // These must come last in case you've also got [link test][1]
 
-   // or [link test](/foo)
 
-   //
 
-   /*
 
-    text = text.replace(/
 
-    (                // wrap whole match in $1
 
-    \[
 
-    ([^\[\]]+)       // link text = $2; can't contain '[' or ']'
 
-    \]
 
-    )()()()()()      // pad rest of backreferences
 
-    /g, writeAnchorTag);
 
-    */
 
-   text = text.replace(/(\[([^\[\]]+)])()()()()()/g, writeAnchorTag);
 
-   text = globals.converter._dispatch('anchors.after', text, options, globals);
 
-   return text;
 
- });
 
- showdown.subParser('autoLinks', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('autoLinks.before', text, options, globals);
 
-   var simpleURLRegex  = /\b(((https?|ftp|dict):\/\/|www\.)[^'">\s]+\.[^'">\s]+)(?=\s|$)(?!["<>])/gi,
 
-       delimUrlRegex   = /<(((https?|ftp|dict):\/\/|www\.)[^'">\s]+)>/gi,
 
-       simpleMailRegex = /(?:^|[ \n\t])([A-Za-z0-9!#$%&'*+-/=?^_`\{|}~\.]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)(?:$|[ \n\t])/gi,
 
-       delimMailRegex  = /<(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi;
 
-   text = text.replace(delimUrlRegex, replaceLink);
 
-   text = text.replace(delimMailRegex, replaceMail);
 
-   // simpleURLRegex  = /\b(((https?|ftp|dict):\/\/|www\.)[-.+~:?#@!$&'()*,;=[\]\w]+)\b/gi,
 
-   // Email addresses: <address@domain.foo>
 
-   if (options.simplifiedAutoLink) {
 
-     text = text.replace(simpleURLRegex, replaceLink);
 
-     text = text.replace(simpleMailRegex, replaceMail);
 
-   }
 
-   function replaceLink(wm, link) {
 
-     var lnkTxt = link;
 
-     if (/^www\./i.test(link)) {
 
-       link = link.replace(/^www\./i, 'http://www.');
 
-     }
 
-     return '<a href="' + link + '">' + lnkTxt + '</a>';
 
-   }
 
-   function replaceMail(wholeMatch, m1) {
 
-     var unescapedStr = showdown.subParser('unescapeSpecialChars')(m1);
 
-     return showdown.subParser('encodeEmailAddress')(unescapedStr);
 
-   }
 
-   text = globals.converter._dispatch('autoLinks.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * These are all the transformations that form block-level
 
-  * tags like paragraphs, headers, and list items.
 
-  */
 
- showdown.subParser('blockGamut', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('blockGamut.before', text, options, globals);
 
-   // we parse blockquotes first so that we can have headings and hrs
 
-   // inside blockquotes
 
-   text = showdown.subParser('blockQuotes')(text, options, globals);
 
-   text = showdown.subParser('headers')(text, options, globals);
 
-   // Do Horizontal Rules:
 
-   var key = showdown.subParser('hashBlock')('<hr />', options, globals);
 
-   text = text.replace(/^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$/gm, key);
 
-   text = text.replace(/^[ ]{0,2}([ ]?\-[ ]?){3,}[ \t]*$/gm, key);
 
-   text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$/gm, key);
 
-   text = showdown.subParser('lists')(text, options, globals);
 
-   text = showdown.subParser('codeBlocks')(text, options, globals);
 
-   text = showdown.subParser('tables')(text, options, globals);
 
-   // We already ran _HashHTMLBlocks() before, in Markdown(), but that
 
-   // was to escape raw HTML in the original Markdown source. This time,
 
-   // we're escaping the markup we've just created, so that we don't wrap
 
-   // <p> tags around block-level tags.
 
-   text = showdown.subParser('hashHTMLBlocks')(text, options, globals);
 
-   text = showdown.subParser('paragraphs')(text, options, globals);
 
-   text = globals.converter._dispatch('blockGamut.after', text, options, globals);
 
-   return text;
 
- });
 
- showdown.subParser('blockQuotes', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('blockQuotes.before', text, options, globals);
 
-   /*
 
-    text = text.replace(/
 
-    (								// Wrap whole match in $1
 
-    (
 
-    ^[ \t]*>[ \t]?			// '>' at the start of a line
 
-    .+\n					// rest of the first line
 
-    (.+\n)*					// subsequent consecutive lines
 
-    \n*						// blanks
 
-    )+
 
-    )
 
-    /gm, function(){...});
 
-    */
 
-   text = text.replace(/((^[ \t]{0,3}>[ \t]?.+\n(.+\n)*\n*)+)/gm, function (wholeMatch, m1) {
 
-     var bq = m1;
 
-     // attacklab: hack around Konqueror 3.5.4 bug:
 
-     // "----------bug".replace(/^-/g,"") == "bug"
 
-     bq = bq.replace(/^[ \t]*>[ \t]?/gm, '~0'); // trim one level of quoting
 
-     // attacklab: clean up hack
 
-     bq = bq.replace(/~0/g, '');
 
-     bq = bq.replace(/^[ \t]+$/gm, ''); // trim whitespace-only lines
 
-     bq = showdown.subParser('githubCodeBlocks')(bq, options, globals);
 
-     bq = showdown.subParser('blockGamut')(bq, options, globals); // recurse
 
-     bq = bq.replace(/(^|\n)/g, '$1  ');
 
-     // These leading spaces screw with <pre> content, so we need to fix that:
 
-     bq = bq.replace(/(\s*<pre>[^\r]+?<\/pre>)/gm, function (wholeMatch, m1) {
 
-       var pre = m1;
 
-       // attacklab: hack around Konqueror 3.5.4 bug:
 
-       pre = pre.replace(/^  /mg, '~0');
 
-       pre = pre.replace(/~0/g, '');
 
-       return pre;
 
-     });
 
-     return showdown.subParser('hashBlock')('<blockquote>\n' + bq + '\n</blockquote>', options, globals);
 
-   });
 
-   text = globals.converter._dispatch('blockQuotes.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Process Markdown `<pre><code>` blocks.
 
-  */
 
- showdown.subParser('codeBlocks', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('codeBlocks.before', text, options, globals);
 
-   /*
 
-    text = text.replace(text,
 
-    /(?:\n\n|^)
 
-    (								// $1 = the code block -- one or more lines, starting with a space/tab
 
-    (?:
 
-    (?:[ ]{4}|\t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
 
-    .*\n+
 
-    )+
 
-    )
 
-    (\n*[ ]{0,3}[^ \t\n]|(?=~0))	// attacklab: g_tab_width
 
-    /g,function(){...});
 
-    */
 
-   // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
 
-   text += '~0';
 
-   var pattern = /(?:\n\n|^)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g;
 
-   text = text.replace(pattern, function (wholeMatch, m1, m2) {
 
-     var codeblock = m1,
 
-         nextChar = m2,
 
-         end = '\n';
 
-     codeblock = showdown.subParser('outdent')(codeblock);
 
-     codeblock = showdown.subParser('encodeCode')(codeblock);
 
-     codeblock = showdown.subParser('detab')(codeblock);
 
-     codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
 
-     codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing newlines
 
-     if (options.omitExtraWLInCodeBlocks) {
 
-       end = '';
 
-     }
 
-     codeblock = '<pre><code>' + codeblock + end + '</code></pre>';
 
-     return showdown.subParser('hashBlock')(codeblock, options, globals) + nextChar;
 
-   });
 
-   // attacklab: strip sentinel
 
-   text = text.replace(/~0/, '');
 
-   text = globals.converter._dispatch('codeBlocks.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  *
 
-  *   *  Backtick quotes are used for <code></code> spans.
 
-  *
 
-  *   *  You can use multiple backticks as the delimiters if you want to
 
-  *     include literal backticks in the code span. So, this input:
 
-  *
 
-  *         Just type ``foo `bar` baz`` at the prompt.
 
-  *
 
-  *       Will translate to:
 
-  *
 
-  *         <p>Just type <code>foo `bar` baz</code> at the prompt.</p>
 
-  *
 
-  *    There's no arbitrary limit to the number of backticks you
 
-  *    can use as delimters. If you need three consecutive backticks
 
-  *    in your code, use four for delimiters, etc.
 
-  *
 
-  *  *  You can use spaces to get literal backticks at the edges:
 
-  *
 
-  *         ... type `` `bar` `` ...
 
-  *
 
-  *       Turns to:
 
-  *
 
-  *         ... type <code>`bar`</code> ...
 
-  */
 
- showdown.subParser('codeSpans', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('codeSpans.before', text, options, globals);
 
-   /*
 
-    text = text.replace(/
 
-    (^|[^\\])					// Character before opening ` can't be a backslash
 
-    (`+)						// $2 = Opening run of `
 
-    (							// $3 = The code block
 
-    [^\r]*?
 
-    [^`]					// attacklab: work around lack of lookbehind
 
-    )
 
-    \2							// Matching closer
 
-    (?!`)
 
-    /gm, function(){...});
 
-    */
 
-   if (typeof(text) === 'undefined') {
 
-     text = '';
 
-   }
 
-   text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
 
-     function (wholeMatch, m1, m2, m3) {
 
-       var c = m3;
 
-       c = c.replace(/^([ \t]*)/g, '');	// leading whitespace
 
-       c = c.replace(/[ \t]*$/g, '');	// trailing whitespace
 
-       c = showdown.subParser('encodeCode')(c);
 
-       return m1 + '<code>' + c + '</code>';
 
-     }
 
-   );
 
-   text = globals.converter._dispatch('codeSpans.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Convert all tabs to spaces
 
-  */
 
- showdown.subParser('detab', function (text) {
 
-   'use strict';
 
-   // expand first n-1 tabs
 
-   text = text.replace(/\t(?=\t)/g, '    '); // g_tab_width
 
-   // replace the nth with two sentinels
 
-   text = text.replace(/\t/g, '~A~B');
 
-   // use the sentinel to anchor our regex so it doesn't explode
 
-   text = text.replace(/~B(.+?)~A/g, function (wholeMatch, m1) {
 
-     var leadingText = m1,
 
-         numSpaces = 4 - leadingText.length % 4;  // g_tab_width
 
-     // there *must* be a better way to do this:
 
-     for (var i = 0; i < numSpaces; i++) {
 
-       leadingText += ' ';
 
-     }
 
-     return leadingText;
 
-   });
 
-   // clean up sentinels
 
-   text = text.replace(/~A/g, '    ');  // g_tab_width
 
-   text = text.replace(/~B/g, '');
 
-   return text;
 
- });
 
- /**
 
-  * Smart processing for ampersands and angle brackets that need to be encoded.
 
-  */
 
- showdown.subParser('encodeAmpsAndAngles', function (text) {
 
-   'use strict';
 
-   // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin:
 
-   // http://bumppo.net/projects/amputator/
 
-   text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/g, '&');
 
-   // Encode naked <'s
 
-   text = text.replace(/<(?![a-z\/?\$!])/gi, '<');
 
-   return text;
 
- });
 
- /**
 
-  * Returns the string, with after processing the following backslash escape sequences.
 
-  *
 
-  * attacklab: The polite way to do this is with the new escapeCharacters() function:
 
-  *
 
-  *    text = escapeCharacters(text,"\\",true);
 
-  *    text = escapeCharacters(text,"`*_{}[]()>#+-.!",true);
 
-  *
 
-  * ...but we're sidestepping its use of the (slow) RegExp constructor
 
-  * as an optimization for Firefox.  This function gets called a LOT.
 
-  */
 
- showdown.subParser('encodeBackslashEscapes', function (text) {
 
-   'use strict';
 
-   text = text.replace(/\\(\\)/g, showdown.helper.escapeCharactersCallback);
 
-   text = text.replace(/\\([`*_{}\[\]()>#+-.!])/g, showdown.helper.escapeCharactersCallback);
 
-   return text;
 
- });
 
- /**
 
-  * Encode/escape certain characters inside Markdown code runs.
 
-  * The point is that in code, these characters are literals,
 
-  * and lose their special Markdown meanings.
 
-  */
 
- showdown.subParser('encodeCode', function (text) {
 
-   'use strict';
 
-   // Encode all ampersands; HTML entities are not
 
-   // entities within a Markdown code span.
 
-   text = text.replace(/&/g, '&');
 
-   // Do the angle bracket song and dance:
 
-   text = text.replace(/</g, '<');
 
-   text = text.replace(/>/g, '>');
 
-   // Now, escape characters that are magic in Markdown:
 
-   text = showdown.helper.escapeCharacters(text, '*_{}[]\\', false);
 
-   // jj the line above breaks this:
 
-   //---
 
-   //* Item
 
-   //   1. Subitem
 
-   //            special char: *
 
-   // ---
 
-   return text;
 
- });
 
- /**
 
-  *  Input: an email address, e.g. "foo@example.com"
 
-  *
 
-  *  Output: the email address as a mailto link, with each character
 
-  *    of the address encoded as either a decimal or hex entity, in
 
-  *    the hopes of foiling most address harvesting spam bots. E.g.:
 
-  *
 
-  *    <a href="mailto:foo@e
 
-  *       xample.com">foo
 
-  *       @example.com</a>
 
-  *
 
-  *  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk
 
-  *  mailing list: <http://tinyurl.com/yu7ue>
 
-  *
 
-  */
 
- showdown.subParser('encodeEmailAddress', function (addr) {
 
-   'use strict';
 
-   var encode = [
 
-     function (ch) {
 
-       return '&#' + ch.charCodeAt(0) + ';';
 
-     },
 
-     function (ch) {
 
-       return '&#x' + ch.charCodeAt(0).toString(16) + ';';
 
-     },
 
-     function (ch) {
 
-       return ch;
 
-     }
 
-   ];
 
-   addr = 'mailto:' + addr;
 
-   addr = addr.replace(/./g, function (ch) {
 
-     if (ch === '@') {
 
-       // this *must* be encoded. I insist.
 
-       ch = encode[Math.floor(Math.random() * 2)](ch);
 
-     } else if (ch !== ':') {
 
-       // leave ':' alone (to spot mailto: later)
 
-       var r = Math.random();
 
-       // roughly 10% raw, 45% hex, 45% dec
 
-       ch = (
 
-         r > 0.9 ? encode[2](ch) : r > 0.45 ? encode[1](ch) : encode[0](ch)
 
-       );
 
-     }
 
-     return ch;
 
-   });
 
-   addr = '<a href="' + addr + '">' + addr + '</a>';
 
-   addr = addr.replace(/">.+:/g, '">'); // strip the mailto: from the visible part
 
-   return addr;
 
- });
 
- /**
 
-  * Within tags -- meaning between < and > -- encode [\ ` * _] so they
 
-  * don't conflict with their use in Markdown for code, italics and strong.
 
-  */
 
- showdown.subParser('escapeSpecialCharsWithinTagAttributes', function (text) {
 
-   'use strict';
 
-   // Build a regex to find HTML tags and comments.  See Friedl's
 
-   // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
 
-   var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi;
 
-   text = text.replace(regex, function (wholeMatch) {
 
-     var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, '$1`');
 
-     tag = showdown.helper.escapeCharacters(tag, '\\`*_', false);
 
-     return tag;
 
-   });
 
-   return text;
 
- });
 
- /**
 
-  * Handle github codeblocks prior to running HashHTML so that
 
-  * HTML contained within the codeblock gets escaped properly
 
-  * Example:
 
-  * ```ruby
 
-  *     def hello_world(x)
 
-  *       puts "Hello, #{x}"
 
-  *     end
 
-  * ```
 
-  */
 
- showdown.subParser('githubCodeBlocks', function (text, options, globals) {
 
-   'use strict';
 
-   // early exit if option is not enabled
 
-   if (!options.ghCodeBlocks) {
 
-     return text;
 
-   }
 
-   text = globals.converter._dispatch('githubCodeBlocks.before', text, options, globals);
 
-   text += '~0';
 
-   text = text.replace(/(?:^|\n)```(.*)\n([\s\S]*?)\n```/g, function (wholeMatch, language, codeblock) {
 
-     var end = (options.omitExtraWLInCodeBlocks) ? '' : '\n';
 
-     // First parse the github code block
 
-     codeblock = showdown.subParser('encodeCode')(codeblock);
 
-     codeblock = showdown.subParser('detab')(codeblock);
 
-     codeblock = codeblock.replace(/^\n+/g, ''); // trim leading newlines
 
-     codeblock = codeblock.replace(/\n+$/g, ''); // trim trailing whitespace
 
-     codeblock = '<pre><code' + (language ? ' class="' + language + ' language-' + language + '"' : '') + '>' + codeblock + end + '</code></pre>';
 
-     codeblock = showdown.subParser('hashBlock')(codeblock, options, globals);
 
-     // Since GHCodeblocks can be false positives, we need to
 
-     // store the primitive text and the parsed text in a global var,
 
-     // and then return a token
 
-     return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
 
-   });
 
-   // attacklab: strip sentinel
 
-   text = text.replace(/~0/, '');
 
-   return globals.converter._dispatch('githubCodeBlocks.after', text, options, globals);
 
- });
 
- showdown.subParser('hashBlock', function (text, options, globals) {
 
-   'use strict';
 
-   text = text.replace(/(^\n+|\n+$)/g, '');
 
-   return '\n\n~K' + (globals.gHtmlBlocks.push(text) - 1) + 'K\n\n';
 
- });
 
- showdown.subParser('hashElement', function (text, options, globals) {
 
-   'use strict';
 
-   return function (wholeMatch, m1) {
 
-     var blockText = m1;
 
-     // Undo double lines
 
-     blockText = blockText.replace(/\n\n/g, '\n');
 
-     blockText = blockText.replace(/^\n/, '');
 
-     // strip trailing blank lines
 
-     blockText = blockText.replace(/\n+$/g, '');
 
-     // Replace the element text with a marker ("~KxK" where x is its key)
 
-     blockText = '\n\n~K' + (globals.gHtmlBlocks.push(blockText) - 1) + 'K\n\n';
 
-     return blockText;
 
-   };
 
- });
 
- showdown.subParser('hashHTMLBlocks', function (text, options, globals) {
 
-   'use strict';
 
-   var blockTags = [
 
-       'pre',
 
-       'div',
 
-       'h1',
 
-       'h2',
 
-       'h3',
 
-       'h4',
 
-       'h5',
 
-       'h6',
 
-       'blockquote',
 
-       'table',
 
-       'dl',
 
-       'ol',
 
-       'ul',
 
-       'script',
 
-       'noscript',
 
-       'form',
 
-       'fieldset',
 
-       'iframe',
 
-       'math',
 
-       'style',
 
-       'section',
 
-       'header',
 
-       'footer',
 
-       'nav',
 
-       'article',
 
-       'aside',
 
-       'address',
 
-       'audio',
 
-       'canvas',
 
-       'figure',
 
-       'hgroup',
 
-       'output',
 
-       'video',
 
-       'p'
 
-     ],
 
-     repFunc = function (wholeMatch, match, left, right) {
 
-       var txt = wholeMatch;
 
-       // check if this html element is marked as markdown
 
-       // if so, it's contents should be parsed as markdown
 
-       if (left.search(/\bmarkdown\b/) !== -1) {
 
-         txt = left + globals.converter.makeHtml(match) + right;
 
-       }
 
-       return '\n\n~K' + (globals.gHtmlBlocks.push(txt) - 1) + 'K\n\n';
 
-     };
 
-   for (var i = 0; i < blockTags.length; ++i) {
 
-     text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<' + blockTags[i] + '\\b[^>]*>', '</' + blockTags[i] + '>', 'gim');
 
-   }
 
-   // HR SPECIAL CASE
 
-   text = text.replace(/(\n[ ]{0,3}(<(hr)\b([^<>])*?\/?>)[ \t]*(?=\n{2,}))/g,
 
-     showdown.subParser('hashElement')(text, options, globals));
 
-   // Special case for standalone HTML comments:
 
-   text = text.replace(/(<!--[\s\S]*?-->)/g,
 
-     showdown.subParser('hashElement')(text, options, globals));
 
-   // PHP and ASP-style processor instructions (<?...?> and <%...%>)
 
-   text = text.replace(/(?:\n\n)([ ]{0,3}(?:<([?%])[^\r]*?\2>)[ \t]*(?=\n{2,}))/g,
 
-     showdown.subParser('hashElement')(text, options, globals));
 
-   return text;
 
- });
 
- /**
 
-  * Hash span elements that should not be parsed as markdown
 
-  */
 
- showdown.subParser('hashHTMLSpans', function (text, config, globals) {
 
-   'use strict';
 
-   var matches = showdown.helper.matchRecursiveRegExp(text, '<code\\b[^>]*>', '</code>', 'gi');
 
-   for (var i = 0; i < matches.length; ++i) {
 
-     text = text.replace(matches[i][0], '~L' + (globals.gHtmlSpans.push(matches[i][0]) - 1) + 'L');
 
-   }
 
-   return text;
 
- });
 
- /**
 
-  * Unhash HTML spans
 
-  */
 
- showdown.subParser('unhashHTMLSpans', function (text, config, globals) {
 
-   'use strict';
 
-   for (var i = 0; i < globals.gHtmlSpans.length; ++i) {
 
-     text = text.replace('~L' + i + 'L', globals.gHtmlSpans[i]);
 
-   }
 
-   return text;
 
- });
 
- /**
 
-  * Hash span elements that should not be parsed as markdown
 
-  */
 
- showdown.subParser('hashPreCodeTags', function (text, config, globals) {
 
-   'use strict';
 
-   var repFunc = function (wholeMatch, match, left, right) {
 
-     // encode html entities
 
-     var codeblock = left + showdown.subParser('encodeCode')(match) + right;
 
-     return '\n\n~G' + (globals.ghCodeBlocks.push({text: wholeMatch, codeblock: codeblock}) - 1) + 'G\n\n';
 
-   };
 
-   text = showdown.helper.replaceRecursiveRegExp(text, repFunc, '^(?: |\\t){0,3}<pre\\b[^>]*>\\s*<code\\b[^>]*>', '^(?: |\\t){0,3}</code>\\s*</pre>', 'gim');
 
-   return text;
 
- });
 
- showdown.subParser('headers', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('headers.before', text, options, globals);
 
-   var prefixHeader = options.prefixHeaderId,
 
-       headerLevelStart = (isNaN(parseInt(options.headerLevelStart))) ? 1 : parseInt(options.headerLevelStart),
 
-   // Set text-style headers:
 
-   //	Header 1
 
-   //	========
 
-   //
 
-   //	Header 2
 
-   //	--------
 
-   //
 
-       setextRegexH1 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n={2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n=+[ \t]*\n+/gm,
 
-       setextRegexH2 = (options.smoothLivePreview) ? /^(.+)[ \t]*\n-{2,}[ \t]*\n+/gm : /^(.+)[ \t]*\n-+[ \t]*\n+/gm;
 
-   text = text.replace(setextRegexH1, function (wholeMatch, m1) {
 
-     var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
 
-         hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
 
-         hLevel = headerLevelStart,
 
-         hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
 
-     return showdown.subParser('hashBlock')(hashBlock, options, globals);
 
-   });
 
-   text = text.replace(setextRegexH2, function (matchFound, m1) {
 
-     var spanGamut = showdown.subParser('spanGamut')(m1, options, globals),
 
-         hID = (options.noHeaderId) ? '' : ' id="' + headerId(m1) + '"',
 
-         hLevel = headerLevelStart + 1,
 
-       hashBlock = '<h' + hLevel + hID + '>' + spanGamut + '</h' + hLevel + '>';
 
-     return showdown.subParser('hashBlock')(hashBlock, options, globals);
 
-   });
 
-   // atx-style headers:
 
-   //  # Header 1
 
-   //  ## Header 2
 
-   //  ## Header 2 with closing hashes ##
 
-   //  ...
 
-   //  ###### Header 6
 
-   //
 
-   text = text.replace(/^(#{1,6})[ \t]*(.+?)[ \t]*#*\n+/gm, function (wholeMatch, m1, m2) {
 
-     var span = showdown.subParser('spanGamut')(m2, options, globals),
 
-         hID = (options.noHeaderId) ? '' : ' id="' + headerId(m2) + '"',
 
-         hLevel = headerLevelStart - 1 + m1.length,
 
-         header = '<h' + hLevel + hID + '>' + span + '</h' + hLevel + '>';
 
-     return showdown.subParser('hashBlock')(header, options, globals);
 
-   });
 
-   function headerId(m) {
 
-     var title, escapedId = m.replace(/[^\w]/g, '').toLowerCase();
 
-     if (globals.hashLinkCounts[escapedId]) {
 
-       title = escapedId + '-' + (globals.hashLinkCounts[escapedId]++);
 
-     } else {
 
-       title = escapedId;
 
-       globals.hashLinkCounts[escapedId] = 1;
 
-     }
 
-     // Prefix id to prevent causing inadvertent pre-existing style matches.
 
-     if (prefixHeader === true) {
 
-       prefixHeader = 'section';
 
-     }
 
-     if (showdown.helper.isString(prefixHeader)) {
 
-       return prefixHeader + title;
 
-     }
 
-     return title;
 
-   }
 
-   text = globals.converter._dispatch('headers.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Turn Markdown image shortcuts into <img> tags.
 
-  */
 
- showdown.subParser('images', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('images.before', text, options, globals);
 
-   var inlineRegExp    = /!\[(.*?)]\s?\([ \t]*()<?(\S+?)>?(?: =([*\d]+[A-Za-z%]{0,4})x([*\d]+[A-Za-z%]{0,4}))?[ \t]*(?:(['"])(.*?)\6[ \t]*)?\)/g,
 
-       referenceRegExp = /!\[([^\]]*?)] ?(?:\n *)?\[(.*?)]()()()()()/g;
 
-   function writeImageTag (wholeMatch, altText, linkId, url, width, height, m5, title) {
 
-     var gUrls   = globals.gUrls,
 
-         gTitles = globals.gTitles,
 
-         gDims   = globals.gDimensions;
 
-     linkId = linkId.toLowerCase();
 
-     if (!title) {
 
-       title = '';
 
-     }
 
-     if (url === '' || url === null) {
 
-       if (linkId === '' || linkId === null) {
 
-         // lower-case and turn embedded newlines into spaces
 
-         linkId = altText.toLowerCase().replace(/ ?\n/g, ' ');
 
-       }
 
-       url = '#' + linkId;
 
-       if (!showdown.helper.isUndefined(gUrls[linkId])) {
 
-         url = gUrls[linkId];
 
-         if (!showdown.helper.isUndefined(gTitles[linkId])) {
 
-           title = gTitles[linkId];
 
-         }
 
-         if (!showdown.helper.isUndefined(gDims[linkId])) {
 
-           width = gDims[linkId].width;
 
-           height = gDims[linkId].height;
 
-         }
 
-       } else {
 
-         return wholeMatch;
 
-       }
 
-     }
 
-     altText = altText.replace(/"/g, '"');
 
-     altText = showdown.helper.escapeCharacters(altText, '*_', false);
 
-     url = showdown.helper.escapeCharacters(url, '*_', false);
 
-     var result = '<img src="' + url + '" alt="' + altText + '"';
 
-     if (title) {
 
-       title = title.replace(/"/g, '"');
 
-       title = showdown.helper.escapeCharacters(title, '*_', false);
 
-       result += ' title="' + title + '"';
 
-     }
 
-     if (width && height) {
 
-       width  = (width === '*') ? 'auto' : width;
 
-       height = (height === '*') ? 'auto' : height;
 
-       result += ' width="' + width + '"';
 
-       result += ' height="' + height + '"';
 
-     }
 
-     result += ' />';
 
-     return result;
 
-   }
 
-   // First, handle reference-style labeled images: ![alt text][id]
 
-   text = text.replace(referenceRegExp, writeImageTag);
 
-   // Next, handle inline images:  
 
-   text = text.replace(inlineRegExp, writeImageTag);
 
-   text = globals.converter._dispatch('images.after', text, options, globals);
 
-   return text;
 
- });
 
- showdown.subParser('italicsAndBold', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('italicsAndBold.before', text, options, globals);
 
-   if (options.literalMidWordUnderscores) {
 
-     //underscores
 
-     // Since we are consuming a \s character, we need to add it
 
-     text = text.replace(/(^|\s|>|\b)__(?=\S)([\s\S]+?)__(?=\b|<|\s|$)/gm, '$1<strong>$2</strong>');
 
-     text = text.replace(/(^|\s|>|\b)_(?=\S)([\s\S]+?)_(?=\b|<|\s|$)/gm, '$1<em>$2</em>');
 
-     //asterisks
 
-     text = text.replace(/(\*\*)(?=\S)([^\r]*?\S[*]*)\1/g, '<strong>$2</strong>');
 
-     text = text.replace(/(\*)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
 
-   } else {
 
-     // <strong> must go first:
 
-     text = text.replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, '<strong>$2</strong>');
 
-     text = text.replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g, '<em>$2</em>');
 
-   }
 
-   text = globals.converter._dispatch('italicsAndBold.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Form HTML ordered (numbered) and unordered (bulleted) lists.
 
-  */
 
- showdown.subParser('lists', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('lists.before', text, options, globals);
 
-   /**
 
-    * Process the contents of a single ordered or unordered list, splitting it
 
-    * into individual list items.
 
-    * @param {string} listStr
 
-    * @param {boolean} trimTrailing
 
-    * @returns {string}
 
-    */
 
-   function processListItems (listStr, trimTrailing) {
 
-     // The $g_list_level global keeps track of when we're inside a list.
 
-     // Each time we enter a list, we increment it; when we leave a list,
 
-     // we decrement. If it's zero, we're not in a list anymore.
 
-     //
 
-     // We do this because when we're not inside a list, we want to treat
 
-     // something like this:
 
-     //
 
-     //    I recommend upgrading to version
 
-     //    8. Oops, now this line is treated
 
-     //    as a sub-list.
 
-     //
 
-     // As a single paragraph, despite the fact that the second line starts
 
-     // with a digit-period-space sequence.
 
-     //
 
-     // Whereas when we're inside a list (or sub-list), that line will be
 
-     // treated as the start of a sub-list. What a kludge, huh? This is
 
-     // an aspect of Markdown's syntax that's hard to parse perfectly
 
-     // without resorting to mind-reading. Perhaps the solution is to
 
-     // change the syntax rules such that sub-lists must start with a
 
-     // starting cardinal number; e.g. "1." or "a.".
 
-     globals.gListLevel++;
 
-     // trim trailing blank lines:
 
-     listStr = listStr.replace(/\n{2,}$/, '\n');
 
-     // attacklab: add sentinel to emulate \z
 
-     listStr += '~0';
 
-     var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
 
-         isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
 
-     listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
 
-       checked = (checked && checked.trim() !== '');
 
-       var item = showdown.subParser('outdent')(m4, options, globals),
 
-           bulletStyle = '';
 
-       // Support for github tasklists
 
-       if (taskbtn && options.tasklists) {
 
-         bulletStyle = ' class="task-list-item" style="list-style-type: none;"';
 
-         item = item.replace(/^[ \t]*\[(x|X| )?]/m, function () {
 
-           var otp = '<input type="checkbox" disabled style="margin: 0px 0.35em 0.25em -1.6em; vertical-align: middle;"';
 
-           if (checked) {
 
-             otp += ' checked';
 
-           }
 
-           otp += '>';
 
-           return otp;
 
-         });
 
-       }
 
-       // m1 - Leading line or
 
-       // Has a double return (multi paragraph) or
 
-       // Has sublist
 
-       if (m1 || (item.search(/\n{2,}/) > -1)) {
 
-         item = showdown.subParser('githubCodeBlocks')(item, options, globals);
 
-         item = showdown.subParser('blockGamut')(item, options, globals);
 
-       } else {
 
-         // Recursion for sub-lists:
 
-         item = showdown.subParser('lists')(item, options, globals);
 
-         item = item.replace(/\n$/, ''); // chomp(item)
 
-         if (isParagraphed) {
 
-           item = showdown.subParser('paragraphs')(item, options, globals);
 
-         } else {
 
-           item = showdown.subParser('spanGamut')(item, options, globals);
 
-         }
 
-       }
 
-       item =  '\n<li' + bulletStyle + '>' + item + '</li>\n';
 
-       return item;
 
-     });
 
-     // attacklab: strip sentinel
 
-     listStr = listStr.replace(/~0/g, '');
 
-     globals.gListLevel--;
 
-     if (trimTrailing) {
 
-       listStr = listStr.replace(/\s+$/, '');
 
-     }
 
-     return listStr;
 
-   }
 
-   /**
 
-    * Check and parse consecutive lists (better fix for issue #142)
 
-    * @param {string} list
 
-    * @param {string} listType
 
-    * @param {boolean} trimTrailing
 
-    * @returns {string}
 
-    */
 
-   function parseConsecutiveLists(list, listType, trimTrailing) {
 
-     // check if we caught 2 or more consecutive lists by mistake
 
-     // we use the counterRgx, meaning if listType is UL we look for UL and vice versa
 
-     var counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm,
 
-       subLists = [],
 
-       result = '';
 
-     if (list.search(counterRxg) !== -1) {
 
-       (function parseCL(txt) {
 
-         var pos = txt.search(counterRxg);
 
-         if (pos !== -1) {
 
-           // slice
 
-           result += '\n\n<' + listType + '>' + processListItems(txt.slice(0, pos), !!trimTrailing) + '</' + listType + '>\n\n';
 
-           // invert counterType and listType
 
-           listType = (listType === 'ul') ? 'ol' : 'ul';
 
-           counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
 
-           //recurse
 
-           parseCL(txt.slice(pos));
 
-         } else {
 
-           result += '\n\n<' + listType + '>' + processListItems(txt, !!trimTrailing) + '</' + listType + '>\n\n';
 
-         }
 
-       })(list);
 
-       for (var i = 0; i < subLists.length; ++i) {
 
-       }
 
-     } else {
 
-       result = '\n\n<' + listType + '>' + processListItems(list, !!trimTrailing) + '</' + listType + '>\n\n';
 
-     }
 
-     return result;
 
-   }
 
-   // attacklab: add sentinel to hack around khtml/safari bug:
 
-   // http://bugs.webkit.org/show_bug.cgi?id=11231
 
-   text += '~0';
 
-   // Re-usable pattern to match any entire ul or ol list:
 
-   var wholeList = /^(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
 
-   if (globals.gListLevel) {
 
-     text = text.replace(wholeList, function (wholeMatch, list, m2) {
 
-       var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
 
-       return parseConsecutiveLists(list, listType, true);
 
-     });
 
-   } else {
 
-     wholeList = /(\n\n|^\n?)(([ ]{0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
 
-     //wholeList = /(\n\n|^\n?)( {0,3}([*+-]|\d+\.)[ \t]+[\s\S]+?)(?=(~0)|(\n\n(?!\t| {2,}| {0,3}([*+-]|\d+\.)[ \t])))/g;
 
-     text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
 
-       var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
 
-       return parseConsecutiveLists(list, listType);
 
-     });
 
-   }
 
-   // attacklab: strip sentinel
 
-   text = text.replace(/~0/, '');
 
-   text = globals.converter._dispatch('lists.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Remove one level of line-leading tabs or spaces
 
-  */
 
- showdown.subParser('outdent', function (text) {
 
-   'use strict';
 
-   // attacklab: hack around Konqueror 3.5.4 bug:
 
-   // "----------bug".replace(/^-/g,"") == "bug"
 
-   text = text.replace(/^(\t|[ ]{1,4})/gm, '~0'); // attacklab: g_tab_width
 
-   // attacklab: clean up hack
 
-   text = text.replace(/~0/g, '');
 
-   return text;
 
- });
 
- /**
 
-  *
 
-  */
 
- showdown.subParser('paragraphs', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('paragraphs.before', text, options, globals);
 
-   // Strip leading and trailing lines:
 
-   text = text.replace(/^\n+/g, '');
 
-   text = text.replace(/\n+$/g, '');
 
-   var grafs = text.split(/\n{2,}/g),
 
-       grafsOut = [],
 
-       end = grafs.length; // Wrap <p> tags
 
-   for (var i = 0; i < end; i++) {
 
-     var str = grafs[i];
 
-     // if this is an HTML marker, copy it
 
-     if (str.search(/~(K|G)(\d+)\1/g) >= 0) {
 
-       grafsOut.push(str);
 
-     } else {
 
-       str = showdown.subParser('spanGamut')(str, options, globals);
 
-       str = str.replace(/^([ \t]*)/g, '<p>');
 
-       str += '</p>';
 
-       grafsOut.push(str);
 
-     }
 
-   }
 
-   /** Unhashify HTML blocks */
 
-   end = grafsOut.length;
 
-   for (i = 0; i < end; i++) {
 
-     var blockText = '',
 
-         grafsOutIt = grafsOut[i],
 
-         codeFlag = false;
 
-     // if this is a marker for an html block...
 
-     while (grafsOutIt.search(/~(K|G)(\d+)\1/) >= 0) {
 
-       var delim = RegExp.$1,
 
-           num   = RegExp.$2;
 
-       if (delim === 'K') {
 
-         blockText = globals.gHtmlBlocks[num];
 
-       } else {
 
-         // we need to check if ghBlock is a false positive
 
-         if (codeFlag) {
 
-           // use encoded version of all text
 
-           blockText = showdown.subParser('encodeCode')(globals.ghCodeBlocks[num].text);
 
-         } else {
 
-           blockText = globals.ghCodeBlocks[num].codeblock;
 
-         }
 
-       }
 
-       blockText = blockText.replace(/\$/g, '$$$$'); // Escape any dollar signs
 
-       grafsOutIt = grafsOutIt.replace(/(\n\n)?~(K|G)\d+\2(\n\n)?/, blockText);
 
-       // Check if grafsOutIt is a pre->code
 
-       if (/^<pre\b[^>]*>\s*<code\b[^>]*>/.test(grafsOutIt)) {
 
-         codeFlag = true;
 
-       }
 
-     }
 
-     grafsOut[i] = grafsOutIt;
 
-   }
 
-   text = grafsOut.join('\n\n');
 
-   // Strip leading and trailing lines:
 
-   text = text.replace(/^\n+/g, '');
 
-   text = text.replace(/\n+$/g, '');
 
-   return globals.converter._dispatch('paragraphs.after', text, options, globals);
 
- });
 
- /**
 
-  * Run extension
 
-  */
 
- showdown.subParser('runExtension', function (ext, text, options, globals) {
 
-   'use strict';
 
-   if (ext.filter) {
 
-     text = ext.filter(text, globals.converter, options);
 
-   } else if (ext.regex) {
 
-     // TODO remove this when old extension loading mechanism is deprecated
 
-     var re = ext.regex;
 
-     if (!re instanceof RegExp) {
 
-       re = new RegExp(re, 'g');
 
-     }
 
-     text = text.replace(re, ext.replace);
 
-   }
 
-   return text;
 
- });
 
- /**
 
-  * These are all the transformations that occur *within* block-level
 
-  * tags like paragraphs, headers, and list items.
 
-  */
 
- showdown.subParser('spanGamut', function (text, options, globals) {
 
-   'use strict';
 
-   text = globals.converter._dispatch('spanGamut.before', text, options, globals);
 
-   text = showdown.subParser('codeSpans')(text, options, globals);
 
-   text = showdown.subParser('escapeSpecialCharsWithinTagAttributes')(text, options, globals);
 
-   text = showdown.subParser('encodeBackslashEscapes')(text, options, globals);
 
-   // Process anchor and image tags. Images must come first,
 
-   // because ![foo][f] looks like an anchor.
 
-   text = showdown.subParser('images')(text, options, globals);
 
-   text = showdown.subParser('anchors')(text, options, globals);
 
-   // Make links out of things like `<http://example.com/>`
 
-   // Must come after _DoAnchors(), because you can use < and >
 
-   // delimiters in inline links like [this](<url>).
 
-   text = showdown.subParser('autoLinks')(text, options, globals);
 
-   text = showdown.subParser('encodeAmpsAndAngles')(text, options, globals);
 
-   text = showdown.subParser('italicsAndBold')(text, options, globals);
 
-   text = showdown.subParser('strikethrough')(text, options, globals);
 
-   // Do hard breaks:
 
-   text = text.replace(/  +\n/g, ' <br />\n');
 
-   text = globals.converter._dispatch('spanGamut.after', text, options, globals);
 
-   return text;
 
- });
 
- showdown.subParser('strikethrough', function (text, options, globals) {
 
-   'use strict';
 
-   if (options.strikethrough) {
 
-     text = globals.converter._dispatch('strikethrough.before', text, options, globals);
 
-     text = text.replace(/(?:~T){2}([\s\S]+?)(?:~T){2}/g, '<del>$1</del>');
 
-     text = globals.converter._dispatch('strikethrough.after', text, options, globals);
 
-   }
 
-   return text;
 
- });
 
- /**
 
-  * Strip any lines consisting only of spaces and tabs.
 
-  * This makes subsequent regexs easier to write, because we can
 
-  * match consecutive blank lines with /\n+/ instead of something
 
-  * contorted like /[ \t]*\n+/
 
-  */
 
- showdown.subParser('stripBlankLines', function (text) {
 
-   'use strict';
 
-   return text.replace(/^[ \t]+$/mg, '');
 
- });
 
- /**
 
-  * Strips link definitions from text, stores the URLs and titles in
 
-  * hash references.
 
-  * Link defs are in the form: ^[id]: url "optional title"
 
-  *
 
-  * ^[ ]{0,3}\[(.+)\]: // id = $1  attacklab: g_tab_width - 1
 
-  * [ \t]*
 
-  * \n?                  // maybe *one* newline
 
-  * [ \t]*
 
-  * <?(\S+?)>?          // url = $2
 
-  * [ \t]*
 
-  * \n?                // maybe one newline
 
-  * [ \t]*
 
-  * (?:
 
-  * (\n*)              // any lines skipped = $3 attacklab: lookbehind removed
 
-  * ["(]
 
-  * (.+?)              // title = $4
 
-  * [")]
 
-  * [ \t]*
 
-  * )?                 // title is optional
 
-  * (?:\n+|$)
 
-  * /gm,
 
-  * function(){...});
 
-  *
 
-  */
 
- showdown.subParser('stripLinkDefinitions', function (text, options, globals) {
 
-   'use strict';
 
-   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;
 
-   // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
 
-   text += '~0';
 
-   text = text.replace(regex, function (wholeMatch, linkId, url, width, height, blankLines, title) {
 
-     linkId = linkId.toLowerCase();
 
-     globals.gUrls[linkId] = showdown.subParser('encodeAmpsAndAngles')(url);  // Link IDs are case-insensitive
 
-     if (blankLines) {
 
-       // Oops, found blank lines, so it's not a title.
 
-       // Put back the parenthetical statement we stole.
 
-       return blankLines + title;
 
-     } else {
 
-       if (title) {
 
-         globals.gTitles[linkId] = title.replace(/"|'/g, '"');
 
-       }
 
-       if (options.parseImgDimensions && width && height) {
 
-         globals.gDimensions[linkId] = {
 
-           width:  width,
 
-           height: height
 
-         };
 
-       }
 
-     }
 
-     // Completely remove the definition from the text
 
-     return '';
 
-   });
 
-   // attacklab: strip sentinel
 
-   text = text.replace(/~0/, '');
 
-   return text;
 
- });
 
- showdown.subParser('tables', function (text, options, globals) {
 
-   'use strict';
 
-   if (!options.tables) {
 
-     return text;
 
-   }
 
-   var tableRgx = /^[ \t]{0,3}\|?.+\|.+\n[ \t]{0,3}\|?[ \t]*:?[ \t]*(?:-|=){2,}[ \t]*:?[ \t]*\|[ \t]*:?[ \t]*(?:-|=){2,}[\s\S]+?(?:\n\n|~0)/gm;
 
-   function parseStyles(sLine) {
 
-     if (/^:[ \t]*--*$/.test(sLine)) {
 
-       return ' style="text-align:left;"';
 
-     } else if (/^--*[ \t]*:[ \t]*$/.test(sLine)) {
 
-       return ' style="text-align:right;"';
 
-     } else if (/^:[ \t]*--*[ \t]*:$/.test(sLine)) {
 
-       return ' style="text-align:center;"';
 
-     } else {
 
-       return '';
 
-     }
 
-   }
 
-   function parseHeaders(header, style) {
 
-     var id = '';
 
-     header = header.trim();
 
-     if (options.tableHeaderId) {
 
-       id = ' id="' + header.replace(/ /g, '_').toLowerCase() + '"';
 
-     }
 
-     header = showdown.subParser('spanGamut')(header, options, globals);
 
-     return '<th' + id + style + '>' + header + '</th>\n';
 
-   }
 
-   function parseCells(cell, style) {
 
-     var subText = showdown.subParser('spanGamut')(cell, options, globals);
 
-     return '<td' + style + '>' + subText + '</td>\n';
 
-   }
 
-   function buildTable(headers, cells) {
 
-     var tb = '<table>\n<thead>\n<tr>\n',
 
-         tblLgn = headers.length;
 
-     for (var i = 0; i < tblLgn; ++i) {
 
-       tb += headers[i];
 
-     }
 
-     tb += '</tr>\n</thead>\n<tbody>\n';
 
-     for (i = 0; i < cells.length; ++i) {
 
-       tb += '<tr>\n';
 
-       for (var ii = 0; ii < tblLgn; ++ii) {
 
-         tb += cells[i][ii];
 
-       }
 
-       tb += '</tr>\n';
 
-     }
 
-     tb += '</tbody>\n</table>\n';
 
-     return tb;
 
-   }
 
-   text = globals.converter._dispatch('tables.before', text, options, globals);
 
-   text = text.replace(tableRgx, function (rawTable) {
 
-     var i, tableLines = rawTable.split('\n');
 
-     // strip wrong first and last column if wrapped tables are used
 
-     for (i = 0; i < tableLines.length; ++i) {
 
-       if (/^[ \t]{0,3}\|/.test(tableLines[i])) {
 
-         tableLines[i] = tableLines[i].replace(/^[ \t]{0,3}\|/, '');
 
-       }
 
-       if (/\|[ \t]*$/.test(tableLines[i])) {
 
-         tableLines[i] = tableLines[i].replace(/\|[ \t]*$/, '');
 
-       }
 
-     }
 
-     var rawHeaders = tableLines[0].split('|').map(function (s) { return s.trim();}),
 
-         rawStyles = tableLines[1].split('|').map(function (s) { return s.trim();}),
 
-         rawCells = [],
 
-         headers = [],
 
-         styles = [],
 
-         cells = [];
 
-     tableLines.shift();
 
-     tableLines.shift();
 
-     for (i = 0; i < tableLines.length; ++i) {
 
-       if (tableLines[i].trim() === '') {
 
-         continue;
 
-       }
 
-       rawCells.push(
 
-         tableLines[i]
 
-           .split('|')
 
-           .map(function (s) {
 
-             return s.trim();
 
-           })
 
-       );
 
-     }
 
-     if (rawHeaders.length < rawStyles.length) {
 
-       return rawTable;
 
-     }
 
-     for (i = 0; i < rawStyles.length; ++i) {
 
-       styles.push(parseStyles(rawStyles[i]));
 
-     }
 
-     for (i = 0; i < rawHeaders.length; ++i) {
 
-       if (showdown.helper.isUndefined(styles[i])) {
 
-         styles[i] = '';
 
-       }
 
-       headers.push(parseHeaders(rawHeaders[i], styles[i]));
 
-     }
 
-     for (i = 0; i < rawCells.length; ++i) {
 
-       var row = [];
 
-       for (var ii = 0; ii < headers.length; ++ii) {
 
-         if (showdown.helper.isUndefined(rawCells[i][ii])) {
 
-         }
 
-         row.push(parseCells(rawCells[i][ii], styles[ii]));
 
-       }
 
-       cells.push(row);
 
-     }
 
-     return buildTable(headers, cells);
 
-   });
 
-   text = globals.converter._dispatch('tables.after', text, options, globals);
 
-   return text;
 
- });
 
- /**
 
-  * Swap back in all the special characters we've hidden.
 
-  */
 
- showdown.subParser('unescapeSpecialChars', function (text) {
 
-   'use strict';
 
-   text = text.replace(/~E(\d+)E/g, function (wholeMatch, m1) {
 
-     var charCodeToReplace = parseInt(m1);
 
-     return String.fromCharCode(charCodeToReplace);
 
-   });
 
-   return text;
 
- });
 
- module.exports = showdown;
 
 
  |