2015-05-04 03:53:29 -04:00
/*! remarkable 1.5.0 https://github.com//jonschlinkert/remarkable @license MIT */ ! function ( e ) { if ( "object" == typeof exports && "undefined" != typeof module ) module . exports = e ( ) ; else if ( "function" == typeof define && define . amd ) define ( [ ] , e ) ; else { var f ; "undefined" != typeof window ? f = window : "undefined" != typeof global ? f = global : "undefined" != typeof self && ( f = self ) , f . Remarkable = e ( ) } } ( function ( ) { var define , module , exports ; return ( function e ( t , n , r ) { function s ( o , u ) { if ( ! n [ o ] ) { if ( ! t [ o ] ) { var a = typeof require == "function" && require ; if ( ! u && a ) return a ( o , ! 0 ) ; if ( i ) return i ( o , ! 0 ) ; var f = new Error ( "Cannot find module '" + o + "'" ) ; throw f . code = "MODULE_NOT_FOUND" , f } var l = n [ o ] = { exports : { } } ; t [ o ] [ 0 ] . call ( l . exports , function ( e ) { var n = t [ o ] [ 1 ] [ e ] ; return s ( n ? n : e ) } , l , l . exports , e , t , n , r ) } return n [ o ] . exports } var i = typeof require == "function" && require ; for ( var o = 0 ; o < r . length ; o ++ ) s ( r [ o ] ) ; return s } ) ( { 1 : [ function ( require , module , exports ) {
// List of valid entities
//
// Generate with ./support/entities.js script
//
'use strict' ;
/*eslint quotes:0*/
module . exports = {
"Aacute" : "\u00C1" ,
"aacute" : "\u00E1" ,
"Abreve" : "\u0102" ,
"abreve" : "\u0103" ,
"ac" : "\u223E" ,
"acd" : "\u223F" ,
"acE" : "\u223E\u0333" ,
"Acirc" : "\u00C2" ,
"acirc" : "\u00E2" ,
"acute" : "\u00B4" ,
"Acy" : "\u0410" ,
"acy" : "\u0430" ,
"AElig" : "\u00C6" ,
"aelig" : "\u00E6" ,
"af" : "\u2061" ,
"Afr" : "\uD835\uDD04" ,
"afr" : "\uD835\uDD1E" ,
"Agrave" : "\u00C0" ,
"agrave" : "\u00E0" ,
"alefsym" : "\u2135" ,
"aleph" : "\u2135" ,
"Alpha" : "\u0391" ,
"alpha" : "\u03B1" ,
"Amacr" : "\u0100" ,
"amacr" : "\u0101" ,
"amalg" : "\u2A3F" ,
"AMP" : "\u0026" ,
"amp" : "\u0026" ,
"And" : "\u2A53" ,
"and" : "\u2227" ,
"andand" : "\u2A55" ,
"andd" : "\u2A5C" ,
"andslope" : "\u2A58" ,
"andv" : "\u2A5A" ,
"ang" : "\u2220" ,
"ange" : "\u29A4" ,
"angle" : "\u2220" ,
"angmsd" : "\u2221" ,
"angmsdaa" : "\u29A8" ,
"angmsdab" : "\u29A9" ,
"angmsdac" : "\u29AA" ,
"angmsdad" : "\u29AB" ,
"angmsdae" : "\u29AC" ,
"angmsdaf" : "\u29AD" ,
"angmsdag" : "\u29AE" ,
"angmsdah" : "\u29AF" ,
"angrt" : "\u221F" ,
"angrtvb" : "\u22BE" ,
"angrtvbd" : "\u299D" ,
"angsph" : "\u2222" ,
"angst" : "\u00C5" ,
"angzarr" : "\u237C" ,
"Aogon" : "\u0104" ,
"aogon" : "\u0105" ,
"Aopf" : "\uD835\uDD38" ,
"aopf" : "\uD835\uDD52" ,
"ap" : "\u2248" ,
"apacir" : "\u2A6F" ,
"apE" : "\u2A70" ,
"ape" : "\u224A" ,
"apid" : "\u224B" ,
"apos" : "\u0027" ,
"ApplyFunction" : "\u2061" ,
"approx" : "\u2248" ,
"approxeq" : "\u224A" ,
"Aring" : "\u00C5" ,
"aring" : "\u00E5" ,
"Ascr" : "\uD835\uDC9C" ,
"ascr" : "\uD835\uDCB6" ,
"Assign" : "\u2254" ,
"ast" : "\u002A" ,
"asymp" : "\u2248" ,
"asympeq" : "\u224D" ,
"Atilde" : "\u00C3" ,
"atilde" : "\u00E3" ,
"Auml" : "\u00C4" ,
"auml" : "\u00E4" ,
"awconint" : "\u2233" ,
"awint" : "\u2A11" ,
"backcong" : "\u224C" ,
"backepsilon" : "\u03F6" ,
"backprime" : "\u2035" ,
"backsim" : "\u223D" ,
"backsimeq" : "\u22CD" ,
"Backslash" : "\u2216" ,
"Barv" : "\u2AE7" ,
"barvee" : "\u22BD" ,
"Barwed" : "\u2306" ,
"barwed" : "\u2305" ,
"barwedge" : "\u2305" ,
"bbrk" : "\u23B5" ,
"bbrktbrk" : "\u23B6" ,
"bcong" : "\u224C" ,
"Bcy" : "\u0411" ,
"bcy" : "\u0431" ,
"bdquo" : "\u201E" ,
"becaus" : "\u2235" ,
"Because" : "\u2235" ,
"because" : "\u2235" ,
"bemptyv" : "\u29B0" ,
"bepsi" : "\u03F6" ,
"bernou" : "\u212C" ,
"Bernoullis" : "\u212C" ,
"Beta" : "\u0392" ,
"beta" : "\u03B2" ,
"beth" : "\u2136" ,
"between" : "\u226C" ,
"Bfr" : "\uD835\uDD05" ,
"bfr" : "\uD835\uDD1F" ,
"bigcap" : "\u22C2" ,
"bigcirc" : "\u25EF" ,
"bigcup" : "\u22C3" ,
"bigodot" : "\u2A00" ,
"bigoplus" : "\u2A01" ,
"bigotimes" : "\u2A02" ,
"bigsqcup" : "\u2A06" ,
"bigstar" : "\u2605" ,
"bigtriangledown" : "\u25BD" ,
"bigtriangleup" : "\u25B3" ,
"biguplus" : "\u2A04" ,
"bigvee" : "\u22C1" ,
"bigwedge" : "\u22C0" ,
"bkarow" : "\u290D" ,
"blacklozenge" : "\u29EB" ,
"blacksquare" : "\u25AA" ,
"blacktriangle" : "\u25B4" ,
"blacktriangledown" : "\u25BE" ,
"blacktriangleleft" : "\u25C2" ,
"blacktriangleright" : "\u25B8" ,
"blank" : "\u2423" ,
"blk12" : "\u2592" ,
"blk14" : "\u2591" ,
"blk34" : "\u2593" ,
"block" : "\u2588" ,
"bne" : "\u003D\u20E5" ,
"bnequiv" : "\u2261\u20E5" ,
"bNot" : "\u2AED" ,
"bnot" : "\u2310" ,
"Bopf" : "\uD835\uDD39" ,
"bopf" : "\uD835\uDD53" ,
"bot" : "\u22A5" ,
"bottom" : "\u22A5" ,
"bowtie" : "\u22C8" ,
"boxbox" : "\u29C9" ,
"boxDL" : "\u2557" ,
"boxDl" : "\u2556" ,
"boxdL" : "\u2555" ,
"boxdl" : "\u2510" ,
"boxDR" : "\u2554" ,
"boxDr" : "\u2553" ,
"boxdR" : "\u2552" ,
"boxdr" : "\u250C" ,
"boxH" : "\u2550" ,
"boxh" : "\u2500" ,
"boxHD" : "\u2566" ,
"boxHd" : "\u2564" ,
"boxhD" : "\u2565" ,
"boxhd" : "\u252C" ,
"boxHU" : "\u2569" ,
"boxHu" : "\u2567" ,
"boxhU" : "\u2568" ,
"boxhu" : "\u2534" ,
"boxminus" : "\u229F" ,
"boxplus" : "\u229E" ,
"boxtimes" : "\u22A0" ,
"boxUL" : "\u255D" ,
"boxUl" : "\u255C" ,
"boxuL" : "\u255B" ,
"boxul" : "\u2518" ,
"boxUR" : "\u255A" ,
"boxUr" : "\u2559" ,
"boxuR" : "\u2558" ,
"boxur" : "\u2514" ,
"boxV" : "\u2551" ,
"boxv" : "\u2502" ,
"boxVH" : "\u256C" ,
"boxVh" : "\u256B" ,
"boxvH" : "\u256A" ,
"boxvh" : "\u253C" ,
"boxVL" : "\u2563" ,
"boxVl" : "\u2562" ,
"boxvL" : "\u2561" ,
"boxvl" : "\u2524" ,
"boxVR" : "\u2560" ,
"boxVr" : "\u255F" ,
"boxvR" : "\u255E" ,
"boxvr" : "\u251C" ,
"bprime" : "\u2035" ,
"Breve" : "\u02D8" ,
"breve" : "\u02D8" ,
"brvbar" : "\u00A6" ,
"Bscr" : "\u212C" ,
"bscr" : "\uD835\uDCB7" ,
"bsemi" : "\u204F" ,
"bsim" : "\u223D" ,
"bsime" : "\u22CD" ,
"bsol" : "\u005C" ,
"bsolb" : "\u29C5" ,
"bsolhsub" : "\u27C8" ,
"bull" : "\u2022" ,
"bullet" : "\u2022" ,
"bump" : "\u224E" ,
"bumpE" : "\u2AAE" ,
"bumpe" : "\u224F" ,
"Bumpeq" : "\u224E" ,
"bumpeq" : "\u224F" ,
"Cacute" : "\u0106" ,
"cacute" : "\u0107" ,
"Cap" : "\u22D2" ,
"cap" : "\u2229" ,
"capand" : "\u2A44" ,
"capbrcup" : "\u2A49" ,
"capcap" : "\u2A4B" ,
"capcup" : "\u2A47" ,
"capdot" : "\u2A40" ,
"CapitalDifferentialD" : "\u2145" ,
"caps" : "\u2229\uFE00" ,
"caret" : "\u2041" ,
"caron" : "\u02C7" ,
"Cayleys" : "\u212D" ,
"ccaps" : "\u2A4D" ,
"Ccaron" : "\u010C" ,
"ccaron" : "\u010D" ,
"Ccedil" : "\u00C7" ,
"ccedil" : "\u00E7" ,
"Ccirc" : "\u0108" ,
"ccirc" : "\u0109" ,
"Cconint" : "\u2230" ,
"ccups" : "\u2A4C" ,
"ccupssm" : "\u2A50" ,
"Cdot" : "\u010A" ,
"cdot" : "\u010B" ,
"cedil" : "\u00B8" ,
"Cedilla" : "\u00B8" ,
"cemptyv" : "\u29B2" ,
"cent" : "\u00A2" ,
"CenterDot" : "\u00B7" ,
"centerdot" : "\u00B7" ,
"Cfr" : "\u212D" ,
"cfr" : "\uD835\uDD20" ,
"CHcy" : "\u0427" ,
"chcy" : "\u0447" ,
"check" : "\u2713" ,
"checkmark" : "\u2713" ,
"Chi" : "\u03A7" ,
"chi" : "\u03C7" ,
"cir" : "\u25CB" ,
"circ" : "\u02C6" ,
"circeq" : "\u2257" ,
"circlearrowleft" : "\u21BA" ,
"circlearrowright" : "\u21BB" ,
"circledast" : "\u229B" ,
"circledcirc" : "\u229A" ,
"circleddash" : "\u229D" ,
"CircleDot" : "\u2299" ,
"circledR" : "\u00AE" ,
"circledS" : "\u24C8" ,
"CircleMinus" : "\u2296" ,
"CirclePlus" : "\u2295" ,
"CircleTimes" : "\u2297" ,
"cirE" : "\u29C3" ,
"cire" : "\u2257" ,
"cirfnint" : "\u2A10" ,
"cirmid" : "\u2AEF" ,
"cirscir" : "\u29C2" ,
"ClockwiseContourIntegral" : "\u2232" ,
"CloseCurlyDoubleQuote" : "\u201D" ,
"CloseCurlyQuote" : "\u2019" ,
"clubs" : "\u2663" ,
"clubsuit" : "\u2663" ,
"Colon" : "\u2237" ,
"colon" : "\u003A" ,
"Colone" : "\u2A74" ,
"colone" : "\u2254" ,
"coloneq" : "\u2254" ,
"comma" : "\u002C" ,
"commat" : "\u0040" ,
"comp" : "\u2201" ,
"compfn" : "\u2218" ,
"complement" : "\u2201" ,
"complexes" : "\u2102" ,
"cong" : "\u2245" ,
"congdot" : "\u2A6D" ,
"Congruent" : "\u2261" ,
"Conint" : "\u222F" ,
"conint" : "\u222E" ,
"ContourIntegral" : "\u222E" ,
"Copf" : "\u2102" ,
"copf" : "\uD835\uDD54" ,
"coprod" : "\u2210" ,
"Coproduct" : "\u2210" ,
"COPY" : "\u00A9" ,
"copy" : "\u00A9" ,
"copysr" : "\u2117" ,
"CounterClockwiseContourIntegral" : "\u2233" ,
"crarr" : "\u21B5" ,
"Cross" : "\u2A2F" ,
"cross" : "\u2717" ,
"Cscr" : "\uD835\uDC9E" ,
"cscr" : "\uD835\uDCB8" ,
"csub" : "\u2ACF" ,
"csube" : "\u2AD1" ,
"csup" : "\u2AD0" ,
"csupe" : "\u2AD2" ,
"ctdot" : "\u22EF" ,
"cudarrl" : "\u2938" ,
"cudarrr" : "\u2935" ,
"cuepr" : "\u22DE" ,
"cuesc" : "\u22DF" ,
"cularr" : "\u21B6" ,
"cularrp" : "\u293D" ,
"Cup" : "\u22D3" ,
"cup" : "\u222A" ,
"cupbrcap" : "\u2A48" ,
"CupCap" : "\u224D" ,
"cupcap" : "\u2A46" ,
"cupcup" : "\u2A4A" ,
"cupdot" : "\u228D" ,
"cupor" : "\u2A45" ,
"cups" : "\u222A\uFE00" ,
"curarr" : "\u21B7" ,
"curarrm" : "\u293C" ,
"curlyeqprec" : "\u22DE" ,
"curlyeqsucc" : "\u22DF" ,
"curlyvee" : "\u22CE" ,
"curlywedge" : "\u22CF" ,
"curren" : "\u00A4" ,
"curvearrowleft" : "\u21B6" ,
"curvearrowright" : "\u21B7" ,
"cuvee" : "\u22CE" ,
"cuwed" : "\u22CF" ,
"cwconint" : "\u2232" ,
"cwint" : "\u2231" ,
"cylcty" : "\u232D" ,
"Dagger" : "\u2021" ,
"dagger" : "\u2020" ,
"daleth" : "\u2138" ,
"Darr" : "\u21A1" ,
"dArr" : "\u21D3" ,
"darr" : "\u2193" ,
"dash" : "\u2010" ,
"Dashv" : "\u2AE4" ,
"dashv" : "\u22A3" ,
"dbkarow" : "\u290F" ,
"dblac" : "\u02DD" ,
"Dcaron" : "\u010E" ,
"dcaron" : "\u010F" ,
"Dcy" : "\u0414" ,
"dcy" : "\u0434" ,
"DD" : "\u2145" ,
"dd" : "\u2146" ,
"ddagger" : "\u2021" ,
"ddarr" : "\u21CA" ,
"DDotrahd" : "\u2911" ,
"ddotseq" : "\u2A77" ,
"deg" : "\u00B0" ,
"Del" : "\u2207" ,
"Delta" : "\u0394" ,
"delta" : "\u03B4" ,
"demptyv" : "\u29B1" ,
"dfisht" : "\u297F" ,
"Dfr" : "\uD835\uDD07" ,
"dfr" : "\uD835\uDD21" ,
"dHar" : "\u2965" ,
"dharl" : "\u21C3" ,
"dharr" : "\u21C2" ,
"DiacriticalAcute" : "\u00B4" ,
"DiacriticalDot" : "\u02D9" ,
"DiacriticalDoubleAcute" : "\u02DD" ,
"DiacriticalGrave" : "\u0060" ,
"DiacriticalTilde" : "\u02DC" ,
"diam" : "\u22C4" ,
"Diamond" : "\u22C4" ,
"diamond" : "\u22C4" ,
"diamondsuit" : "\u2666" ,
"diams" : "\u2666" ,
"die" : "\u00A8" ,
"DifferentialD" : "\u2146" ,
"digamma" : "\u03DD" ,
"disin" : "\u22F2" ,
"div" : "\u00F7" ,
"divide" : "\u00F7" ,
"divideontimes" : "\u22C7" ,
"divonx" : "\u22C7" ,
"DJcy" : "\u0402" ,
"djcy" : "\u0452" ,
"dlcorn" : "\u231E" ,
"dlcrop" : "\u230D" ,
"dollar" : "\u0024" ,
"Dopf" : "\uD835\uDD3B" ,
"dopf" : "\uD835\uDD55" ,
"Dot" : "\u00A8" ,
"dot" : "\u02D9" ,
"DotDot" : "\u20DC" ,
"doteq" : "\u2250" ,
"doteqdot" : "\u2251" ,
"DotEqual" : "\u2250" ,
"dotminus" : "\u2238" ,
"dotplus" : "\u2214" ,
"dotsquare" : "\u22A1" ,
"doublebarwedge" : "\u2306" ,
"DoubleContourIntegral" : "\u222F" ,
"DoubleDot" : "\u00A8" ,
"DoubleDownArrow" : "\u21D3" ,
"DoubleLeftArrow" : "\u21D0" ,
"DoubleLeftRightArrow" : "\u21D4" ,
"DoubleLeftTee" : "\u2AE4" ,
"DoubleLongLeftArrow" : "\u27F8" ,
"DoubleLongLeftRightArrow" : "\u27FA" ,
"DoubleLongRightArrow" : "\u27F9" ,
"DoubleRightArrow" : "\u21D2" ,
"DoubleRightTee" : "\u22A8" ,
"DoubleUpArrow" : "\u21D1" ,
"DoubleUpDownArrow" : "\u21D5" ,
"DoubleVerticalBar" : "\u2225" ,
"DownArrow" : "\u2193" ,
"Downarrow" : "\u21D3" ,
"downarrow" : "\u2193" ,
"DownArrowBar" : "\u2913" ,
"DownArrowUpArrow" : "\u21F5" ,
"DownBreve" : "\u0311" ,
"downdownarrows" : "\u21CA" ,
"downharpoonleft" : "\u21C3" ,
"downharpoonright" : "\u21C2" ,
"DownLeftRightVector" : "\u2950" ,
"DownLeftTeeVector" : "\u295E" ,
"DownLeftVector" : "\u21BD" ,
"DownLeftVectorBar" : "\u2956" ,
"DownRightTeeVector" : "\u295F" ,
"DownRightVector" : "\u21C1" ,
"DownRightVectorBar" : "\u2957" ,
"DownTee" : "\u22A4" ,
"DownTeeArrow" : "\u21A7" ,
"drbkarow" : "\u2910" ,
"drcorn" : "\u231F" ,
"drcrop" : "\u230C" ,
"Dscr" : "\uD835\uDC9F" ,
"dscr" : "\uD835\uDCB9" ,
"DScy" : "\u0405" ,
"dscy" : "\u0455" ,
"dsol" : "\u29F6" ,
"Dstrok" : "\u0110" ,
"dstrok" : "\u0111" ,
"dtdot" : "\u22F1" ,
"dtri" : "\u25BF" ,
"dtrif" : "\u25BE" ,
"duarr" : "\u21F5" ,
"duhar" : "\u296F" ,
"dwangle" : "\u29A6" ,
"DZcy" : "\u040F" ,
"dzcy" : "\u045F" ,
"dzigrarr" : "\u27FF" ,
"Eacute" : "\u00C9" ,
"eacute" : "\u00E9" ,
"easter" : "\u2A6E" ,
"Ecaron" : "\u011A" ,
"ecaron" : "\u011B" ,
"ecir" : "\u2256" ,
"Ecirc" : "\u00CA" ,
"ecirc" : "\u00EA" ,
"ecolon" : "\u2255" ,
"Ecy" : "\u042D" ,
"ecy" : "\u044D" ,
"eDDot" : "\u2A77" ,
"Edot" : "\u0116" ,
"eDot" : "\u2251" ,
"edot" : "\u0117" ,
"ee" : "\u2147" ,
"efDot" : "\u2252" ,
"Efr" : "\uD835\uDD08" ,
"efr" : "\uD835\uDD22" ,
"eg" : "\u2A9A" ,
"Egrave" : "\u00C8" ,
"egrave" : "\u00E8" ,
"egs" : "\u2A96" ,
"egsdot" : "\u2A98" ,
"el" : "\u2A99" ,
"Element" : "\u2208" ,
"elinters" : "\u23E7" ,
"ell" : "\u2113" ,
"els" : "\u2A95" ,
"elsdot" : "\u2A97" ,
"Emacr" : "\u0112" ,
"emacr" : "\u0113" ,
"empty" : "\u2205" ,
"emptyset" : "\u2205" ,
"EmptySmallSquare" : "\u25FB" ,
"emptyv" : "\u2205" ,
"EmptyVerySmallSquare" : "\u25AB" ,
"emsp" : "\u2003" ,
"emsp13" : "\u2004" ,
"emsp14" : "\u2005" ,
"ENG" : "\u014A" ,
"eng" : "\u014B" ,
"ensp" : "\u2002" ,
"Eogon" : "\u0118" ,
"eogon" : "\u0119" ,
"Eopf" : "\uD835\uDD3C" ,
"eopf" : "\uD835\uDD56" ,
"epar" : "\u22D5" ,
"eparsl" : "\u29E3" ,
"eplus" : "\u2A71" ,
"epsi" : "\u03B5" ,
"Epsilon" : "\u0395" ,
"epsilon" : "\u03B5" ,
"epsiv" : "\u03F5" ,
"eqcirc" : "\u2256" ,
"eqcolon" : "\u2255" ,
"eqsim" : "\u2242" ,
"eqslantgtr" : "\u2A96" ,
"eqslantless" : "\u2A95" ,
"Equal" : "\u2A75" ,
"equals" : "\u003D" ,
"EqualTilde" : "\u2242" ,
"equest" : "\u225F" ,
"Equilibrium" : "\u21CC" ,
"equiv" : "\u2261" ,
"equivDD" : "\u2A78" ,
"eqvparsl" : "\u29E5" ,
"erarr" : "\u2971" ,
"erDot" : "\u2253" ,
"Escr" : "\u2130" ,
"escr" : "\u212F" ,
"esdot" : "\u2250" ,
"Esim" : "\u2A73" ,
"esim" : "\u2242" ,
"Eta" : "\u0397" ,
"eta" : "\u03B7" ,
"ETH" : "\u00D0" ,
"eth" : "\u00F0" ,
"Euml" : "\u00CB" ,
"euml" : "\u00EB" ,
"euro" : "\u20AC" ,
"excl" : "\u0021" ,
"exist" : "\u2203" ,
"Exists" : "\u2203" ,
"expectation" : "\u2130" ,
"ExponentialE" : "\u2147" ,
"exponentiale" : "\u2147" ,
"fallingdotseq" : "\u2252" ,
"Fcy" : "\u0424" ,
"fcy" : "\u0444" ,
"female" : "\u2640" ,
"ffilig" : "\uFB03" ,
"fflig" : "\uFB00" ,
"ffllig" : "\uFB04" ,
"Ffr" : "\uD835\uDD09" ,
"ffr" : "\uD835\uDD23" ,
"filig" : "\uFB01" ,
"FilledSmallSquare" : "\u25FC" ,
"FilledVerySmallSquare" : "\u25AA" ,
"fjlig" : "\u0066\u006A" ,
"flat" : "\u266D" ,
"fllig" : "\uFB02" ,
"fltns" : "\u25B1" ,
"fnof" : "\u0192" ,
"Fopf" : "\uD835\uDD3D" ,
"fopf" : "\uD835\uDD57" ,
"ForAll" : "\u2200" ,
"forall" : "\u2200" ,
"fork" : "\u22D4" ,
"forkv" : "\u2AD9" ,
"Fouriertrf" : "\u2131" ,
"fpartint" : "\u2A0D" ,
"frac12" : "\u00BD" ,
"frac13" : "\u2153" ,
"frac14" : "\u00BC" ,
"frac15" : "\u2155" ,
"frac16" : "\u2159" ,
"frac18" : "\u215B" ,
"frac23" : "\u2154" ,
"frac25" : "\u2156" ,
"frac34" : "\u00BE" ,
"frac35" : "\u2157" ,
"frac38" : "\u215C" ,
"frac45" : "\u2158" ,
"frac56" : "\u215A" ,
"frac58" : "\u215D" ,
"frac78" : "\u215E" ,
"frasl" : "\u2044" ,
"frown" : "\u2322" ,
"Fscr" : "\u2131" ,
"fscr" : "\uD835\uDCBB" ,
"gacute" : "\u01F5" ,
"Gamma" : "\u0393" ,
"gamma" : "\u03B3" ,
"Gammad" : "\u03DC" ,
"gammad" : "\u03DD" ,
"gap" : "\u2A86" ,
"Gbreve" : "\u011E" ,
"gbreve" : "\u011F" ,
"Gcedil" : "\u0122" ,
"Gcirc" : "\u011C" ,
"gcirc" : "\u011D" ,
"Gcy" : "\u0413" ,
"gcy" : "\u0433" ,
"Gdot" : "\u0120" ,
"gdot" : "\u0121" ,
"gE" : "\u2267" ,
"ge" : "\u2265" ,
"gEl" : "\u2A8C" ,
"gel" : "\u22DB" ,
"geq" : "\u2265" ,
"geqq" : "\u2267" ,
"geqslant" : "\u2A7E" ,
"ges" : "\u2A7E" ,
"gescc" : "\u2AA9" ,
"gesdot" : "\u2A80" ,
"gesdoto" : "\u2A82" ,
"gesdotol" : "\u2A84" ,
"gesl" : "\u22DB\uFE00" ,
"gesles" : "\u2A94" ,
"Gfr" : "\uD835\uDD0A" ,
"gfr" : "\uD835\uDD24" ,
"Gg" : "\u22D9" ,
"gg" : "\u226B" ,
"ggg" : "\u22D9" ,
"gimel" : "\u2137" ,
"GJcy" : "\u0403" ,
"gjcy" : "\u0453" ,
"gl" : "\u2277" ,
"gla" : "\u2AA5" ,
"glE" : "\u2A92" ,
"glj" : "\u2AA4" ,
"gnap" : "\u2A8A" ,
"gnapprox" : "\u2A8A" ,
"gnE" : "\u2269" ,
"gne" : "\u2A88" ,
"gneq" : "\u2A88" ,
"gneqq" : "\u2269" ,
"gnsim" : "\u22E7" ,
"Gopf" : "\uD835\uDD3E" ,
"gopf" : "\uD835\uDD58" ,
"grave" : "\u0060" ,
"GreaterEqual" : "\u2265" ,
"GreaterEqualLess" : "\u22DB" ,
"GreaterFullEqual" : "\u2267" ,
"GreaterGreater" : "\u2AA2" ,
"GreaterLess" : "\u2277" ,
"GreaterSlantEqual" : "\u2A7E" ,
"GreaterTilde" : "\u2273" ,
"Gscr" : "\uD835\uDCA2" ,
"gscr" : "\u210A" ,
"gsim" : "\u2273" ,
"gsime" : "\u2A8E" ,
"gsiml" : "\u2A90" ,
"GT" : "\u003E" ,
"Gt" : "\u226B" ,
"gt" : "\u003E" ,
"gtcc" : "\u2AA7" ,
"gtcir" : "\u2A7A" ,
"gtdot" : "\u22D7" ,
"gtlPar" : "\u2995" ,
"gtquest" : "\u2A7C" ,
"gtrapprox" : "\u2A86" ,
"gtrarr" : "\u2978" ,
"gtrdot" : "\u22D7" ,
"gtreqless" : "\u22DB" ,
"gtreqqless" : "\u2A8C" ,
"gtrless" : "\u2277" ,
"gtrsim" : "\u2273" ,
"gvertneqq" : "\u2269\uFE00" ,
"gvnE" : "\u2269\uFE00" ,
"Hacek" : "\u02C7" ,
"hairsp" : "\u200A" ,
"half" : "\u00BD" ,
"hamilt" : "\u210B" ,
"HARDcy" : "\u042A" ,
"hardcy" : "\u044A" ,
"hArr" : "\u21D4" ,
"harr" : "\u2194" ,
"harrcir" : "\u2948" ,
"harrw" : "\u21AD" ,
"Hat" : "\u005E" ,
"hbar" : "\u210F" ,
"Hcirc" : "\u0124" ,
"hcirc" : "\u0125" ,
"hearts" : "\u2665" ,
"heartsuit" : "\u2665" ,
"hellip" : "\u2026" ,
"hercon" : "\u22B9" ,
"Hfr" : "\u210C" ,
"hfr" : "\uD835\uDD25" ,
"HilbertSpace" : "\u210B" ,
"hksearow" : "\u2925" ,
"hkswarow" : "\u2926" ,
"hoarr" : "\u21FF" ,
"homtht" : "\u223B" ,
"hookleftarrow" : "\u21A9" ,
"hookrightarrow" : "\u21AA" ,
"Hopf" : "\u210D" ,
"hopf" : "\uD835\uDD59" ,
"horbar" : "\u2015" ,
"HorizontalLine" : "\u2500" ,
"Hscr" : "\u210B" ,
"hscr" : "\uD835\uDCBD" ,
"hslash" : "\u210F" ,
"Hstrok" : "\u0126" ,
"hstrok" : "\u0127" ,
"HumpDownHump" : "\u224E" ,
"HumpEqual" : "\u224F" ,
"hybull" : "\u2043" ,
"hyphen" : "\u2010" ,
"Iacute" : "\u00CD" ,
"iacute" : "\u00ED" ,
"ic" : "\u2063" ,
"Icirc" : "\u00CE" ,
"icirc" : "\u00EE" ,
"Icy" : "\u0418" ,
"icy" : "\u0438" ,
"Idot" : "\u0130" ,
"IEcy" : "\u0415" ,
"iecy" : "\u0435" ,
"iexcl" : "\u00A1" ,
"iff" : "\u21D4" ,
"Ifr" : "\u2111" ,
"ifr" : "\uD835\uDD26" ,
"Igrave" : "\u00CC" ,
"igrave" : "\u00EC" ,
"ii" : "\u2148" ,
"iiiint" : "\u2A0C" ,
"iiint" : "\u222D" ,
"iinfin" : "\u29DC" ,
"iiota" : "\u2129" ,
"IJlig" : "\u0132" ,
"ijlig" : "\u0133" ,
"Im" : "\u2111" ,
"Imacr" : "\u012A" ,
"imacr" : "\u012B" ,
"image" : "\u2111" ,
"ImaginaryI" : "\u2148" ,
"imagline" : "\u2110" ,
"imagpart" : "\u2111" ,
"imath" : "\u0131" ,
"imof" : "\u22B7" ,
"imped" : "\u01B5" ,
"Implies" : "\u21D2" ,
"in" : "\u2208" ,
"incare" : "\u2105" ,
"infin" : "\u221E" ,
"infintie" : "\u29DD" ,
"inodot" : "\u0131" ,
"Int" : "\u222C" ,
"int" : "\u222B" ,
"intcal" : "\u22BA" ,
"integers" : "\u2124" ,
"Integral" : "\u222B" ,
"intercal" : "\u22BA" ,
"Intersection" : "\u22C2" ,
"intlarhk" : "\u2A17" ,
"intprod" : "\u2A3C" ,
"InvisibleComma" : "\u2063" ,
"InvisibleTimes" : "\u2062" ,
"IOcy" : "\u0401" ,
"iocy" : "\u0451" ,
"Iogon" : "\u012E" ,
"iogon" : "\u012F" ,
"Iopf" : "\uD835\uDD40" ,
"iopf" : "\uD835\uDD5A" ,
"Iota" : "\u0399" ,
"iota" : "\u03B9" ,
"iprod" : "\u2A3C" ,
"iquest" : "\u00BF" ,
"Iscr" : "\u2110" ,
"iscr" : "\uD835\uDCBE" ,
"isin" : "\u2208" ,
"isindot" : "\u22F5" ,
"isinE" : "\u22F9" ,
"isins" : "\u22F4" ,
"isinsv" : "\u22F3" ,
"isinv" : "\u2208" ,
"it" : "\u2062" ,
"Itilde" : "\u0128" ,
"itilde" : "\u0129" ,
"Iukcy" : "\u0406" ,
"iukcy" : "\u0456" ,
"Iuml" : "\u00CF" ,
"iuml" : "\u00EF" ,
"Jcirc" : "\u0134" ,
"jcirc" : "\u0135" ,
"Jcy" : "\u0419" ,
"jcy" : "\u0439" ,
"Jfr" : "\uD835\uDD0D" ,
"jfr" : "\uD835\uDD27" ,
"jmath" : "\u0237" ,
"Jopf" : "\uD835\uDD41" ,
"jopf" : "\uD835\uDD5B" ,
"Jscr" : "\uD835\uDCA5" ,
"jscr" : "\uD835\uDCBF" ,
"Jsercy" : "\u0408" ,
"jsercy" : "\u0458" ,
"Jukcy" : "\u0404" ,
"jukcy" : "\u0454" ,
"Kappa" : "\u039A" ,
"kappa" : "\u03BA" ,
"kappav" : "\u03F0" ,
"Kcedil" : "\u0136" ,
"kcedil" : "\u0137" ,
"Kcy" : "\u041A" ,
"kcy" : "\u043A" ,
"Kfr" : "\uD835\uDD0E" ,
"kfr" : "\uD835\uDD28" ,
"kgreen" : "\u0138" ,
"KHcy" : "\u0425" ,
"khcy" : "\u0445" ,
"KJcy" : "\u040C" ,
"kjcy" : "\u045C" ,
"Kopf" : "\uD835\uDD42" ,
"kopf" : "\uD835\uDD5C" ,
"Kscr" : "\uD835\uDCA6" ,
"kscr" : "\uD835\uDCC0" ,
"lAarr" : "\u21DA" ,
"Lacute" : "\u0139" ,
"lacute" : "\u013A" ,
"laemptyv" : "\u29B4" ,
"lagran" : "\u2112" ,
"Lambda" : "\u039B" ,
"lambda" : "\u03BB" ,
"Lang" : "\u27EA" ,
"lang" : "\u27E8" ,
"langd" : "\u2991" ,
"langle" : "\u27E8" ,
"lap" : "\u2A85" ,
"Laplacetrf" : "\u2112" ,
"laquo" : "\u00AB" ,
"Larr" : "\u219E" ,
"lArr" : "\u21D0" ,
"larr" : "\u2190" ,
"larrb" : "\u21E4" ,
"larrbfs" : "\u291F" ,
"larrfs" : "\u291D" ,
"larrhk" : "\u21A9" ,
"larrlp" : "\u21AB" ,
"larrpl" : "\u2939" ,
"larrsim" : "\u2973" ,
"larrtl" : "\u21A2" ,
"lat" : "\u2AAB" ,
"lAtail" : "\u291B" ,
"latail" : "\u2919" ,
"late" : "\u2AAD" ,
"lates" : "\u2AAD\uFE00" ,
"lBarr" : "\u290E" ,
"lbarr" : "\u290C" ,
"lbbrk" : "\u2772" ,
"lbrace" : "\u007B" ,
"lbrack" : "\u005B" ,
"lbrke" : "\u298B" ,
"lbrksld" : "\u298F" ,
"lbrkslu" : "\u298D" ,
"Lcaron" : "\u013D" ,
"lcaron" : "\u013E" ,
"Lcedil" : "\u013B" ,
"lcedil" : "\u013C" ,
"lceil" : "\u2308" ,
"lcub" : "\u007B" ,
"Lcy" : "\u041B" ,
"lcy" : "\u043B" ,
"ldca" : "\u2936" ,
"ldquo" : "\u201C" ,
"ldquor" : "\u201E" ,
"ldrdhar" : "\u2967" ,
"ldrushar" : "\u294B" ,
"ldsh" : "\u21B2" ,
"lE" : "\u2266" ,
"le" : "\u2264" ,
"LeftAngleBracket" : "\u27E8" ,
"LeftArrow" : "\u2190" ,
"Leftarrow" : "\u21D0" ,
"leftarrow" : "\u2190" ,
"LeftArrowBar" : "\u21E4" ,
"LeftArrowRightArrow" : "\u21C6" ,
"leftarrowtail" : "\u21A2" ,
"LeftCeiling" : "\u2308" ,
"LeftDoubleBracket" : "\u27E6" ,
"LeftDownTeeVector" : "\u2961" ,
"LeftDownVector" : "\u21C3" ,
"LeftDownVectorBar" : "\u2959" ,
"LeftFloor" : "\u230A" ,
"leftharpoondown" : "\u21BD" ,
"leftharpoonup" : "\u21BC" ,
"leftleftarrows" : "\u21C7" ,
"LeftRightArrow" : "\u2194" ,
"Leftrightarrow" : "\u21D4" ,
"leftrightarrow" : "\u2194" ,
"leftrightarrows" : "\u21C6" ,
"leftrightharpoons" : "\u21CB" ,
"leftrightsquigarrow" : "\u21AD" ,
"LeftRightVector" : "\u294E" ,
"LeftTee" : "\u22A3" ,
"LeftTeeArrow" : "\u21A4" ,
"LeftTeeVector" : "\u295A" ,
"leftthreetimes" : "\u22CB" ,
"LeftTriangle" : "\u22B2" ,
"LeftTriangleBar" : "\u29CF" ,
"LeftTriangleEqual" : "\u22B4" ,
"LeftUpDownVector" : "\u2951" ,
"LeftUpTeeVector" : "\u2960" ,
"LeftUpVector" : "\u21BF" ,
"LeftUpVectorBar" : "\u2958" ,
"LeftVector" : "\u21BC" ,
"LeftVectorBar" : "\u2952" ,
"lEg" : "\u2A8B" ,
"leg" : "\u22DA" ,
"leq" : "\u2264" ,
"leqq" : "\u2266" ,
"leqslant" : "\u2A7D" ,
"les" : "\u2A7D" ,
"lescc" : "\u2AA8" ,
"lesdot" : "\u2A7F" ,
"lesdoto" : "\u2A81" ,
"lesdotor" : "\u2A83" ,
"lesg" : "\u22DA\uFE00" ,
"lesges" : "\u2A93" ,
"lessapprox" : "\u2A85" ,
"lessdot" : "\u22D6" ,
"lesseqgtr" : "\u22DA" ,
"lesseqqgtr" : "\u2A8B" ,
"LessEqualGreater" : "\u22DA" ,
"LessFullEqual" : "\u2266" ,
"LessGreater" : "\u2276" ,
"lessgtr" : "\u2276" ,
"LessLess" : "\u2AA1" ,
"lesssim" : "\u2272" ,
"LessSlantEqual" : "\u2A7D" ,
"LessTilde" : "\u2272" ,
"lfisht" : "\u297C" ,
"lfloor" : "\u230A" ,
"Lfr" : "\uD835\uDD0F" ,
"lfr" : "\uD835\uDD29" ,
"lg" : "\u2276" ,
"lgE" : "\u2A91" ,
"lHar" : "\u2962" ,
"lhard" : "\u21BD" ,
"lharu" : "\u21BC" ,
"lharul" : "\u296A" ,
"lhblk" : "\u2584" ,
"LJcy" : "\u0409" ,
"ljcy" : "\u0459" ,
"Ll" : "\u22D8" ,
"ll" : "\u226A" ,
"llarr" : "\u21C7" ,
"llcorner" : "\u231E" ,
"Lleftarrow" : "\u21DA" ,
"llhard" : "\u296B" ,
"lltri" : "\u25FA" ,
"Lmidot" : "\u013F" ,
"lmidot" : "\u0140" ,
"lmoust" : "\u23B0" ,
"lmoustache" : "\u23B0" ,
"lnap" : "\u2A89" ,
"lnapprox" : "\u2A89" ,
"lnE" : "\u2268" ,
"lne" : "\u2A87" ,
"lneq" : "\u2A87" ,
"lneqq" : "\u2268" ,
"lnsim" : "\u22E6" ,
"loang" : "\u27EC" ,
"loarr" : "\u21FD" ,
"lobrk" : "\u27E6" ,
"LongLeftArrow" : "\u27F5" ,
"Longleftarrow" : "\u27F8" ,
"longleftarrow" : "\u27F5" ,
"LongLeftRightArrow" : "\u27F7" ,
"Longleftrightarrow" : "\u27FA" ,
"longleftrightarrow" : "\u27F7" ,
"longmapsto" : "\u27FC" ,
"LongRightArrow" : "\u27F6" ,
"Longrightarrow" : "\u27F9" ,
"longrightarrow" : "\u27F6" ,
"looparrowleft" : "\u21AB" ,
"looparrowright" : "\u21AC" ,
"lopar" : "\u2985" ,
"Lopf" : "\uD835\uDD43" ,
"lopf" : "\uD835\uDD5D" ,
"loplus" : "\u2A2D" ,
"lotimes" : "\u2A34" ,
"lowast" : "\u2217" ,
"lowbar" : "\u005F" ,
"LowerLeftArrow" : "\u2199" ,
"LowerRightArrow" : "\u2198" ,
"loz" : "\u25CA" ,
"lozenge" : "\u25CA" ,
"lozf" : "\u29EB" ,
"lpar" : "\u0028" ,
"lparlt" : "\u2993" ,
"lrarr" : "\u21C6" ,
"lrcorner" : "\u231F" ,
"lrhar" : "\u21CB" ,
"lrhard" : "\u296D" ,
"lrm" : "\u200E" ,
"lrtri" : "\u22BF" ,
"lsaquo" : "\u2039" ,
"Lscr" : "\u2112" ,
"lscr" : "\uD835\uDCC1" ,
"Lsh" : "\u21B0" ,
"lsh" : "\u21B0" ,
"lsim" : "\u2272" ,
"lsime" : "\u2A8D" ,
"lsimg" : "\u2A8F" ,
"lsqb" : "\u005B" ,
"lsquo" : "\u2018" ,
"lsquor" : "\u201A" ,
"Lstrok" : "\u0141" ,
"lstrok" : "\u0142" ,
"LT" : "\u003C" ,
"Lt" : "\u226A" ,
"lt" : "\u003C" ,
"ltcc" : "\u2AA6" ,
"ltcir" : "\u2A79" ,
"ltdot" : "\u22D6" ,
"lthree" : "\u22CB" ,
"ltimes" : "\u22C9" ,
"ltlarr" : "\u2976" ,
"ltquest" : "\u2A7B" ,
"ltri" : "\u25C3" ,
"ltrie" : "\u22B4" ,
"ltrif" : "\u25C2" ,
"ltrPar" : "\u2996" ,
"lurdshar" : "\u294A" ,
"luruhar" : "\u2966" ,
"lvertneqq" : "\u2268\uFE00" ,
"lvnE" : "\u2268\uFE00" ,
"macr" : "\u00AF" ,
"male" : "\u2642" ,
"malt" : "\u2720" ,
"maltese" : "\u2720" ,
"Map" : "\u2905" ,
"map" : "\u21A6" ,
"mapsto" : "\u21A6" ,
"mapstodown" : "\u21A7" ,
"mapstoleft" : "\u21A4" ,
"mapstoup" : "\u21A5" ,
"marker" : "\u25AE" ,
"mcomma" : "\u2A29" ,
"Mcy" : "\u041C" ,
"mcy" : "\u043C" ,
"mdash" : "\u2014" ,
"mDDot" : "\u223A" ,
"measuredangle" : "\u2221" ,
"MediumSpace" : "\u205F" ,
"Mellintrf" : "\u2133" ,
"Mfr" : "\uD835\uDD10" ,
"mfr" : "\uD835\uDD2A" ,
"mho" : "\u2127" ,
"micro" : "\u00B5" ,
"mid" : "\u2223" ,
"midast" : "\u002A" ,
"midcir" : "\u2AF0" ,
"middot" : "\u00B7" ,
"minus" : "\u2212" ,
"minusb" : "\u229F" ,
"minusd" : "\u2238" ,
"minusdu" : "\u2A2A" ,
"MinusPlus" : "\u2213" ,
"mlcp" : "\u2ADB" ,
"mldr" : "\u2026" ,
"mnplus" : "\u2213" ,
"models" : "\u22A7" ,
"Mopf" : "\uD835\uDD44" ,
"mopf" : "\uD835\uDD5E" ,
"mp" : "\u2213" ,
"Mscr" : "\u2133" ,
"mscr" : "\uD835\uDCC2" ,
"mstpos" : "\u223E" ,
"Mu" : "\u039C" ,
"mu" : "\u03BC" ,
"multimap" : "\u22B8" ,
"mumap" : "\u22B8" ,
"nabla" : "\u2207" ,
"Nacute" : "\u0143" ,
"nacute" : "\u0144" ,
"nang" : "\u2220\u20D2" ,
"nap" : "\u2249" ,
"napE" : "\u2A70\u0338" ,
"napid" : "\u224B\u0338" ,
"napos" : "\u0149" ,
"napprox" : "\u2249" ,
"natur" : "\u266E" ,
"natural" : "\u266E" ,
"naturals" : "\u2115" ,
"nbsp" : "\u00A0" ,
"nbump" : "\u224E\u0338" ,
"nbumpe" : "\u224F\u0338" ,
"ncap" : "\u2A43" ,
"Ncaron" : "\u0147" ,
"ncaron" : "\u0148" ,
"Ncedil" : "\u0145" ,
"ncedil" : "\u0146" ,
"ncong" : "\u2247" ,
"ncongdot" : "\u2A6D\u0338" ,
"ncup" : "\u2A42" ,
"Ncy" : "\u041D" ,
"ncy" : "\u043D" ,
"ndash" : "\u2013" ,
"ne" : "\u2260" ,
"nearhk" : "\u2924" ,
"neArr" : "\u21D7" ,
"nearr" : "\u2197" ,
"nearrow" : "\u2197" ,
"nedot" : "\u2250\u0338" ,
"NegativeMediumSpace" : "\u200B" ,
"NegativeThickSpace" : "\u200B" ,
"NegativeThinSpace" : "\u200B" ,
"NegativeVeryThinSpace" : "\u200B" ,
"nequiv" : "\u2262" ,
"nesear" : "\u2928" ,
"nesim" : "\u2242\u0338" ,
"NestedGreaterGreater" : "\u226B" ,
"NestedLessLess" : "\u226A" ,
"NewLine" : "\u000A" ,
"nexist" : "\u2204" ,
"nexists" : "\u2204" ,
"Nfr" : "\uD835\uDD11" ,
"nfr" : "\uD835\uDD2B" ,
"ngE" : "\u2267\u0338" ,
"nge" : "\u2271" ,
"ngeq" : "\u2271" ,
"ngeqq" : "\u2267\u0338" ,
"ngeqslant" : "\u2A7E\u0338" ,
"nges" : "\u2A7E\u0338" ,
"nGg" : "\u22D9\u0338" ,
"ngsim" : "\u2275" ,
"nGt" : "\u226B\u20D2" ,
"ngt" : "\u226F" ,
"ngtr" : "\u226F" ,
"nGtv" : "\u226B\u0338" ,
"nhArr" : "\u21CE" ,
"nharr" : "\u21AE" ,
"nhpar" : "\u2AF2" ,
"ni" : "\u220B" ,
"nis" : "\u22FC" ,
"nisd" : "\u22FA" ,
"niv" : "\u220B" ,
"NJcy" : "\u040A" ,
"njcy" : "\u045A" ,
"nlArr" : "\u21CD" ,
"nlarr" : "\u219A" ,
"nldr" : "\u2025" ,
"nlE" : "\u2266\u0338" ,
"nle" : "\u2270" ,
"nLeftarrow" : "\u21CD" ,
"nleftarrow" : "\u219A" ,
"nLeftrightarrow" : "\u21CE" ,
"nleftrightarrow" : "\u21AE" ,
"nleq" : "\u2270" ,
"nleqq" : "\u2266\u0338" ,
"nleqslant" : "\u2A7D\u0338" ,
"nles" : "\u2A7D\u0338" ,
"nless" : "\u226E" ,
"nLl" : "\u22D8\u0338" ,
"nlsim" : "\u2274" ,
"nLt" : "\u226A\u20D2" ,
"nlt" : "\u226E" ,
"nltri" : "\u22EA" ,
"nltrie" : "\u22EC" ,
"nLtv" : "\u226A\u0338" ,
"nmid" : "\u2224" ,
"NoBreak" : "\u2060" ,
"NonBreakingSpace" : "\u00A0" ,
"Nopf" : "\u2115" ,
"nopf" : "\uD835\uDD5F" ,
"Not" : "\u2AEC" ,
"not" : "\u00AC" ,
"NotCongruent" : "\u2262" ,
"NotCupCap" : "\u226D" ,
"NotDoubleVerticalBar" : "\u2226" ,
"NotElement" : "\u2209" ,
"NotEqual" : "\u2260" ,
"NotEqualTilde" : "\u2242\u0338" ,
"NotExists" : "\u2204" ,
"NotGreater" : "\u226F" ,
"NotGreaterEqual" : "\u2271" ,
"NotGreaterFullEqual" : "\u2267\u0338" ,
"NotGreaterGreater" : "\u226B\u0338" ,
"NotGreaterLess" : "\u2279" ,
"NotGreaterSlantEqual" : "\u2A7E\u0338" ,
"NotGreaterTilde" : "\u2275" ,
"NotHumpDownHump" : "\u224E\u0338" ,
"NotHumpEqual" : "\u224F\u0338" ,
"notin" : "\u2209" ,
"notindot" : "\u22F5\u0338" ,
"notinE" : "\u22F9\u0338" ,
"notinva" : "\u2209" ,
"notinvb" : "\u22F7" ,
"notinvc" : "\u22F6" ,
"NotLeftTriangle" : "\u22EA" ,
"NotLeftTriangleBar" : "\u29CF\u0338" ,
"NotLeftTriangleEqual" : "\u22EC" ,
"NotLess" : "\u226E" ,
"NotLessEqual" : "\u2270" ,
"NotLessGreater" : "\u2278" ,
"NotLessLess" : "\u226A\u0338" ,
"NotLessSlantEqual" : "\u2A7D\u0338" ,
"NotLessTilde" : "\u2274" ,
"NotNestedGreaterGreater" : "\u2AA2\u0338" ,
"NotNestedLessLess" : "\u2AA1\u0338" ,
"notni" : "\u220C" ,
"notniva" : "\u220C" ,
"notnivb" : "\u22FE" ,
"notnivc" : "\u22FD" ,
"NotPrecedes" : "\u2280" ,
"NotPrecedesEqual" : "\u2AAF\u0338" ,
"NotPrecedesSlantEqual" : "\u22E0" ,
"NotReverseElement" : "\u220C" ,
"NotRightTriangle" : "\u22EB" ,
"NotRightTriangleBar" : "\u29D0\u0338" ,
"NotRightTriangleEqual" : "\u22ED" ,
"NotSquareSubset" : "\u228F\u0338" ,
"NotSquareSubsetEqual" : "\u22E2" ,
"NotSquareSuperset" : "\u2290\u0338" ,
"NotSquareSupersetEqual" : "\u22E3" ,
"NotSubset" : "\u2282\u20D2" ,
"NotSubsetEqual" : "\u2288" ,
"NotSucceeds" : "\u2281" ,
"NotSucceedsEqual" : "\u2AB0\u0338" ,
"NotSucceedsSlantEqual" : "\u22E1" ,
"NotSucceedsTilde" : "\u227F\u0338" ,
"NotSuperset" : "\u2283\u20D2" ,
"NotSupersetEqual" : "\u2289" ,
"NotTilde" : "\u2241" ,
"NotTildeEqual" : "\u2244" ,
"NotTildeFullEqual" : "\u2247" ,
"NotTildeTilde" : "\u2249" ,
"NotVerticalBar" : "\u2224" ,
"npar" : "\u2226" ,
"nparallel" : "\u2226" ,
"nparsl" : "\u2AFD\u20E5" ,
"npart" : "\u2202\u0338" ,
"npolint" : "\u2A14" ,
"npr" : "\u2280" ,
"nprcue" : "\u22E0" ,
"npre" : "\u2AAF\u0338" ,
"nprec" : "\u2280" ,
"npreceq" : "\u2AAF\u0338" ,
"nrArr" : "\u21CF" ,
"nrarr" : "\u219B" ,
"nrarrc" : "\u2933\u0338" ,
"nrarrw" : "\u219D\u0338" ,
"nRightarrow" : "\u21CF" ,
"nrightarrow" : "\u219B" ,
"nrtri" : "\u22EB" ,
"nrtrie" : "\u22ED" ,
"nsc" : "\u2281" ,
"nsccue" : "\u22E1" ,
"nsce" : "\u2AB0\u0338" ,
"Nscr" : "\uD835\uDCA9" ,
"nscr" : "\uD835\uDCC3" ,
"nshortmid" : "\u2224" ,
"nshortparallel" : "\u2226" ,
"nsim" : "\u2241" ,
"nsime" : "\u2244" ,
"nsimeq" : "\u2244" ,
"nsmid" : "\u2224" ,
"nspar" : "\u2226" ,
"nsqsube" : "\u22E2" ,
"nsqsupe" : "\u22E3" ,
"nsub" : "\u2284" ,
"nsubE" : "\u2AC5\u0338" ,
"nsube" : "\u2288" ,
"nsubset" : "\u2282\u20D2" ,
"nsubseteq" : "\u2288" ,
"nsubseteqq" : "\u2AC5\u0338" ,
"nsucc" : "\u2281" ,
"nsucceq" : "\u2AB0\u0338" ,
"nsup" : "\u2285" ,
"nsupE" : "\u2AC6\u0338" ,
"nsupe" : "\u2289" ,
"nsupset" : "\u2283\u20D2" ,
"nsupseteq" : "\u2289" ,
"nsupseteqq" : "\u2AC6\u0338" ,
"ntgl" : "\u2279" ,
"Ntilde" : "\u00D1" ,
"ntilde" : "\u00F1" ,
"ntlg" : "\u2278" ,
"ntriangleleft" : "\u22EA" ,
"ntrianglelefteq" : "\u22EC" ,
"ntriangleright" : "\u22EB" ,
"ntrianglerighteq" : "\u22ED" ,
"Nu" : "\u039D" ,
"nu" : "\u03BD" ,
"num" : "\u0023" ,
"numero" : "\u2116" ,
"numsp" : "\u2007" ,
"nvap" : "\u224D\u20D2" ,
"nVDash" : "\u22AF" ,
"nVdash" : "\u22AE" ,
"nvDash" : "\u22AD" ,
"nvdash" : "\u22AC" ,
"nvge" : "\u2265\u20D2" ,
"nvgt" : "\u003E\u20D2" ,
"nvHarr" : "\u2904" ,
"nvinfin" : "\u29DE" ,
"nvlArr" : "\u2902" ,
"nvle" : "\u2264\u20D2" ,
"nvlt" : "\u003C\u20D2" ,
"nvltrie" : "\u22B4\u20D2" ,
"nvrArr" : "\u2903" ,
"nvrtrie" : "\u22B5\u20D2" ,
"nvsim" : "\u223C\u20D2" ,
"nwarhk" : "\u2923" ,
"nwArr" : "\u21D6" ,
"nwarr" : "\u2196" ,
"nwarrow" : "\u2196" ,
"nwnear" : "\u2927" ,
"Oacute" : "\u00D3" ,
"oacute" : "\u00F3" ,
"oast" : "\u229B" ,
"ocir" : "\u229A" ,
"Ocirc" : "\u00D4" ,
"ocirc" : "\u00F4" ,
"Ocy" : "\u041E" ,
"ocy" : "\u043E" ,
"odash" : "\u229D" ,
"Odblac" : "\u0150" ,
"odblac" : "\u0151" ,
"odiv" : "\u2A38" ,
"odot" : "\u2299" ,
"odsold" : "\u29BC" ,
"OElig" : "\u0152" ,
"oelig" : "\u0153" ,
"ofcir" : "\u29BF" ,
"Ofr" : "\uD835\uDD12" ,
"ofr" : "\uD835\uDD2C" ,
"ogon" : "\u02DB" ,
"Ograve" : "\u00D2" ,
"ograve" : "\u00F2" ,
"ogt" : "\u29C1" ,
"ohbar" : "\u29B5" ,
"ohm" : "\u03A9" ,
"oint" : "\u222E" ,
"olarr" : "\u21BA" ,
"olcir" : "\u29BE" ,
"olcross" : "\u29BB" ,
"oline" : "\u203E" ,
"olt" : "\u29C0" ,
"Omacr" : "\u014C" ,
"omacr" : "\u014D" ,
"Omega" : "\u03A9" ,
"omega" : "\u03C9" ,
"Omicron" : "\u039F" ,
"omicron" : "\u03BF" ,
"omid" : "\u29B6" ,
"ominus" : "\u2296" ,
"Oopf" : "\uD835\uDD46" ,
"oopf" : "\uD835\uDD60" ,
"opar" : "\u29B7" ,
"OpenCurlyDoubleQuote" : "\u201C" ,
"OpenCurlyQuote" : "\u2018" ,
"operp" : "\u29B9" ,
"oplus" : "\u2295" ,
"Or" : "\u2A54" ,
"or" : "\u2228" ,
"orarr" : "\u21BB" ,
"ord" : "\u2A5D" ,
"order" : "\u2134" ,
"orderof" : "\u2134" ,
"ordf" : "\u00AA" ,
"ordm" : "\u00BA" ,
"origof" : "\u22B6" ,
"oror" : "\u2A56" ,
"orslope" : "\u2A57" ,
"orv" : "\u2A5B" ,
"oS" : "\u24C8" ,
"Oscr" : "\uD835\uDCAA" ,
"oscr" : "\u2134" ,
"Oslash" : "\u00D8" ,
"oslash" : "\u00F8" ,
"osol" : "\u2298" ,
"Otilde" : "\u00D5" ,
"otilde" : "\u00F5" ,
"Otimes" : "\u2A37" ,
"otimes" : "\u2297" ,
"otimesas" : "\u2A36" ,
"Ouml" : "\u00D6" ,
"ouml" : "\u00F6" ,
"ovbar" : "\u233D" ,
"OverBar" : "\u203E" ,
"OverBrace" : "\u23DE" ,
"OverBracket" : "\u23B4" ,
"OverParenthesis" : "\u23DC" ,
"par" : "\u2225" ,
"para" : "\u00B6" ,
"parallel" : "\u2225" ,
"parsim" : "\u2AF3" ,
"parsl" : "\u2AFD" ,
"part" : "\u2202" ,
"PartialD" : "\u2202" ,
"Pcy" : "\u041F" ,
"pcy" : "\u043F" ,
"percnt" : "\u0025" ,
"period" : "\u002E" ,
"permil" : "\u2030" ,
"perp" : "\u22A5" ,
"pertenk" : "\u2031" ,
"Pfr" : "\uD835\uDD13" ,
"pfr" : "\uD835\uDD2D" ,
"Phi" : "\u03A6" ,
"phi" : "\u03C6" ,
"phiv" : "\u03D5" ,
"phmmat" : "\u2133" ,
"phone" : "\u260E" ,
"Pi" : "\u03A0" ,
"pi" : "\u03C0" ,
"pitchfork" : "\u22D4" ,
"piv" : "\u03D6" ,
"planck" : "\u210F" ,
"planckh" : "\u210E" ,
"plankv" : "\u210F" ,
"plus" : "\u002B" ,
"plusacir" : "\u2A23" ,
"plusb" : "\u229E" ,
"pluscir" : "\u2A22" ,
"plusdo" : "\u2214" ,
"plusdu" : "\u2A25" ,
"pluse" : "\u2A72" ,
"PlusMinus" : "\u00B1" ,
"plusmn" : "\u00B1" ,
"plussim" : "\u2A26" ,
"plustwo" : "\u2A27" ,
"pm" : "\u00B1" ,
"Poincareplane" : "\u210C" ,
"pointint" : "\u2A15" ,
"Popf" : "\u2119" ,
"popf" : "\uD835\uDD61" ,
"pound" : "\u00A3" ,
"Pr" : "\u2ABB" ,
"pr" : "\u227A" ,
"prap" : "\u2AB7" ,
"prcue" : "\u227C" ,
"prE" : "\u2AB3" ,
"pre" : "\u2AAF" ,
"prec" : "\u227A" ,
"precapprox" : "\u2AB7" ,
"preccurlyeq" : "\u227C" ,
"Precedes" : "\u227A" ,
"PrecedesEqual" : "\u2AAF" ,
"PrecedesSlantEqual" : "\u227C" ,
"PrecedesTilde" : "\u227E" ,
"preceq" : "\u2AAF" ,
"precnapprox" : "\u2AB9" ,
"precneqq" : "\u2AB5" ,
"precnsim" : "\u22E8" ,
"precsim" : "\u227E" ,
"Prime" : "\u2033" ,
"prime" : "\u2032" ,
"primes" : "\u2119" ,
"prnap" : "\u2AB9" ,
"prnE" : "\u2AB5" ,
"prnsim" : "\u22E8" ,
"prod" : "\u220F" ,
"Product" : "\u220F" ,
"profalar" : "\u232E" ,
"profline" : "\u2312" ,
"profsurf" : "\u2313" ,
"prop" : "\u221D" ,
"Proportion" : "\u2237" ,
"Proportional" : "\u221D" ,
"propto" : "\u221D" ,
"prsim" : "\u227E" ,
"prurel" : "\u22B0" ,
"Pscr" : "\uD835\uDCAB" ,
"pscr" : "\uD835\uDCC5" ,
"Psi" : "\u03A8" ,
"psi" : "\u03C8" ,
"puncsp" : "\u2008" ,
"Qfr" : "\uD835\uDD14" ,
"qfr" : "\uD835\uDD2E" ,
"qint" : "\u2A0C" ,
"Qopf" : "\u211A" ,
"qopf" : "\uD835\uDD62" ,
"qprime" : "\u2057" ,
"Qscr" : "\uD835\uDCAC" ,
"qscr" : "\uD835\uDCC6" ,
"quaternions" : "\u210D" ,
"quatint" : "\u2A16" ,
"quest" : "\u003F" ,
"questeq" : "\u225F" ,
"QUOT" : "\u0022" ,
"quot" : "\u0022" ,
"rAarr" : "\u21DB" ,
"race" : "\u223D\u0331" ,
"Racute" : "\u0154" ,
"racute" : "\u0155" ,
"radic" : "\u221A" ,
"raemptyv" : "\u29B3" ,
"Rang" : "\u27EB" ,
"rang" : "\u27E9" ,
"rangd" : "\u2992" ,
"range" : "\u29A5" ,
"rangle" : "\u27E9" ,
"raquo" : "\u00BB" ,
"Rarr" : "\u21A0" ,
"rArr" : "\u21D2" ,
"rarr" : "\u2192" ,
"rarrap" : "\u2975" ,
"rarrb" : "\u21E5" ,
"rarrbfs" : "\u2920" ,
"rarrc" : "\u2933" ,
"rarrfs" : "\u291E" ,
"rarrhk" : "\u21AA" ,
"rarrlp" : "\u21AC" ,
"rarrpl" : "\u2945" ,
"rarrsim" : "\u2974" ,
"Rarrtl" : "\u2916" ,
"rarrtl" : "\u21A3" ,
"rarrw" : "\u219D" ,
"rAtail" : "\u291C" ,
"ratail" : "\u291A" ,
"ratio" : "\u2236" ,
"rationals" : "\u211A" ,
"RBarr" : "\u2910" ,
"rBarr" : "\u290F" ,
"rbarr" : "\u290D" ,
"rbbrk" : "\u2773" ,
"rbrace" : "\u007D" ,
"rbrack" : "\u005D" ,
"rbrke" : "\u298C" ,
"rbrksld" : "\u298E" ,
"rbrkslu" : "\u2990" ,
"Rcaron" : "\u0158" ,
"rcaron" : "\u0159" ,
"Rcedil" : "\u0156" ,
"rcedil" : "\u0157" ,
"rceil" : "\u2309" ,
"rcub" : "\u007D" ,
"Rcy" : "\u0420" ,
"rcy" : "\u0440" ,
"rdca" : "\u2937" ,
"rdldhar" : "\u2969" ,
"rdquo" : "\u201D" ,
"rdquor" : "\u201D" ,
"rdsh" : "\u21B3" ,
"Re" : "\u211C" ,
"real" : "\u211C" ,
"realine" : "\u211B" ,
"realpart" : "\u211C" ,
"reals" : "\u211D" ,
"rect" : "\u25AD" ,
"REG" : "\u00AE" ,
"reg" : "\u00AE" ,
"ReverseElement" : "\u220B" ,
"ReverseEquilibrium" : "\u21CB" ,
"ReverseUpEquilibrium" : "\u296F" ,
"rfisht" : "\u297D" ,
"rfloor" : "\u230B" ,
"Rfr" : "\u211C" ,
"rfr" : "\uD835\uDD2F" ,
"rHar" : "\u2964" ,
"rhard" : "\u21C1" ,
"rharu" : "\u21C0" ,
"rharul" : "\u296C" ,
"Rho" : "\u03A1" ,
"rho" : "\u03C1" ,
"rhov" : "\u03F1" ,
"RightAngleBracket" : "\u27E9" ,
"RightArrow" : "\u2192" ,
"Rightarrow" : "\u21D2" ,
"rightarrow" : "\u2192" ,
"RightArrowBar" : "\u21E5" ,
"RightArrowLeftArrow" : "\u21C4" ,
"rightarrowtail" : "\u21A3" ,
"RightCeiling" : "\u2309" ,
"RightDoubleBracket" : "\u27E7" ,
"RightDownTeeVector" : "\u295D" ,
"RightDownVector" : "\u21C2" ,
"RightDownVectorBar" : "\u2955" ,
"RightFloor" : "\u230B" ,
"rightharpoondown" : "\u21C1" ,
"rightharpoonup" : "\u21C0" ,
"rightleftarrows" : "\u21C4" ,
"rightleftharpoons" : "\u21CC" ,
"rightrightarrows" : "\u21C9" ,
"rightsquigarrow" : "\u219D" ,
"RightTee" : "\u22A2" ,
"RightTeeArrow" : "\u21A6" ,
"RightTeeVector" : "\u295B" ,
"rightthreetimes" : "\u22CC" ,
"RightTriangle" : "\u22B3" ,
"RightTriangleBar" : "\u29D0" ,
"RightTriangleEqual" : "\u22B5" ,
"RightUpDownVector" : "\u294F" ,
"RightUpTeeVector" : "\u295C" ,
"RightUpVector" : "\u21BE" ,
"RightUpVectorBar" : "\u2954" ,
"RightVector" : "\u21C0" ,
"RightVectorBar" : "\u2953" ,
"ring" : "\u02DA" ,
"risingdotseq" : "\u2253" ,
"rlarr" : "\u21C4" ,
"rlhar" : "\u21CC" ,
"rlm" : "\u200F" ,
"rmoust" : "\u23B1" ,
"rmoustache" : "\u23B1" ,
"rnmid" : "\u2AEE" ,
"roang" : "\u27ED" ,
"roarr" : "\u21FE" ,
"robrk" : "\u27E7" ,
"ropar" : "\u2986" ,
"Ropf" : "\u211D" ,
"ropf" : "\uD835\uDD63" ,
"roplus" : "\u2A2E" ,
"rotimes" : "\u2A35" ,
"RoundImplies" : "\u2970" ,
"rpar" : "\u0029" ,
"rpargt" : "\u2994" ,
"rppolint" : "\u2A12" ,
"rrarr" : "\u21C9" ,
"Rrightarrow" : "\u21DB" ,
"rsaquo" : "\u203A" ,
"Rscr" : "\u211B" ,
"rscr" : "\uD835\uDCC7" ,
"Rsh" : "\u21B1" ,
"rsh" : "\u21B1" ,
"rsqb" : "\u005D" ,
"rsquo" : "\u2019" ,
"rsquor" : "\u2019" ,
"rthree" : "\u22CC" ,
"rtimes" : "\u22CA" ,
"rtri" : "\u25B9" ,
"rtrie" : "\u22B5" ,
"rtrif" : "\u25B8" ,
"rtriltri" : "\u29CE" ,
"RuleDelayed" : "\u29F4" ,
"ruluhar" : "\u2968" ,
"rx" : "\u211E" ,
"Sacute" : "\u015A" ,
"sacute" : "\u015B" ,
"sbquo" : "\u201A" ,
"Sc" : "\u2ABC" ,
"sc" : "\u227B" ,
"scap" : "\u2AB8" ,
"Scaron" : "\u0160" ,
"scaron" : "\u0161" ,
"sccue" : "\u227D" ,
"scE" : "\u2AB4" ,
"sce" : "\u2AB0" ,
"Scedil" : "\u015E" ,
"scedil" : "\u015F" ,
"Scirc" : "\u015C" ,
"scirc" : "\u015D" ,
"scnap" : "\u2ABA" ,
"scnE" : "\u2AB6" ,
"scnsim" : "\u22E9" ,
"scpolint" : "\u2A13" ,
"scsim" : "\u227F" ,
"Scy" : "\u0421" ,
"scy" : "\u0441" ,
"sdot" : "\u22C5" ,
"sdotb" : "\u22A1" ,
"sdote" : "\u2A66" ,
"searhk" : "\u2925" ,
"seArr" : "\u21D8" ,
"searr" : "\u2198" ,
"searrow" : "\u2198" ,
"sect" : "\u00A7" ,
"semi" : "\u003B" ,
"seswar" : "\u2929" ,
"setminus" : "\u2216" ,
"setmn" : "\u2216" ,
"sext" : "\u2736" ,
"Sfr" : "\uD835\uDD16" ,
"sfr" : "\uD835\uDD30" ,
"sfrown" : "\u2322" ,
"sharp" : "\u266F" ,
"SHCHcy" : "\u0429" ,
"shchcy" : "\u0449" ,
"SHcy" : "\u0428" ,
"shcy" : "\u0448" ,
"ShortDownArrow" : "\u2193" ,
"ShortLeftArrow" : "\u2190" ,
"shortmid" : "\u2223" ,
"shortparallel" : "\u2225" ,
"ShortRightArrow" : "\u2192" ,
"ShortUpArrow" : "\u2191" ,
"shy" : "\u00AD" ,
"Sigma" : "\u03A3" ,
"sigma" : "\u03C3" ,
"sigmaf" : "\u03C2" ,
"sigmav" : "\u03C2" ,
"sim" : "\u223C" ,
"simdot" : "\u2A6A" ,
"sime" : "\u2243" ,
"simeq" : "\u2243" ,
"simg" : "\u2A9E" ,
"simgE" : "\u2AA0" ,
"siml" : "\u2A9D" ,
"simlE" : "\u2A9F" ,
"simne" : "\u2246" ,
"simplus" : "\u2A24" ,
"simrarr" : "\u2972" ,
"slarr" : "\u2190" ,
"SmallCircle" : "\u2218" ,
"smallsetminus" : "\u2216" ,
"smashp" : "\u2A33" ,
"smeparsl" : "\u29E4" ,
"smid" : "\u2223" ,
"smile" : "\u2323" ,
"smt" : "\u2AAA" ,
"smte" : "\u2AAC" ,
"smtes" : "\u2AAC\uFE00" ,
"SOFTcy" : "\u042C" ,
"softcy" : "\u044C" ,
"sol" : "\u002F" ,
"solb" : "\u29C4" ,
"solbar" : "\u233F" ,
"Sopf" : "\uD835\uDD4A" ,
"sopf" : "\uD835\uDD64" ,
"spades" : "\u2660" ,
"spadesuit" : "\u2660" ,
"spar" : "\u2225" ,
"sqcap" : "\u2293" ,
"sqcaps" : "\u2293\uFE00" ,
"sqcup" : "\u2294" ,
"sqcups" : "\u2294\uFE00" ,
"Sqrt" : "\u221A" ,
"sqsub" : "\u228F" ,
"sqsube" : "\u2291" ,
"sqsubset" : "\u228F" ,
"sqsubseteq" : "\u2291" ,
"sqsup" : "\u2290" ,
"sqsupe" : "\u2292" ,
"sqsupset" : "\u2290" ,
"sqsupseteq" : "\u2292" ,
"squ" : "\u25A1" ,
"Square" : "\u25A1" ,
"square" : "\u25A1" ,
"SquareIntersection" : "\u2293" ,
"SquareSubset" : "\u228F" ,
"SquareSubsetEqual" : "\u2291" ,
"SquareSuperset" : "\u2290" ,
"SquareSupersetEqual" : "\u2292" ,
"SquareUnion" : "\u2294" ,
"squarf" : "\u25AA" ,
"squf" : "\u25AA" ,
"srarr" : "\u2192" ,
"Sscr" : "\uD835\uDCAE" ,
"sscr" : "\uD835\uDCC8" ,
"ssetmn" : "\u2216" ,
"ssmile" : "\u2323" ,
"sstarf" : "\u22C6" ,
"Star" : "\u22C6" ,
"star" : "\u2606" ,
"starf" : "\u2605" ,
"straightepsilon" : "\u03F5" ,
"straightphi" : "\u03D5" ,
"strns" : "\u00AF" ,
"Sub" : "\u22D0" ,
"sub" : "\u2282" ,
"subdot" : "\u2ABD" ,
"subE" : "\u2AC5" ,
"sube" : "\u2286" ,
"subedot" : "\u2AC3" ,
"submult" : "\u2AC1" ,
"subnE" : "\u2ACB" ,
"subne" : "\u228A" ,
"subplus" : "\u2ABF" ,
"subrarr" : "\u2979" ,
"Subset" : "\u22D0" ,
"subset" : "\u2282" ,
"subseteq" : "\u2286" ,
"subseteqq" : "\u2AC5" ,
"SubsetEqual" : "\u2286" ,
"subsetneq" : "\u228A" ,
"subsetneqq" : "\u2ACB" ,
"subsim" : "\u2AC7" ,
"subsub" : "\u2AD5" ,
"subsup" : "\u2AD3" ,
"succ" : "\u227B" ,
"succapprox" : "\u2AB8" ,
"succcurlyeq" : "\u227D" ,
"Succeeds" : "\u227B" ,
"SucceedsEqual" : "\u2AB0" ,
"SucceedsSlantEqual" : "\u227D" ,
"SucceedsTilde" : "\u227F" ,
"succeq" : "\u2AB0" ,
"succnapprox" : "\u2ABA" ,
"succneqq" : "\u2AB6" ,
"succnsim" : "\u22E9" ,
"succsim" : "\u227F" ,
"SuchThat" : "\u220B" ,
"Sum" : "\u2211" ,
"sum" : "\u2211" ,
"sung" : "\u266A" ,
"Sup" : "\u22D1" ,
"sup" : "\u2283" ,
"sup1" : "\u00B9" ,
"sup2" : "\u00B2" ,
"sup3" : "\u00B3" ,
"supdot" : "\u2ABE" ,
"supdsub" : "\u2AD8" ,
"supE" : "\u2AC6" ,
"supe" : "\u2287" ,
"supedot" : "\u2AC4" ,
"Superset" : "\u2283" ,
"SupersetEqual" : "\u2287" ,
"suphsol" : "\u27C9" ,
"suphsub" : "\u2AD7" ,
"suplarr" : "\u297B" ,
"supmult" : "\u2AC2" ,
"supnE" : "\u2ACC" ,
"supne" : "\u228B" ,
"supplus" : "\u2AC0" ,
"Supset" : "\u22D1" ,
"supset" : "\u2283" ,
"supseteq" : "\u2287" ,
"supseteqq" : "\u2AC6" ,
"supsetneq" : "\u228B" ,
"supsetneqq" : "\u2ACC" ,
"supsim" : "\u2AC8" ,
"supsub" : "\u2AD4" ,
"supsup" : "\u2AD6" ,
"swarhk" : "\u2926" ,
"swArr" : "\u21D9" ,
"swarr" : "\u2199" ,
"swarrow" : "\u2199" ,
"swnwar" : "\u292A" ,
"szlig" : "\u00DF" ,
"Tab" : "\u0009" ,
"target" : "\u2316" ,
"Tau" : "\u03A4" ,
"tau" : "\u03C4" ,
"tbrk" : "\u23B4" ,
"Tcaron" : "\u0164" ,
"tcaron" : "\u0165" ,
"Tcedil" : "\u0162" ,
"tcedil" : "\u0163" ,
"Tcy" : "\u0422" ,
"tcy" : "\u0442" ,
"tdot" : "\u20DB" ,
"telrec" : "\u2315" ,
"Tfr" : "\uD835\uDD17" ,
"tfr" : "\uD835\uDD31" ,
"there4" : "\u2234" ,
"Therefore" : "\u2234" ,
"therefore" : "\u2234" ,
"Theta" : "\u0398" ,
"theta" : "\u03B8" ,
"thetasym" : "\u03D1" ,
"thetav" : "\u03D1" ,
"thickapprox" : "\u2248" ,
"thicksim" : "\u223C" ,
"ThickSpace" : "\u205F\u200A" ,
"thinsp" : "\u2009" ,
"ThinSpace" : "\u2009" ,
"thkap" : "\u2248" ,
"thksim" : "\u223C" ,
"THORN" : "\u00DE" ,
"thorn" : "\u00FE" ,
"Tilde" : "\u223C" ,
"tilde" : "\u02DC" ,
"TildeEqual" : "\u2243" ,
"TildeFullEqual" : "\u2245" ,
"TildeTilde" : "\u2248" ,
"times" : "\u00D7" ,
"timesb" : "\u22A0" ,
"timesbar" : "\u2A31" ,
"timesd" : "\u2A30" ,
"tint" : "\u222D" ,
"toea" : "\u2928" ,
"top" : "\u22A4" ,
"topbot" : "\u2336" ,
"topcir" : "\u2AF1" ,
"Topf" : "\uD835\uDD4B" ,
"topf" : "\uD835\uDD65" ,
"topfork" : "\u2ADA" ,
"tosa" : "\u2929" ,
"tprime" : "\u2034" ,
"TRADE" : "\u2122" ,
"trade" : "\u2122" ,
"triangle" : "\u25B5" ,
"triangledown" : "\u25BF" ,
"triangleleft" : "\u25C3" ,
"trianglelefteq" : "\u22B4" ,
"triangleq" : "\u225C" ,
"triangleright" : "\u25B9" ,
"trianglerighteq" : "\u22B5" ,
"tridot" : "\u25EC" ,
"trie" : "\u225C" ,
"triminus" : "\u2A3A" ,
"TripleDot" : "\u20DB" ,
"triplus" : "\u2A39" ,
"trisb" : "\u29CD" ,
"tritime" : "\u2A3B" ,
"trpezium" : "\u23E2" ,
"Tscr" : "\uD835\uDCAF" ,
"tscr" : "\uD835\uDCC9" ,
"TScy" : "\u0426" ,
"tscy" : "\u0446" ,
"TSHcy" : "\u040B" ,
"tshcy" : "\u045B" ,
"Tstrok" : "\u0166" ,
"tstrok" : "\u0167" ,
"twixt" : "\u226C" ,
"twoheadleftarrow" : "\u219E" ,
"twoheadrightarrow" : "\u21A0" ,
"Uacute" : "\u00DA" ,
"uacute" : "\u00FA" ,
"Uarr" : "\u219F" ,
"uArr" : "\u21D1" ,
"uarr" : "\u2191" ,
"Uarrocir" : "\u2949" ,
"Ubrcy" : "\u040E" ,
"ubrcy" : "\u045E" ,
"Ubreve" : "\u016C" ,
"ubreve" : "\u016D" ,
"Ucirc" : "\u00DB" ,
"ucirc" : "\u00FB" ,
"Ucy" : "\u0423" ,
"ucy" : "\u0443" ,
"udarr" : "\u21C5" ,
"Udblac" : "\u0170" ,
"udblac" : "\u0171" ,
"udhar" : "\u296E" ,
"ufisht" : "\u297E" ,
"Ufr" : "\uD835\uDD18" ,
"ufr" : "\uD835\uDD32" ,
"Ugrave" : "\u00D9" ,
"ugrave" : "\u00F9" ,
"uHar" : "\u2963" ,
"uharl" : "\u21BF" ,
"uharr" : "\u21BE" ,
"uhblk" : "\u2580" ,
"ulcorn" : "\u231C" ,
"ulcorner" : "\u231C" ,
"ulcrop" : "\u230F" ,
"ultri" : "\u25F8" ,
"Umacr" : "\u016A" ,
"umacr" : "\u016B" ,
"uml" : "\u00A8" ,
"UnderBar" : "\u005F" ,
"UnderBrace" : "\u23DF" ,
"UnderBracket" : "\u23B5" ,
"UnderParenthesis" : "\u23DD" ,
"Union" : "\u22C3" ,
"UnionPlus" : "\u228E" ,
"Uogon" : "\u0172" ,
"uogon" : "\u0173" ,
"Uopf" : "\uD835\uDD4C" ,
"uopf" : "\uD835\uDD66" ,
"UpArrow" : "\u2191" ,
"Uparrow" : "\u21D1" ,
"uparrow" : "\u2191" ,
"UpArrowBar" : "\u2912" ,
"UpArrowDownArrow" : "\u21C5" ,
"UpDownArrow" : "\u2195" ,
"Updownarrow" : "\u21D5" ,
"updownarrow" : "\u2195" ,
"UpEquilibrium" : "\u296E" ,
"upharpoonleft" : "\u21BF" ,
"upharpoonright" : "\u21BE" ,
"uplus" : "\u228E" ,
"UpperLeftArrow" : "\u2196" ,
"UpperRightArrow" : "\u2197" ,
"Upsi" : "\u03D2" ,
"upsi" : "\u03C5" ,
"upsih" : "\u03D2" ,
"Upsilon" : "\u03A5" ,
"upsilon" : "\u03C5" ,
"UpTee" : "\u22A5" ,
"UpTeeArrow" : "\u21A5" ,
"upuparrows" : "\u21C8" ,
"urcorn" : "\u231D" ,
"urcorner" : "\u231D" ,
"urcrop" : "\u230E" ,
"Uring" : "\u016E" ,
"uring" : "\u016F" ,
"urtri" : "\u25F9" ,
"Uscr" : "\uD835\uDCB0" ,
"uscr" : "\uD835\uDCCA" ,
"utdot" : "\u22F0" ,
"Utilde" : "\u0168" ,
"utilde" : "\u0169" ,
"utri" : "\u25B5" ,
"utrif" : "\u25B4" ,
"uuarr" : "\u21C8" ,
"Uuml" : "\u00DC" ,
"uuml" : "\u00FC" ,
"uwangle" : "\u29A7" ,
"vangrt" : "\u299C" ,
"varepsilon" : "\u03F5" ,
"varkappa" : "\u03F0" ,
"varnothing" : "\u2205" ,
"varphi" : "\u03D5" ,
"varpi" : "\u03D6" ,
"varpropto" : "\u221D" ,
"vArr" : "\u21D5" ,
"varr" : "\u2195" ,
"varrho" : "\u03F1" ,
"varsigma" : "\u03C2" ,
"varsubsetneq" : "\u228A\uFE00" ,
"varsubsetneqq" : "\u2ACB\uFE00" ,
"varsupsetneq" : "\u228B\uFE00" ,
"varsupsetneqq" : "\u2ACC\uFE00" ,
"vartheta" : "\u03D1" ,
"vartriangleleft" : "\u22B2" ,
"vartriangleright" : "\u22B3" ,
"Vbar" : "\u2AEB" ,
"vBar" : "\u2AE8" ,
"vBarv" : "\u2AE9" ,
"Vcy" : "\u0412" ,
"vcy" : "\u0432" ,
"VDash" : "\u22AB" ,
"Vdash" : "\u22A9" ,
"vDash" : "\u22A8" ,
"vdash" : "\u22A2" ,
"Vdashl" : "\u2AE6" ,
"Vee" : "\u22C1" ,
"vee" : "\u2228" ,
"veebar" : "\u22BB" ,
"veeeq" : "\u225A" ,
"vellip" : "\u22EE" ,
"Verbar" : "\u2016" ,
"verbar" : "\u007C" ,
"Vert" : "\u2016" ,
"vert" : "\u007C" ,
"VerticalBar" : "\u2223" ,
"VerticalLine" : "\u007C" ,
"VerticalSeparator" : "\u2758" ,
"VerticalTilde" : "\u2240" ,
"VeryThinSpace" : "\u200A" ,
"Vfr" : "\uD835\uDD19" ,
"vfr" : "\uD835\uDD33" ,
"vltri" : "\u22B2" ,
"vnsub" : "\u2282\u20D2" ,
"vnsup" : "\u2283\u20D2" ,
"Vopf" : "\uD835\uDD4D" ,
"vopf" : "\uD835\uDD67" ,
"vprop" : "\u221D" ,
"vrtri" : "\u22B3" ,
"Vscr" : "\uD835\uDCB1" ,
"vscr" : "\uD835\uDCCB" ,
"vsubnE" : "\u2ACB\uFE00" ,
"vsubne" : "\u228A\uFE00" ,
"vsupnE" : "\u2ACC\uFE00" ,
"vsupne" : "\u228B\uFE00" ,
"Vvdash" : "\u22AA" ,
"vzigzag" : "\u299A" ,
"Wcirc" : "\u0174" ,
"wcirc" : "\u0175" ,
"wedbar" : "\u2A5F" ,
"Wedge" : "\u22C0" ,
"wedge" : "\u2227" ,
"wedgeq" : "\u2259" ,
"weierp" : "\u2118" ,
"Wfr" : "\uD835\uDD1A" ,
"wfr" : "\uD835\uDD34" ,
"Wopf" : "\uD835\uDD4E" ,
"wopf" : "\uD835\uDD68" ,
"wp" : "\u2118" ,
"wr" : "\u2240" ,
"wreath" : "\u2240" ,
"Wscr" : "\uD835\uDCB2" ,
"wscr" : "\uD835\uDCCC" ,
"xcap" : "\u22C2" ,
"xcirc" : "\u25EF" ,
"xcup" : "\u22C3" ,
"xdtri" : "\u25BD" ,
"Xfr" : "\uD835\uDD1B" ,
"xfr" : "\uD835\uDD35" ,
"xhArr" : "\u27FA" ,
"xharr" : "\u27F7" ,
"Xi" : "\u039E" ,
"xi" : "\u03BE" ,
"xlArr" : "\u27F8" ,
"xlarr" : "\u27F5" ,
"xmap" : "\u27FC" ,
"xnis" : "\u22FB" ,
"xodot" : "\u2A00" ,
"Xopf" : "\uD835\uDD4F" ,
"xopf" : "\uD835\uDD69" ,
"xoplus" : "\u2A01" ,
"xotime" : "\u2A02" ,
"xrArr" : "\u27F9" ,
"xrarr" : "\u27F6" ,
"Xscr" : "\uD835\uDCB3" ,
"xscr" : "\uD835\uDCCD" ,
"xsqcup" : "\u2A06" ,
"xuplus" : "\u2A04" ,
"xutri" : "\u25B3" ,
"xvee" : "\u22C1" ,
"xwedge" : "\u22C0" ,
"Yacute" : "\u00DD" ,
"yacute" : "\u00FD" ,
"YAcy" : "\u042F" ,
"yacy" : "\u044F" ,
"Ycirc" : "\u0176" ,
"ycirc" : "\u0177" ,
"Ycy" : "\u042B" ,
"ycy" : "\u044B" ,
"yen" : "\u00A5" ,
"Yfr" : "\uD835\uDD1C" ,
"yfr" : "\uD835\uDD36" ,
"YIcy" : "\u0407" ,
"yicy" : "\u0457" ,
"Yopf" : "\uD835\uDD50" ,
"yopf" : "\uD835\uDD6A" ,
"Yscr" : "\uD835\uDCB4" ,
"yscr" : "\uD835\uDCCE" ,
"YUcy" : "\u042E" ,
"yucy" : "\u044E" ,
"Yuml" : "\u0178" ,
"yuml" : "\u00FF" ,
"Zacute" : "\u0179" ,
"zacute" : "\u017A" ,
"Zcaron" : "\u017D" ,
"zcaron" : "\u017E" ,
"Zcy" : "\u0417" ,
"zcy" : "\u0437" ,
"Zdot" : "\u017B" ,
"zdot" : "\u017C" ,
"zeetrf" : "\u2128" ,
"ZeroWidthSpace" : "\u200B" ,
"Zeta" : "\u0396" ,
"zeta" : "\u03B6" ,
"Zfr" : "\u2128" ,
"zfr" : "\uD835\uDD37" ,
"ZHcy" : "\u0416" ,
"zhcy" : "\u0436" ,
"zigrarr" : "\u21DD" ,
"Zopf" : "\u2124" ,
"zopf" : "\uD835\uDD6B" ,
"Zscr" : "\uD835\uDCB5" ,
"zscr" : "\uD835\uDCCF" ,
"zwj" : "\u200D" ,
"zwnj" : "\u200C"
} ;
} , { } ] , 2 : [ function ( require , module , exports ) {
// List of valid html blocks names, accorting to commonmark spec
// http://jgm.github.io/CommonMark/spec.html#html-blocks
'use strict' ;
var html _blocks = { } ;
[
'article' ,
'aside' ,
'button' ,
'blockquote' ,
'body' ,
'canvas' ,
'caption' ,
'col' ,
'colgroup' ,
'dd' ,
'div' ,
'dl' ,
'dt' ,
'embed' ,
'fieldset' ,
'figcaption' ,
'figure' ,
'footer' ,
'form' ,
'h1' ,
'h2' ,
'h3' ,
'h4' ,
'h5' ,
'h6' ,
'header' ,
'hgroup' ,
'hr' ,
'iframe' ,
'li' ,
'map' ,
'object' ,
'ol' ,
'output' ,
'p' ,
'pre' ,
'progress' ,
'script' ,
'section' ,
'style' ,
'table' ,
'tbody' ,
'td' ,
'textarea' ,
'tfoot' ,
'th' ,
'tr' ,
'thead' ,
'ul' ,
'video'
] . forEach ( function ( name ) { html _blocks [ name ] = true ; } ) ;
module . exports = html _blocks ;
} , { } ] , 3 : [ function ( require , module , exports ) {
// Regexps to match html elements
'use strict' ;
function replace ( regex , options ) {
regex = regex . source ;
options = options || '' ;
return function self ( name , val ) {
if ( ! name ) {
return new RegExp ( regex , options ) ;
}
val = val . source || val ;
regex = regex . replace ( name , val ) ;
return self ;
} ;
}
var attr _name = /[a-zA-Z_:][a-zA-Z0-9:._-]*/ ;
var unquoted = /[^"'=<>`\x00-\x20]+/ ;
var single _quoted = /'[^']*'/ ;
var double _quoted = /"[^"]*"/ ;
/*eslint no-spaced-func:0*/
var attr _value = replace ( /(?:unquoted|single_quoted|double_quoted)/ )
( 'unquoted' , unquoted )
( 'single_quoted' , single _quoted )
( 'double_quoted' , double _quoted )
( ) ;
var attribute = replace ( /(?:\s+attr_name(?:\s*=\s*attr_value)?)/ )
( 'attr_name' , attr _name )
( 'attr_value' , attr _value )
( ) ;
var open _tag = replace ( /<[A-Za-z][A-Za-z0-9]*attribute*\s*\/?>/ )
( 'attribute' , attribute )
( ) ;
var close _tag = /<\/[A-Za-z][A-Za-z0-9]*\s*>/ ;
var comment = /<!--([^-]+|[-][^-]+)*-->/ ;
var processing = /<[?].*?[?]>/ ;
var declaration = /<![A-Z]+\s+[^>]*>/ ;
var cdata = /<!\[CDATA\[([^\]]+|\][^\]]|\]\][^>])*\]\]>/ ;
var HTML _TAG _RE = replace ( /^(?:open_tag|close_tag|comment|processing|declaration|cdata)/ )
( 'open_tag' , open _tag )
( 'close_tag' , close _tag )
( 'comment' , comment )
( 'processing' , processing )
( 'declaration' , declaration )
( 'cdata' , cdata )
( ) ;
module . exports . HTML _TAG _RE = HTML _TAG _RE ;
} , { } ] , 4 : [ function ( require , module , exports ) {
// List of valid url schemas, accorting to commonmark spec
// http://jgm.github.io/CommonMark/spec.html#autolinks
'use strict' ;
module . exports = [
'coap' ,
'doi' ,
'javascript' ,
'aaa' ,
'aaas' ,
'about' ,
'acap' ,
'cap' ,
'cid' ,
'crid' ,
'data' ,
'dav' ,
'dict' ,
'dns' ,
'file' ,
'ftp' ,
'geo' ,
'go' ,
'gopher' ,
'h323' ,
'http' ,
'https' ,
'iax' ,
'icap' ,
'im' ,
'imap' ,
'info' ,
'ipp' ,
'iris' ,
'iris.beep' ,
'iris.xpc' ,
'iris.xpcs' ,
'iris.lwz' ,
'ldap' ,
'mailto' ,
'mid' ,
'msrp' ,
'msrps' ,
'mtqp' ,
'mupdate' ,
'news' ,
'nfs' ,
'ni' ,
'nih' ,
'nntp' ,
'opaquelocktoken' ,
'pop' ,
'pres' ,
'rtsp' ,
'service' ,
'session' ,
'shttp' ,
'sieve' ,
'sip' ,
'sips' ,
'sms' ,
'snmp' ,
'soap.beep' ,
'soap.beeps' ,
'tag' ,
'tel' ,
'telnet' ,
'tftp' ,
'thismessage' ,
'tn3270' ,
'tip' ,
'tv' ,
'urn' ,
'vemmi' ,
'ws' ,
'wss' ,
'xcon' ,
'xcon-userid' ,
'xmlrpc.beep' ,
'xmlrpc.beeps' ,
'xmpp' ,
'z39.50r' ,
'z39.50s' ,
'adiumxtra' ,
'afp' ,
'afs' ,
'aim' ,
'apt' ,
'attachment' ,
'aw' ,
'beshare' ,
'bitcoin' ,
'bolo' ,
'callto' ,
'chrome' ,
'chrome-extension' ,
'com-eventbrite-attendee' ,
'content' ,
'cvs' ,
'dlna-playsingle' ,
'dlna-playcontainer' ,
'dtn' ,
'dvb' ,
'ed2k' ,
'facetime' ,
'feed' ,
'finger' ,
'fish' ,
'gg' ,
'git' ,
'gizmoproject' ,
'gtalk' ,
'hcp' ,
'icon' ,
'ipn' ,
'irc' ,
'irc6' ,
'ircs' ,
'itms' ,
'jar' ,
'jms' ,
'keyparc' ,
'lastfm' ,
'ldaps' ,
'magnet' ,
'maps' ,
'market' ,
'message' ,
'mms' ,
'ms-help' ,
'msnim' ,
'mumble' ,
'mvn' ,
'notes' ,
'oid' ,
'palm' ,
'paparazzi' ,
'platform' ,
'proxy' ,
'psyc' ,
'query' ,
'res' ,
'resource' ,
'rmi' ,
'rsync' ,
'rtmp' ,
'secondlife' ,
'sftp' ,
'sgn' ,
'skype' ,
'smb' ,
'soldat' ,
'spotify' ,
'ssh' ,
'steam' ,
'svn' ,
'teamspeak' ,
'things' ,
'udp' ,
'unreal' ,
'ut2004' ,
'ventrilo' ,
'view-source' ,
'webcal' ,
'wtai' ,
'wyciwyg' ,
'xfire' ,
'xri' ,
'ymsgr'
] ;
} , { } ] , 5 : [ function ( require , module , exports ) {
// Utilities
//
'use strict' ;
function _class ( obj ) { return Object . prototype . toString . call ( obj ) ; }
function isString ( obj ) { return _class ( obj ) === '[object String]' ; }
var _hasOwnProperty = Object . prototype . hasOwnProperty ;
function has ( object , key ) {
return object ? _hasOwnProperty . call ( object , key ) : false ;
}
// Merge objects
//
function assign ( obj /*from1, from2, from3, ...*/ ) {
var sources = Array . prototype . slice . call ( arguments , 1 ) ;
sources . forEach ( function ( source ) {
if ( ! source ) { return ; }
if ( typeof source !== 'object' ) {
throw new TypeError ( source + 'must be object' ) ;
}
Object . keys ( source ) . forEach ( function ( key ) {
obj [ key ] = source [ key ] ;
} ) ;
} ) ;
return obj ;
}
////////////////////////////////////////////////////////////////////////////////
var UNESCAPE _MD _RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g ;
function unescapeMd ( str ) {
if ( str . indexOf ( '\\' ) < 0 ) { return str ; }
return str . replace ( UNESCAPE _MD _RE , '$1' ) ;
}
////////////////////////////////////////////////////////////////////////////////
function isValidEntityCode ( c ) {
/*eslint no-bitwise:0*/
// broken sequence
if ( c >= 0xD800 && c <= 0xDFFF ) { return false ; }
// never used
if ( c >= 0xFDD0 && c <= 0xFDEF ) { return false ; }
if ( ( c & 0xFFFF ) === 0xFFFF || ( c & 0xFFFF ) === 0xFFFE ) { return false ; }
// control codes
if ( c >= 0x00 && c <= 0x08 ) { return false ; }
if ( c === 0x0B ) { return false ; }
if ( c >= 0x0E && c <= 0x1F ) { return false ; }
if ( c >= 0x7F && c <= 0x9F ) { return false ; }
// out of range
if ( c > 0x10FFFF ) { return false ; }
return true ;
}
function fromCodePoint ( c ) {
/*eslint no-bitwise:0*/
if ( c > 0xffff ) {
c -= 0x10000 ;
var surrogate1 = 0xd800 + ( c >> 10 ) ,
surrogate2 = 0xdc00 + ( c & 0x3ff ) ;
return String . fromCharCode ( surrogate1 , surrogate2 ) ;
}
return String . fromCharCode ( c ) ;
}
var NAMED _ENTITY _RE = /&([a-z#][a-z0-9]{1,31});/gi ;
var DIGITAL _ENTITY _TEST _RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i ;
var entities = require ( './entities' ) ;
function replaceEntityPattern ( match , name ) {
var code = 0 ;
if ( has ( entities , name ) ) {
return entities [ name ] ;
} else if ( name . charCodeAt ( 0 ) === 0x23 /* # */ && DIGITAL _ENTITY _TEST _RE . test ( name ) ) {
code = name [ 1 ] . toLowerCase ( ) === 'x' ?
parseInt ( name . slice ( 2 ) , 16 )
:
parseInt ( name . slice ( 1 ) , 10 ) ;
if ( isValidEntityCode ( code ) ) {
return fromCodePoint ( code ) ;
}
}
return match ;
}
function replaceEntities ( str ) {
if ( str . indexOf ( '&' ) < 0 ) { return str ; }
return str . replace ( NAMED _ENTITY _RE , replaceEntityPattern ) ;
}
////////////////////////////////////////////////////////////////////////////////
var HTML _ESCAPE _TEST _RE = /[&<>"]/ ;
var HTML _ESCAPE _REPLACE _RE = /[&<>"]/g ;
var HTML _REPLACEMENTS = {
'&' : '&' ,
'<' : '<' ,
'>' : '>' ,
'"' : '"'
} ;
function replaceUnsafeChar ( ch ) {
return HTML _REPLACEMENTS [ ch ] ;
}
function escapeHtml ( str ) {
if ( HTML _ESCAPE _TEST _RE . test ( str ) ) {
return str . replace ( HTML _ESCAPE _REPLACE _RE , replaceUnsafeChar ) ;
}
return str ;
}
////////////////////////////////////////////////////////////////////////////////
exports . assign = assign ;
exports . isString = isString ;
exports . has = has ;
exports . unescapeMd = unescapeMd ;
exports . isValidEntityCode = isValidEntityCode ;
exports . fromCodePoint = fromCodePoint ;
exports . replaceEntities = replaceEntities ;
exports . escapeHtml = escapeHtml ;
} , { "./entities" : 1 } ] , 6 : [ function ( require , module , exports ) {
// Commonmark default options
'use strict' ;
module . exports = {
options : {
html : true , // Enable HTML tags in source
xhtmlOut : true , // Use '/' to close single tags (<br />)
breaks : false , // Convert '\n' in paragraphs into <br>
langPrefix : 'language-' , // CSS language prefix for fenced blocks
linkify : false , // autoconvert URL-like texts to links
// Enable some language-neutral replacements + quotes beautification
typographer : false ,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes : '“”‘’' ,
// Highlighter function. Should return escaped HTML,
// or '' if input not changed
//
// function (/*str, lang*/) { return ''; }
//
highlight : null ,
maxNesting : 20 // Internal protection, recursion limit
} ,
components : {
core : {
rules : [
'block' ,
'inline' ,
'references' ,
'abbr2'
]
} ,
block : {
rules : [
'blockquote' ,
'code' ,
'fences' ,
'heading' ,
'hr' ,
'htmlblock' ,
'lheading' ,
'list' ,
'paragraph'
]
} ,
inline : {
rules : [
'autolink' ,
'backticks' ,
'emphasis' ,
'entity' ,
'escape' ,
'htmltag' ,
'links' ,
'newline' ,
'text'
]
}
}
} ;
} , { } ] , 7 : [ function ( require , module , exports ) {
// Remarkable default options
'use strict' ;
module . exports = {
options : {
html : false , // Enable HTML tags in source
xhtmlOut : false , // Use '/' to close single tags (<br />)
breaks : false , // Convert '\n' in paragraphs into <br>
langPrefix : 'language-' , // CSS language prefix for fenced blocks
linkify : false , // autoconvert URL-like texts to links
// Enable some language-neutral replacements + quotes beautification
typographer : false ,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes : '“”‘’' ,
// Highlighter function. Should return escaped HTML,
// or '' if input not changed
//
// function (/*str, lang*/) { return ''; }
//
highlight : null ,
maxNesting : 20 // Internal protection, recursion limit
} ,
components : {
core : {
rules : [
'block' ,
'inline' ,
'references' ,
'replacements' ,
'linkify' ,
'smartquotes' ,
'references' ,
'abbr2' ,
'footnote_tail'
]
} ,
block : {
rules : [
'blockquote' ,
'code' ,
'fences' ,
'heading' ,
'hr' ,
'htmlblock' ,
'lheading' ,
'list' ,
'paragraph' ,
'table'
]
} ,
inline : {
rules : [
'autolink' ,
'backticks' ,
'del' ,
'emphasis' ,
'entity' ,
'escape' ,
'footnote_ref' ,
'htmltag' ,
'links' ,
'newline' ,
'text'
]
}
}
} ;
} , { } ] , 8 : [ function ( require , module , exports ) {
// Remarkable default options
'use strict' ;
module . exports = {
options : {
html : false , // Enable HTML tags in source
xhtmlOut : false , // Use '/' to close single tags (<br />)
breaks : false , // Convert '\n' in paragraphs into <br>
langPrefix : 'language-' , // CSS language prefix for fenced blocks
linkify : false , // autoconvert URL-like texts to links
// Enable some language-neutral replacements + quotes beautification
typographer : false ,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Set doubles to '«»' for Russian, '„“' for German.
quotes : '“”‘’' ,
// Highlighter function. Should return escaped HTML,
// or '' if input not changed
//
// function (/*str, lang*/) { return ''; }
//
highlight : null ,
maxNesting : 20 // Internal protection, recursion limit
} ,
components : {
// Don't restrict core/block/inline rules
core : { } ,
block : { } ,
inline : { }
}
} ;
} , { } ] , 9 : [ function ( require , module , exports ) {
'use strict' ;
var replaceEntities = require ( '../common/utils' ) . replaceEntities ;
module . exports = function normalizeLink ( url ) {
var normalized = replaceEntities ( url ) ;
// We don't care much about result of mailformed URIs,
// but shoud not throw exception.
try {
normalized = decodeURI ( normalized ) ;
} catch ( _ _ ) { }
return encodeURI ( normalized ) ;
} ;
} , { "../common/utils" : 5 } ] , 10 : [ function ( require , module , exports ) {
'use strict' ;
module . exports = function normalizeReference ( str ) {
// use .toUpperCase() instead of .toLowerCase()
// here to avoid a conflict with Object.prototype
// members (most notably, `__proto__`)
return str . trim ( ) . replace ( /\s+/g , ' ' ) . toUpperCase ( ) ;
} ;
} , { } ] , 11 : [ function ( require , module , exports ) {
// Parse link destination
//
// on success it returns a string and updates state.pos;
// on failure it returns null
//
'use strict' ;
var normalizeLink = require ( './normalize_link' ) ;
var unescapeMd = require ( '../common/utils' ) . unescapeMd ;
module . exports = function parseLinkDestination ( state , pos ) {
var code , level , link ,
start = pos ,
max = state . posMax ;
if ( state . src . charCodeAt ( pos ) === 0x3C /* < */ ) {
pos ++ ;
while ( pos < max ) {
code = state . src . charCodeAt ( pos ) ;
if ( code === 0x0A /* \n */ ) { return false ; }
if ( code === 0x3E /* > */ ) {
link = normalizeLink ( unescapeMd ( state . src . slice ( start + 1 , pos ) ) ) ;
if ( ! state . parser . validateLink ( link ) ) { return false ; }
state . pos = pos + 1 ;
state . linkContent = link ;
return true ;
}
if ( code === 0x5C /* \ */ && pos + 1 < max ) {
pos += 2 ;
continue ;
}
pos ++ ;
}
// no closing '>'
return false ;
}
// this should be ... } else { ... branch
level = 0 ;
while ( pos < max ) {
code = state . src . charCodeAt ( pos ) ;
if ( code === 0x20 ) { break ; }
// ascii control characters
if ( code < 0x20 || code === 0x7F ) { break ; }
if ( code === 0x5C /* \ */ && pos + 1 < max ) {
pos += 2 ;
continue ;
}
if ( code === 0x28 /* ( */ ) {
level ++ ;
if ( level > 1 ) { break ; }
}
if ( code === 0x29 /* ) */ ) {
level -- ;
if ( level < 0 ) { break ; }
}
pos ++ ;
}
if ( start === pos ) { return false ; }
link = normalizeLink ( unescapeMd ( state . src . slice ( start , pos ) ) ) ;
if ( ! state . parser . validateLink ( link ) ) { return false ; }
state . linkContent = link ;
state . pos = pos ;
return true ;
} ;
} , { "../common/utils" : 5 , "./normalize_link" : 9 } ] , 12 : [ function ( require , module , exports ) {
// Parse link label
//
// this function assumes that first character ("[") already matches;
// returns the end of the label
//
'use strict' ;
module . exports = function parseLinkLabel ( state , start ) {
var level , found , marker ,
labelEnd = - 1 ,
max = state . posMax ,
oldPos = state . pos ,
oldFlag = state . isInLabel ;
if ( state . isInLabel ) { return - 1 ; }
if ( state . labelUnmatchedScopes ) {
state . labelUnmatchedScopes -- ;
return - 1 ;
}
state . pos = start + 1 ;
state . isInLabel = true ;
level = 1 ;
while ( state . pos < max ) {
marker = state . src . charCodeAt ( state . pos ) ;
if ( marker === 0x5B /* [ */ ) {
level ++ ;
} else if ( marker === 0x5D /* ] */ ) {
level -- ;
if ( level === 0 ) {
found = true ;
break ;
}
}
state . parser . skipToken ( state ) ;
}
if ( found ) {
labelEnd = state . pos ;
state . labelUnmatchedScopes = 0 ;
} else {
state . labelUnmatchedScopes = level - 1 ;
}
// restore old state
state . pos = oldPos ;
state . isInLabel = oldFlag ;
return labelEnd ;
} ;
} , { } ] , 13 : [ function ( require , module , exports ) {
// Parse link title
//
// on success it returns a string and updates state.pos;
// on failure it returns null
//
'use strict' ;
var unescapeMd = require ( '../common/utils' ) . unescapeMd ;
module . exports = function parseLinkTitle ( state , pos ) {
var code ,
start = pos ,
max = state . posMax ,
marker = state . src . charCodeAt ( pos ) ;
if ( marker !== 0x22 /* " */ && marker !== 0x27 /* ' */ && marker !== 0x28 /* ( */ ) { return false ; }
pos ++ ;
// if opening marker is "(", switch it to closing marker ")"
if ( marker === 0x28 ) { marker = 0x29 ; }
while ( pos < max ) {
code = state . src . charCodeAt ( pos ) ;
if ( code === marker ) {
state . pos = pos + 1 ;
state . linkContent = unescapeMd ( state . src . slice ( start + 1 , pos ) ) ;
return true ;
}
if ( code === 0x5C /* \ */ && pos + 1 < max ) {
pos += 2 ;
continue ;
}
pos ++ ;
}
return false ;
} ;
} , { "../common/utils" : 5 } ] , 14 : [ function ( require , module , exports ) {
// Main perser class
'use strict' ;
var assign = require ( './common/utils' ) . assign ;
var isString = require ( './common/utils' ) . isString ;
var Renderer = require ( './renderer' ) ;
var ParserCore = require ( './parser_core' ) ;
var ParserBlock = require ( './parser_block' ) ;
var ParserInline = require ( './parser_inline' ) ;
var Ruler = require ( './ruler' ) ;
var config = {
'default' : require ( './configs/default' ) ,
full : require ( './configs/full' ) ,
commonmark : require ( './configs/commonmark' )
} ;
function StateCore ( self , src , env ) {
this . src = src ;
this . env = env ;
this . options = self . options ;
this . tokens = [ ] ;
this . inlineMode = false ;
this . inline = self . inline ;
this . block = self . block ;
this . renderer = self . renderer ;
this . typographer = self . typographer ;
}
// Main class
//
function Remarkable ( presetName , options ) {
if ( ! options ) {
if ( ! isString ( presetName ) ) {
options = presetName || { } ;
presetName = 'default' ;
}
}
this . inline = new ParserInline ( ) ;
this . block = new ParserBlock ( ) ;
this . core = new ParserCore ( ) ;
this . renderer = new Renderer ( ) ;
this . ruler = new Ruler ( ) ;
this . options = { } ;
this . configure ( config [ presetName ] ) ;
if ( options ) { this . set ( options ) ; }
}
// Set options, if you did not passed those to constructor
//
Remarkable . prototype . set = function ( options ) {
assign ( this . options , options ) ;
} ;
// Batch loader for components rules states & options
//
Remarkable . prototype . configure = function ( presets ) {
var self = this ;
if ( ! presets ) { throw new Error ( 'Wrong `remarkable` preset, check name/content' ) ; }
if ( presets . options ) { self . set ( presets . options ) ; }
if ( presets . components ) {
Object . keys ( presets . components ) . forEach ( function ( name ) {
if ( presets . components [ name ] . rules ) {
self [ name ] . ruler . enable ( presets . components [ name ] . rules , true ) ;
}
} ) ;
}
} ;
// Sugar for curried plugins init:
//
// var md = new Remarkable();
//
// md.use(plugin1)
// .use(plugin2, opts)
// .use(plugin3);
//
Remarkable . prototype . use = function ( plugin , opts ) {
plugin ( this , opts ) ;
return this ;
} ;
// Parse input string, returns tokens array. Modify `env` with
// definitions data.
//
Remarkable . prototype . parse = function ( src , env ) {
var state = new StateCore ( this , src , env ) ;
this . core . process ( state ) ;
return state . tokens ;
} ;
// Main method that does all magic :)
//
Remarkable . prototype . render = function ( src , env ) {
env = env || { } ;
return this . renderer . render ( this . parse ( src , env ) , this . options , env ) ;
} ;
// Parse content as single string
//
Remarkable . prototype . parseInline = function ( src , env ) {
var state = new StateCore ( this , src , env ) ;
state . inlineMode = true ;
this . core . process ( state ) ;
return state . tokens ;
} ;
// Render single string, without wrapping it to paragraphs
//
Remarkable . prototype . renderInline = function ( src , env ) {
env = env || { } ;
return this . renderer . render ( this . parseInline ( src , env ) , this . options , env ) ;
} ;
module . exports = Remarkable ;
// Expose helpers, useful for custom renderer functions
module . exports . utils = require ( './common/utils' ) ;
} , { "./common/utils" : 5 , "./configs/commonmark" : 6 , "./configs/default" : 7 , "./configs/full" : 8 , "./parser_block" : 15 , "./parser_core" : 16 , "./parser_inline" : 17 , "./renderer" : 18 , "./ruler" : 19 } ] , 15 : [ function ( require , module , exports ) {
// Block parser
'use strict' ;
var Ruler = require ( './ruler' ) ;
var StateBlock = require ( './rules_block/state_block' ) ;
var _rules = [
[ 'code' , require ( './rules_block/code' ) ] ,
[ 'fences' , require ( './rules_block/fences' ) , [ 'paragraph' , 'blockquote' , 'list' ] ] ,
[ 'blockquote' , require ( './rules_block/blockquote' ) , [ 'paragraph' , 'blockquote' , 'list' ] ] ,
[ 'hr' , require ( './rules_block/hr' ) , [ 'paragraph' , 'blockquote' , 'list' ] ] ,
[ 'list' , require ( './rules_block/list' ) , [ 'paragraph' , 'blockquote' ] ] ,
[ 'footnote' , require ( './rules_block/footnote' ) , [ 'paragraph' ] ] ,
[ 'heading' , require ( './rules_block/heading' ) , [ 'paragraph' , 'blockquote' ] ] ,
[ 'lheading' , require ( './rules_block/lheading' ) ] ,
[ 'htmlblock' , require ( './rules_block/htmlblock' ) , [ 'paragraph' , 'blockquote' ] ] ,
[ 'table' , require ( './rules_block/table' ) , [ 'paragraph' ] ] ,
[ 'deflist' , require ( './rules_block/deflist' ) , [ 'paragraph' ] ] ,
[ 'paragraph' , require ( './rules_block/paragraph' ) ]
] ;
// Block Parser class
//
function ParserBlock ( ) {
this . ruler = new Ruler ( ) ;
for ( var i = 0 ; i < _rules . length ; i ++ ) {
this . ruler . push ( _rules [ i ] [ 0 ] , _rules [ i ] [ 1 ] , { alt : ( _rules [ i ] [ 2 ] || [ ] ) . slice ( ) } ) ;
}
}
// Generate tokens for input range
//
ParserBlock . prototype . tokenize = function ( state , startLine , endLine ) {
var ok , i ,
rules = this . ruler . getRules ( '' ) ,
len = rules . length ,
line = startLine ,
hasEmptyLines = false ;
while ( line < endLine ) {
state . line = line = state . skipEmptyLines ( line ) ;
if ( line >= endLine ) { break ; }
// Termination condition for nested calls.
// Nested calls currently used for blockquotes & lists
if ( state . tShift [ line ] < state . blkIndent ) { break ; }
// Try all possible rules.
// On success, rule should:
//
// - update `state.line`
// - update `state.tokens`
// - return true
for ( i = 0 ; i < len ; i ++ ) {
ok = rules [ i ] ( state , line , endLine , false ) ;
if ( ok ) { break ; }
}
// set state.tight iff we had an empty line before current tag
// i.e. latest empty line should not count
state . tight = ! hasEmptyLines ;
// paragraph might "eat" one newline after it in nested lists
if ( state . isEmpty ( state . line - 1 ) ) {
hasEmptyLines = true ;
}
line = state . line ;
if ( line < endLine && state . isEmpty ( line ) ) {
hasEmptyLines = true ;
line ++ ;
// two empty lines should stop the parser in list mode
if ( line < endLine && state . parentType === 'list' && state . isEmpty ( line ) ) { break ; }
state . line = line ;
}
}
} ;
var TABS _SCAN _RE = /[\n\t]/g ;
var NEWLINES _RE = /\r[\n\u0085]|[\u2424\u2028\u0085]/g ;
var SPACES _RE = /\u00a0/g ;
ParserBlock . prototype . parse = function ( src , options , env , outTokens ) {
var state , lineStart = 0 , lastTabPos = 0 ;
if ( ! src ) { return [ ] ; }
// Normalize spaces
src = src . replace ( SPACES _RE , ' ' ) ;
// Normalize newlines
src = src . replace ( NEWLINES _RE , '\n' ) ;
// Replace tabs with proper number of spaces (1..4)
if ( src . indexOf ( '\t' ) >= 0 ) {
src = src . replace ( TABS _SCAN _RE , function ( match , offset ) {
var result ;
if ( src . charCodeAt ( offset ) === 0x0A ) {
lineStart = offset + 1 ;
lastTabPos = 0 ;
return match ;
}
result = ' ' . slice ( ( offset - lineStart - lastTabPos ) % 4 ) ;
lastTabPos = offset - lineStart + 1 ;
return result ;
} ) ;
}
state = new StateBlock (
src ,
this ,
options ,
env ,
outTokens
) ;
this . tokenize ( state , state . line , state . lineMax ) ;
} ;
module . exports = ParserBlock ;
} , { "./ruler" : 19 , "./rules_block/blockquote" : 20 , "./rules_block/code" : 21 , "./rules_block/deflist" : 22 , "./rules_block/fences" : 23 , "./rules_block/footnote" : 24 , "./rules_block/heading" : 25 , "./rules_block/hr" : 26 , "./rules_block/htmlblock" : 27 , "./rules_block/lheading" : 28 , "./rules_block/list" : 29 , "./rules_block/paragraph" : 30 , "./rules_block/state_block" : 31 , "./rules_block/table" : 32 } ] , 16 : [ function ( require , module , exports ) {
// Class of top level (`core`) rules
//
'use strict' ;
var Ruler = require ( './ruler' ) ;
var _rules = [
[ 'block' , require ( './rules_core/block' ) ] ,
[ 'abbr' , require ( './rules_core/abbr' ) ] ,
[ 'references' , require ( './rules_core/references' ) ] ,
[ 'inline' , require ( './rules_core/inline' ) ] ,
[ 'footnote_tail' , require ( './rules_core/footnote_tail' ) ] ,
[ 'abbr2' , require ( './rules_core/abbr2' ) ] ,
[ 'replacements' , require ( './rules_core/replacements' ) ] ,
[ 'smartquotes' , require ( './rules_core/smartquotes' ) ] ,
[ 'linkify' , require ( './rules_core/linkify' ) ]
] ;
function Core ( ) {
this . options = { } ;
this . ruler = new Ruler ( ) ;
for ( var i = 0 ; i < _rules . length ; i ++ ) {
this . ruler . push ( _rules [ i ] [ 0 ] , _rules [ i ] [ 1 ] ) ;
}
}
Core . prototype . process = function ( state ) {
var i , l , rules ;
rules = this . ruler . getRules ( '' ) ;
for ( i = 0 , l = rules . length ; i < l ; i ++ ) {
rules [ i ] ( state ) ;
}
} ;
module . exports = Core ;
} , { "./ruler" : 19 , "./rules_core/abbr" : 33 , "./rules_core/abbr2" : 34 , "./rules_core/block" : 35 , "./rules_core/footnote_tail" : 36 , "./rules_core/inline" : 37 , "./rules_core/linkify" : 38 , "./rules_core/references" : 39 , "./rules_core/replacements" : 40 , "./rules_core/smartquotes" : 41 } ] , 17 : [ function ( require , module , exports ) {
// Inline parser
'use strict' ;
var Ruler = require ( './ruler' ) ;
var StateInline = require ( './rules_inline/state_inline' ) ;
var replaceEntities = require ( './common/utils' ) . replaceEntities ;
////////////////////////////////////////////////////////////////////////////////
// Parser rules
var _rules = [
[ 'text' , require ( './rules_inline/text' ) ] ,
[ 'newline' , require ( './rules_inline/newline' ) ] ,
[ 'escape' , require ( './rules_inline/escape' ) ] ,
[ 'backticks' , require ( './rules_inline/backticks' ) ] ,
[ 'del' , require ( './rules_inline/del' ) ] ,
[ 'ins' , require ( './rules_inline/ins' ) ] ,
[ 'mark' , require ( './rules_inline/mark' ) ] ,
[ 'emphasis' , require ( './rules_inline/emphasis' ) ] ,
[ 'sub' , require ( './rules_inline/sub' ) ] ,
[ 'sup' , require ( './rules_inline/sup' ) ] ,
[ 'links' , require ( './rules_inline/links' ) ] ,
[ 'footnote_inline' , require ( './rules_inline/footnote_inline' ) ] ,
[ 'footnote_ref' , require ( './rules_inline/footnote_ref' ) ] ,
[ 'autolink' , require ( './rules_inline/autolink' ) ] ,
[ 'htmltag' , require ( './rules_inline/htmltag' ) ] ,
[ 'entity' , require ( './rules_inline/entity' ) ]
] ;
var BAD _PROTOCOLS = [ 'vbscript' , 'javascript' , 'file' ] ;
function validateLink ( url ) {
var str = url . trim ( ) . toLowerCase ( ) ;
// Care about digital entities "javascript:alert(1)"
str = replaceEntities ( str ) ;
if ( str . indexOf ( ':' ) >= 0 && BAD _PROTOCOLS . indexOf ( str . split ( ':' ) [ 0 ] ) >= 0 ) {
return false ;
}
return true ;
}
// Inline Parser class
//
function ParserInline ( ) {
// By default CommonMark allows too much in links
// If you need to restrict it - override this with your validator.
this . validateLink = validateLink ;
this . ruler = new Ruler ( ) ;
for ( var i = 0 ; i < _rules . length ; i ++ ) {
this . ruler . push ( _rules [ i ] [ 0 ] , _rules [ i ] [ 1 ] ) ;
}
}
// Skip single token by running all rules in validation mode;
// returns `true` if any rule reported success
//
ParserInline . prototype . skipToken = function ( state ) {
var i , cached _pos , pos = state . pos ,
rules = this . ruler . getRules ( '' ) ,
len = rules . length ;
if ( ( cached _pos = state . cacheGet ( pos ) ) > 0 ) {
state . pos = cached _pos ;
return ;
}
for ( i = 0 ; i < len ; i ++ ) {
if ( rules [ i ] ( state , true ) ) {
state . cacheSet ( pos , state . pos ) ;
return ;
}
}
state . pos ++ ;
state . cacheSet ( pos , state . pos ) ;
} ;
// Generate tokens for input range
//
ParserInline . prototype . tokenize = function ( state ) {
var ok , i ,
rules = this . ruler . getRules ( '' ) ,
len = rules . length ,
end = state . posMax ;
while ( state . pos < end ) {
// Try all possible rules.
// On success, rule should:
//
// - update `state.pos`
// - update `state.tokens`
// - return true
for ( i = 0 ; i < len ; i ++ ) {
ok = rules [ i ] ( state , false ) ;
if ( ok ) { break ; }
}
if ( ok ) {
if ( state . pos >= end ) { break ; }
continue ;
}
state . pending += state . src [ state . pos ++ ] ;
}
if ( state . pending ) {
state . pushPending ( ) ;
}
} ;
// Parse input string.
//
ParserInline . prototype . parse = function ( str , options , env , outTokens ) {
var state = new StateInline ( str , this , options , env , outTokens ) ;
this . tokenize ( state ) ;
} ;
module . exports = ParserInline ;
} , { "./common/utils" : 5 , "./ruler" : 19 , "./rules_inline/autolink" : 42 , "./rules_inline/backticks" : 43 , "./rules_inline/del" : 44 , "./rules_inline/emphasis" : 45 , "./rules_inline/entity" : 46 , "./rules_inline/escape" : 47 , "./rules_inline/footnote_inline" : 48 , "./rules_inline/footnote_ref" : 49 , "./rules_inline/htmltag" : 50 , "./rules_inline/ins" : 51 , "./rules_inline/links" : 52 , "./rules_inline/mark" : 53 , "./rules_inline/newline" : 54 , "./rules_inline/state_inline" : 55 , "./rules_inline/sub" : 56 , "./rules_inline/sup" : 57 , "./rules_inline/text" : 58 } ] , 18 : [ function ( require , module , exports ) {
'use strict' ;
var assign = require ( './common/utils' ) . assign ;
var has = require ( './common/utils' ) . has ;
var unescapeMd = require ( './common/utils' ) . unescapeMd ;
var replaceEntities = require ( './common/utils' ) . replaceEntities ;
var escapeHtml = require ( './common/utils' ) . escapeHtml ;
////////////////////////////////////////////////////////////////////////////////
// Helpers
function nextToken ( tokens , idx ) {
if ( ++ idx >= tokens . length - 2 ) { return idx ; }
if ( ( tokens [ idx ] . type === 'paragraph_open' && tokens [ idx ] . tight ) &&
( tokens [ idx + 1 ] . type === 'inline' && tokens [ idx + 1 ] . content . length === 0 ) &&
( tokens [ idx + 2 ] . type === 'paragraph_close' && tokens [ idx + 2 ] . tight ) ) {
return nextToken ( tokens , idx + 2 ) ;
}
return idx ;
}
// check if we need to hide '\n' before next token
function getBreak ( tokens , idx ) {
idx = nextToken ( tokens , idx ) ;
if ( idx < tokens . length &&
tokens [ idx ] . type === 'list_item_close' ) {
return '' ;
}
return '\n' ;
}
////////////////////////////////////////////////////////////////////////////////
var rules = { } ;
rules . blockquote _open = function ( /* tokens, idx, options, env */ ) {
return '<blockquote>\n' ;
} ;
rules . blockquote _close = function ( tokens , idx /*, options, env */ ) {
return '</blockquote>' + getBreak ( tokens , idx ) ;
} ;
rules . code = function ( tokens , idx /*, options, env */ ) {
if ( tokens [ idx ] . block ) {
return '<pre><code>' + escapeHtml ( tokens [ idx ] . content ) + '</code></pre>' + getBreak ( tokens , idx ) ;
}
return '<code>' + escapeHtml ( tokens [ idx ] . content ) + '</code>' ;
} ;
rules . fence = function ( tokens , idx , options , env , self ) {
var token = tokens [ idx ] ;
var langClass = '' ;
var langPrefix = options . langPrefix ;
var langName = '' , fenceName ;
var highlighted ;
if ( token . params ) {
//
// ```foo bar
//
// Try custom renderer "foo" first. That will simplify overwrite
// for diagrams, latex, and any other fenced block with custom look
//
fenceName = token . params . split ( /\s+/g ) [ 0 ] ;
if ( has ( self . rules . fence _custom , fenceName ) ) {
return self . rules . fence _custom [ fenceName ] ( tokens , idx , options , env , self ) ;
}
langName = escapeHtml ( replaceEntities ( unescapeMd ( fenceName ) ) ) ;
langClass = ' class="' + langPrefix + langName + '"' ;
}
if ( options . highlight ) {
highlighted = options . highlight ( token . content , langName ) || escapeHtml ( token . content ) ;
} else {
highlighted = escapeHtml ( token . content ) ;
}
return '<pre><code' + langClass + '>'
+ highlighted
+ '</code></pre>' + getBreak ( tokens , idx ) ;
} ;
rules . fence _custom = { } ;
rules . heading _open = function ( tokens , idx /*, options, env */ ) {
return '<h' + tokens [ idx ] . hLevel + '>' ;
} ;
rules . heading _close = function ( tokens , idx /*, options, env */ ) {
return '</h' + tokens [ idx ] . hLevel + '>\n' ;
} ;
rules . hr = function ( tokens , idx , options /*, env */ ) {
return ( options . xhtmlOut ? '<hr />' : '<hr>' ) + getBreak ( tokens , idx ) ;
} ;
rules . bullet _list _open = function ( /* tokens, idx, options, env */ ) {
return '<ul>\n' ;
} ;
rules . bullet _list _close = function ( tokens , idx /*, options, env */ ) {
return '</ul>' + getBreak ( tokens , idx ) ;
} ;
rules . list _item _open = function ( /* tokens, idx, options, env */ ) {
return '<li>' ;
} ;
rules . list _item _close = function ( /* tokens, idx, options, env */ ) {
return '</li>\n' ;
} ;
rules . ordered _list _open = function ( tokens , idx /*, options, env */ ) {
var token = tokens [ idx ] ;
return '<ol'
+ ( token . order > 1 ? ' start="' + token . order + '"' : '' )
+ '>\n' ;
} ;
rules . ordered _list _close = function ( tokens , idx /*, options, env */ ) {
return '</ol>' + getBreak ( tokens , idx ) ;
} ;
rules . paragraph _open = function ( tokens , idx /*, options, env */ ) {
return tokens [ idx ] . tight ? '' : '<p>' ;
} ;
rules . paragraph _close = function ( tokens , idx /*, options, env */ ) {
var addBreak = ! ( tokens [ idx ] . tight && idx && tokens [ idx - 1 ] . type === 'inline' && ! tokens [ idx - 1 ] . content ) ;
return ( tokens [ idx ] . tight ? '' : '</p>' ) + ( addBreak ? getBreak ( tokens , idx ) : '' ) ;
} ;
rules . link _open = function ( tokens , idx /*, options, env */ ) {
var title = tokens [ idx ] . title ? ( ' title="' + escapeHtml ( replaceEntities ( tokens [ idx ] . title ) ) + '"' ) : '' ;
return '<a href="' + escapeHtml ( tokens [ idx ] . href ) + '"' + title + '>' ;
} ;
rules . link _close = function ( /* tokens, idx, options, env */ ) {
return '</a>' ;
} ;
rules . image = function ( tokens , idx , options /*, env */ ) {
var src = ' src="' + escapeHtml ( tokens [ idx ] . src ) + '"' ;
var title = tokens [ idx ] . title ? ( ' title="' + escapeHtml ( replaceEntities ( tokens [ idx ] . title ) ) + '"' ) : '' ;
var alt = ' alt="' + ( tokens [ idx ] . alt ? escapeHtml ( replaceEntities ( tokens [ idx ] . alt ) ) : '' ) + '"' ;
var suffix = options . xhtmlOut ? ' /' : '' ;
return '<img' + src + alt + title + suffix + '>' ;
} ;
rules . table _open = function ( /* tokens, idx, options, env */ ) {
return '<table>\n' ;
} ;
rules . table _close = function ( /* tokens, idx, options, env */ ) {
return '</table>\n' ;
} ;
rules . thead _open = function ( /* tokens, idx, options, env */ ) {
return '<thead>\n' ;
} ;
rules . thead _close = function ( /* tokens, idx, options, env */ ) {
return '</thead>\n' ;
} ;
rules . tbody _open = function ( /* tokens, idx, options, env */ ) {
return '<tbody>\n' ;
} ;
rules . tbody _close = function ( /* tokens, idx, options, env */ ) {
return '</tbody>\n' ;
} ;
rules . tr _open = function ( /* tokens, idx, options, env */ ) {
return '<tr>' ;
} ;
rules . tr _close = function ( /* tokens, idx, options, env */ ) {
return '</tr>\n' ;
} ;
rules . th _open = function ( tokens , idx /*, options, env */ ) {
var token = tokens [ idx ] ;
return '<th'
+ ( token . align ? ' style="text-align:' + token . align + '"' : '' )
+ '>' ;
} ;
rules . th _close = function ( /* tokens, idx, options, env */ ) {
return '</th>' ;
} ;
rules . td _open = function ( tokens , idx /*, options, env */ ) {
var token = tokens [ idx ] ;
return '<td'
+ ( token . align ? ' style="text-align:' + token . align + '"' : '' )
+ '>' ;
} ;
rules . td _close = function ( /* tokens, idx, options, env */ ) {
return '</td>' ;
} ;
rules . strong _open = function ( /* tokens, idx, options, env */ ) {
return '<strong>' ;
} ;
rules . strong _close = function ( /* tokens, idx, options, env */ ) {
return '</strong>' ;
} ;
rules . em _open = function ( /* tokens, idx, options, env */ ) {
return '<em>' ;
} ;
rules . em _close = function ( /* tokens, idx, options, env */ ) {
return '</em>' ;
} ;
rules . del _open = function ( /* tokens, idx, options, env */ ) {
return '<del>' ;
} ;
rules . del _close = function ( /* tokens, idx, options, env */ ) {
return '</del>' ;
} ;
rules . ins _open = function ( /* tokens, idx, options, env */ ) {
return '<ins>' ;
} ;
rules . ins _close = function ( /* tokens, idx, options, env */ ) {
return '</ins>' ;
} ;
rules . mark _open = function ( /* tokens, idx, options, env */ ) {
return '<mark>' ;
} ;
rules . mark _close = function ( /* tokens, idx, options, env */ ) {
return '</mark>' ;
} ;
rules . sub = function ( tokens , idx /*, options, env */ ) {
return '<sub>' + escapeHtml ( tokens [ idx ] . content ) + '</sub>' ;
} ;
rules . sup = function ( tokens , idx /*, options, env */ ) {
return '<sup>' + escapeHtml ( tokens [ idx ] . content ) + '</sup>' ;
} ;
rules . hardbreak = function ( tokens , idx , options /*, env */ ) {
return options . xhtmlOut ? '<br />\n' : '<br>\n' ;
} ;
rules . softbreak = function ( tokens , idx , options /*, env */ ) {
return options . breaks ? ( options . xhtmlOut ? '<br />\n' : '<br>\n' ) : '\n' ;
} ;
rules . text = function ( tokens , idx /*, options, env */ ) {
return escapeHtml ( tokens [ idx ] . content ) ;
} ;
rules . htmlblock = function ( tokens , idx /*, options, env */ ) {
return tokens [ idx ] . content ;
} ;
rules . htmltag = function ( tokens , idx /*, options, env */ ) {
return tokens [ idx ] . content ;
} ;
rules . abbr _open = function ( tokens , idx /*, options, env */ ) {
return '<abbr title="' + escapeHtml ( replaceEntities ( tokens [ idx ] . title ) ) + '">' ;
} ;
rules . abbr _close = function ( /* tokens, idx, options, env */ ) {
return '</abbr>' ;
} ;
rules . footnote _ref = function ( tokens , idx ) {
var n = Number ( tokens [ idx ] . id + 1 ) . toString ( ) ;
var id = 'fnref' + n ;
if ( tokens [ idx ] . subId > 0 ) {
id += ':' + tokens [ idx ] . subId ;
}
return '<sup class="footnote-ref"><a href="#fn' + n + '" id="' + id + '">[' + n + ']</a></sup>' ;
} ;
rules . footnote _block _open = function ( tokens , idx , options ) {
return ( options . xhtmlOut ? '<hr class="footnotes-sep" />\n' : '<hr class="footnotes-sep">\n' ) +
'<section class="footnotes">\n' +
'<ol class="footnotes-list">\n' ;
} ;
rules . footnote _block _close = function ( ) {
return '</ol>\n</section>\n' ;
} ;
rules . footnote _open = function ( tokens , idx ) {
var id = Number ( tokens [ idx ] . id + 1 ) . toString ( ) ;
return '<li id="fn' + id + '" class="footnote-item">' ;
} ;
rules . footnote _close = function ( ) {
return '</li>\n' ;
} ;
rules . footnote _anchor = function ( tokens , idx ) {
var n = Number ( tokens [ idx ] . id + 1 ) . toString ( ) ;
var id = 'fnref' + n ;
if ( tokens [ idx ] . subId > 0 ) {
id += ':' + tokens [ idx ] . subId ;
}
return ' <a href="#' + id + '" class="footnote-backref">↩</a>' ;
} ;
rules . dl _open = function ( ) {
return '<dl>\n' ;
} ;
rules . dt _open = function ( ) {
return '<dt>' ;
} ;
rules . dd _open = function ( ) {
return '<dd>' ;
} ;
rules . dl _close = function ( ) {
return '</dl>\n' ;
} ;
rules . dt _close = function ( ) {
return '</dt>\n' ;
} ;
rules . dd _close = function ( ) {
return '</dd>\n' ;
} ;
// Renderer class
function Renderer ( ) {
// Clone rules object to allow local modifications
this . rules = assign ( { } , rules ) ;
// exported helper, for custom rules only
this . getBreak = getBreak ;
}
Renderer . prototype . renderInline = function ( tokens , options , env ) {
var result = '' ,
_rules = this . rules ;
for ( var i = 0 , len = tokens . length ; i < len ; i ++ ) {
result += _rules [ tokens [ i ] . type ] ( tokens , i , options , env , this ) ;
}
return result ;
} ;
Renderer . prototype . render = function ( tokens , options , env ) {
var i , len ,
result = '' ,
_rules = this . rules ;
for ( i = 0 , len = tokens . length ; i < len ; i ++ ) {
if ( tokens [ i ] . type === 'inline' ) {
result += this . renderInline ( tokens [ i ] . children , options , env ) ;
} else {
result += _rules [ tokens [ i ] . type ] ( tokens , i , options , env , this ) ;
}
}
return result ;
} ;
module . exports = Renderer ;
} , { "./common/utils" : 5 } ] , 19 : [ function ( require , module , exports ) {
// Ruler is helper class to build responsibility chains from parse rules.
// It allows:
//
// - easy stack rules chains
// - getting main chain and named chains content (as arrays of functions)
//
'use strict' ;
////////////////////////////////////////////////////////////////////////////////
function Ruler ( ) {
// List of added rules. Each element is:
//
// {
// name: XXX,
// enabled: Boolean,
// fn: Function(),
// alt: [ name2, name3 ]
// }
//
this . _ _rules _ _ = [ ] ;
// Cached rule chains.
//
// First level - chain name, '' for default.
// Second level - diginal anchor for fast filtering by charcodes.
//
this . _ _cache _ _ = null ;
}
////////////////////////////////////////////////////////////////////////////////
// Helper methods, should not be used directly
// Find rule index by name
//
Ruler . prototype . _ _find _ _ = function ( name ) {
for ( var i = 0 ; i < this . _ _rules _ _ . length ; i ++ ) {
if ( this . _ _rules _ _ [ i ] . name === name ) {
return i ;
}
}
return - 1 ;
} ;
// Build rules lookup cache
//
Ruler . prototype . _ _compile _ _ = function ( ) {
var self = this ;
var chains = [ '' ] ;
// collect unique names
self . _ _rules _ _ . forEach ( function ( rule ) {
if ( ! rule . enabled ) { return ; }
rule . alt . forEach ( function ( altName ) {
if ( chains . indexOf ( altName ) < 0 ) {
chains . push ( altName ) ;
}
} ) ;
} ) ;
self . _ _cache _ _ = { } ;
chains . forEach ( function ( chain ) {
self . _ _cache _ _ [ chain ] = [ ] ;
self . _ _rules _ _ . forEach ( function ( rule ) {
if ( ! rule . enabled ) { return ; }
if ( chain && rule . alt . indexOf ( chain ) < 0 ) { return ; }
self . _ _cache _ _ [ chain ] . push ( rule . fn ) ;
} ) ;
} ) ;
} ;
////////////////////////////////////////////////////////////////////////////////
// Public methods
// Replace rule function
//
Ruler . prototype . at = function ( name , fn , options ) {
var index = this . _ _find _ _ ( name ) ;
var opt = options || { } ;
if ( index === - 1 ) { throw new Error ( 'Parser rule not found: ' + name ) ; }
this . _ _rules _ _ [ index ] . fn = fn ;
this . _ _rules _ _ [ index ] . alt = opt . alt || [ ] ;
this . _ _cache _ _ = null ;
} ;
// Add rule to chain before one with given name.
//
Ruler . prototype . before = function ( beforeName , ruleName , fn , options ) {
var index = this . _ _find _ _ ( beforeName ) ;
var opt = options || { } ;
if ( index === - 1 ) { throw new Error ( 'Parser rule not found: ' + beforeName ) ; }
this . _ _rules _ _ . splice ( index , 0 , {
name : ruleName ,
enabled : true ,
fn : fn ,
alt : opt . alt || [ ]
} ) ;
this . _ _cache _ _ = null ;
} ;
// Add rule to chain after one with given name.
//
Ruler . prototype . after = function ( afterName , ruleName , fn , options ) {
var index = this . _ _find _ _ ( afterName ) ;
var opt = options || { } ;
if ( index === - 1 ) { throw new Error ( 'Parser rule not found: ' + afterName ) ; }
this . _ _rules _ _ . splice ( index + 1 , 0 , {
name : ruleName ,
enabled : true ,
fn : fn ,
alt : opt . alt || [ ]
} ) ;
this . _ _cache _ _ = null ;
} ;
// Add rule to the end of chain.
//
Ruler . prototype . push = function ( ruleName , fn , options ) {
var opt = options || { } ;
this . _ _rules _ _ . push ( {
name : ruleName ,
enabled : true ,
fn : fn ,
alt : opt . alt || [ ]
} ) ;
this . _ _cache _ _ = null ;
} ;
// Enable list of rules by names. If `strict` is true, then all non listed
// rules will be disabled.
//
Ruler . prototype . enable = function ( list , strict ) {
if ( ! Array . isArray ( list ) ) {
list = [ list ] ;
}
// In strict mode disable all existing rules first
if ( strict ) {
this . _ _rules _ _ . forEach ( function ( rule ) {
rule . enabled = false ;
} ) ;
}
// Search by name and enable
list . forEach ( function ( name ) {
var idx = this . _ _find _ _ ( name ) ;
if ( idx < 0 ) { throw new Error ( 'Rules manager: invalid rule name ' + name ) ; }
this . _ _rules _ _ [ idx ] . enabled = true ;
} , this ) ;
this . _ _cache _ _ = null ;
} ;
// Disable list of rules by names.
//
Ruler . prototype . disable = function ( list ) {
if ( ! Array . isArray ( list ) ) {
list = [ list ] ;
}
// Search by name and disable
list . forEach ( function ( name ) {
var idx = this . _ _find _ _ ( name ) ;
if ( idx < 0 ) { throw new Error ( 'Rules manager: invalid rule name ' + name ) ; }
this . _ _rules _ _ [ idx ] . enabled = false ;
} , this ) ;
this . _ _cache _ _ = null ;
} ;
// Get rules list as array of functions.
//
Ruler . prototype . getRules = function ( chainName ) {
if ( this . _ _cache _ _ === null ) {
this . _ _compile _ _ ( ) ;
}
return this . _ _cache _ _ [ chainName ] ;
} ;
module . exports = Ruler ;
} , { } ] , 20 : [ function ( require , module , exports ) {
// Block quotes
'use strict' ;
module . exports = function blockquote ( state , startLine , endLine , silent ) {
var nextLine , lastLineEmpty , oldTShift , oldBMarks , oldIndent , oldParentType , lines ,
terminatorRules ,
i , l , terminate ,
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
max = state . eMarks [ startLine ] ;
if ( pos > max ) { return false ; }
// check the block quote marker
if ( state . src . charCodeAt ( pos ++ ) !== 0x3E /* > */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
// we know that it's going to be a valid blockquote,
// so no point trying to find the end of it in silent mode
if ( silent ) { return true ; }
// skip one optional space after '>'
if ( state . src . charCodeAt ( pos ) === 0x20 ) { pos ++ ; }
oldIndent = state . blkIndent ;
state . blkIndent = 0 ;
oldBMarks = [ state . bMarks [ startLine ] ] ;
state . bMarks [ startLine ] = pos ;
// check if we have an empty blockquote
pos = pos < max ? state . skipSpaces ( pos ) : pos ;
lastLineEmpty = pos >= max ;
oldTShift = [ state . tShift [ startLine ] ] ;
state . tShift [ startLine ] = pos - state . bMarks [ startLine ] ;
terminatorRules = state . parser . ruler . getRules ( 'blockquote' ) ;
// Search the end of the block
//
// Block ends with either:
// 1. an empty line outside:
// ```
// > test
//
// ```
// 2. an empty line inside:
// ```
// >
// test
// ```
// 3. another tag
// ```
// > test
// - - -
// ```
for ( nextLine = startLine + 1 ; nextLine < endLine ; nextLine ++ ) {
pos = state . bMarks [ nextLine ] + state . tShift [ nextLine ] ;
max = state . eMarks [ nextLine ] ;
if ( pos >= max ) {
// Case 1: line is not inside the blockquote, and this line is empty.
break ;
}
if ( state . src . charCodeAt ( pos ++ ) === 0x3E /* > */ ) {
// This line is inside the blockquote.
// skip one optional space after '>'
if ( state . src . charCodeAt ( pos ) === 0x20 ) { pos ++ ; }
oldBMarks . push ( state . bMarks [ nextLine ] ) ;
state . bMarks [ nextLine ] = pos ;
pos = pos < max ? state . skipSpaces ( pos ) : pos ;
lastLineEmpty = pos >= max ;
oldTShift . push ( state . tShift [ nextLine ] ) ;
state . tShift [ nextLine ] = pos - state . bMarks [ nextLine ] ;
continue ;
}
// Case 2: line is not inside the blockquote, and the last line was empty.
if ( lastLineEmpty ) { break ; }
// Case 3: another tag found.
terminate = false ;
for ( i = 0 , l = terminatorRules . length ; i < l ; i ++ ) {
if ( terminatorRules [ i ] ( state , nextLine , endLine , true ) ) {
terminate = true ;
break ;
}
}
if ( terminate ) { break ; }
oldBMarks . push ( state . bMarks [ nextLine ] ) ;
oldTShift . push ( state . tShift [ nextLine ] ) ;
// A negative number means that this is a paragraph continuation;
//
// Any negative number will do the job here, but it's better for it
// to be large enough to make any bugs obvious.
state . tShift [ nextLine ] = - 1337 ;
}
oldParentType = state . parentType ;
state . parentType = 'blockquote' ;
state . tokens . push ( {
type : 'blockquote_open' ,
lines : lines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
state . parser . tokenize ( state , startLine , nextLine ) ;
state . tokens . push ( {
type : 'blockquote_close' ,
level : -- state . level
} ) ;
state . parentType = oldParentType ;
lines [ 1 ] = state . line ;
// Restore original tShift; this might not be necessary since the parser
// has already been here, but just to make sure we can do that.
for ( i = 0 ; i < oldTShift . length ; i ++ ) {
state . bMarks [ i + startLine ] = oldBMarks [ i ] ;
state . tShift [ i + startLine ] = oldTShift [ i ] ;
}
state . blkIndent = oldIndent ;
return true ;
} ;
} , { } ] , 21 : [ function ( require , module , exports ) {
// Code block (4 spaces padded)
'use strict' ;
module . exports = function code ( state , startLine , endLine /*, silent*/ ) {
var nextLine , last ;
if ( state . tShift [ startLine ] - state . blkIndent < 4 ) { return false ; }
last = nextLine = startLine + 1 ;
while ( nextLine < endLine ) {
if ( state . isEmpty ( nextLine ) ) {
nextLine ++ ;
continue ;
}
if ( state . tShift [ nextLine ] - state . blkIndent >= 4 ) {
nextLine ++ ;
last = nextLine ;
continue ;
}
break ;
}
state . line = nextLine ;
state . tokens . push ( {
type : 'code' ,
content : state . getLines ( startLine , last , 4 + state . blkIndent , true ) ,
block : true ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
return true ;
} ;
} , { } ] , 22 : [ function ( require , module , exports ) {
// Definition lists
'use strict' ;
// Search `[:~][\n ]`, returns next pos after marker on success
// or -1 on fail.
function skipMarker ( state , line ) {
var pos , marker ,
start = state . bMarks [ line ] + state . tShift [ line ] ,
max = state . eMarks [ line ] ;
if ( start >= max ) { return - 1 ; }
// Check bullet
marker = state . src . charCodeAt ( start ++ ) ;
if ( marker !== 0x7E /* ~ */ && marker !== 0x3A /* : */ ) { return - 1 ; }
pos = state . skipSpaces ( start ) ;
// require space after ":"
if ( start === pos ) { return - 1 ; }
// no empty definitions, e.g. " : "
if ( pos >= max ) { return - 1 ; }
return pos ;
}
function markTightParagraphs ( state , idx ) {
var i , l ,
level = state . level + 2 ;
for ( i = idx + 2 , l = state . tokens . length - 2 ; i < l ; i ++ ) {
if ( state . tokens [ i ] . level === level && state . tokens [ i ] . type === 'paragraph_open' ) {
state . tokens [ i + 2 ] . tight = true ;
state . tokens [ i ] . tight = true ;
i += 2 ;
}
}
}
module . exports = function deflist ( state , startLine , endLine , silent ) {
var contentStart ,
ddLine ,
dtLine ,
itemLines ,
listLines ,
listTokIdx ,
nextLine ,
oldIndent ,
oldDDIndent ,
oldParentType ,
oldTShift ,
oldTight ,
prevEmptyEnd ,
tight ;
if ( silent ) {
// quirk: validation mode validates a dd block only, not a whole deflist
if ( state . ddIndent < 0 ) { return false ; }
return skipMarker ( state , startLine ) >= 0 ;
}
nextLine = startLine + 1 ;
if ( state . isEmpty ( nextLine ) ) {
if ( ++ nextLine > endLine ) { return false ; }
}
if ( state . tShift [ nextLine ] < state . blkIndent ) { return false ; }
contentStart = skipMarker ( state , nextLine ) ;
if ( contentStart < 0 ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
// Start list
listTokIdx = state . tokens . length ;
state . tokens . push ( {
type : 'dl_open' ,
lines : listLines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
//
// Iterate list items
//
dtLine = startLine ;
ddLine = nextLine ;
// One definition list can contain multiple DTs,
// and one DT can be followed by multiple DDs.
//
// Thus, there is two loops here, and label is
// needed to break out of the second one
//
/*eslint no-labels:0,block-scoped-var:0*/
OUTER :
for ( ; ; ) {
tight = true ;
prevEmptyEnd = false ;
state . tokens . push ( {
type : 'dt_open' ,
lines : [ dtLine , dtLine ] ,
level : state . level ++
} ) ;
state . tokens . push ( {
type : 'inline' ,
content : state . getLines ( dtLine , dtLine + 1 , state . blkIndent , false ) . trim ( ) ,
level : state . level + 1 ,
lines : [ dtLine , dtLine ] ,
children : [ ]
} ) ;
state . tokens . push ( {
type : 'dt_close' ,
level : -- state . level
} ) ;
for ( ; ; ) {
state . tokens . push ( {
type : 'dd_open' ,
lines : itemLines = [ nextLine , 0 ] ,
level : state . level ++
} ) ;
oldTight = state . tight ;
oldDDIndent = state . ddIndent ;
oldIndent = state . blkIndent ;
oldTShift = state . tShift [ ddLine ] ;
oldParentType = state . parentType ;
state . blkIndent = state . ddIndent = state . tShift [ ddLine ] + 2 ;
state . tShift [ ddLine ] = contentStart - state . bMarks [ ddLine ] ;
state . tight = true ;
state . parentType = 'deflist' ;
state . parser . tokenize ( state , ddLine , endLine , true ) ;
// If any of list item is tight, mark list as tight
if ( ! state . tight || prevEmptyEnd ) {
tight = false ;
}
// Item become loose if finish with empty line,
// but we should filter last element, because it means list finish
prevEmptyEnd = ( state . line - ddLine ) > 1 && state . isEmpty ( state . line - 1 ) ;
state . tShift [ ddLine ] = oldTShift ;
state . tight = oldTight ;
state . parentType = oldParentType ;
state . blkIndent = oldIndent ;
state . ddIndent = oldDDIndent ;
state . tokens . push ( {
type : 'dd_close' ,
level : -- state . level
} ) ;
itemLines [ 1 ] = nextLine = state . line ;
if ( nextLine >= endLine ) { break OUTER ; }
if ( state . tShift [ nextLine ] < state . blkIndent ) { break OUTER ; }
contentStart = skipMarker ( state , nextLine ) ;
if ( contentStart < 0 ) { break ; }
ddLine = nextLine ;
// go to the next loop iteration:
// insert DD tag and repeat checking
}
if ( nextLine >= endLine ) { break ; }
dtLine = nextLine ;
if ( state . isEmpty ( dtLine ) ) { break ; }
if ( state . tShift [ dtLine ] < state . blkIndent ) { break ; }
ddLine = dtLine + 1 ;
if ( ddLine >= endLine ) { break ; }
if ( state . isEmpty ( ddLine ) ) { ddLine ++ ; }
if ( ddLine >= endLine ) { break ; }
if ( state . tShift [ ddLine ] < state . blkIndent ) { break ; }
contentStart = skipMarker ( state , ddLine ) ;
if ( contentStart < 0 ) { break ; }
// go to the next loop iteration:
// insert DT and DD tags and repeat checking
}
// Finilize list
state . tokens . push ( {
type : 'dl_close' ,
level : -- state . level
} ) ;
listLines [ 1 ] = nextLine ;
state . line = nextLine ;
// mark paragraphs tight if needed
if ( tight ) {
markTightParagraphs ( state , listTokIdx ) ;
}
return true ;
} ;
} , { } ] , 23 : [ function ( require , module , exports ) {
// fences (``` lang, ~~~ lang)
'use strict' ;
module . exports = function fences ( state , startLine , endLine , silent ) {
var marker , len , params , nextLine , mem ,
haveEndMarker = false ,
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
max = state . eMarks [ startLine ] ;
if ( pos + 3 > max ) { return false ; }
marker = state . src . charCodeAt ( pos ) ;
if ( marker !== 0x7E /* ~ */ && marker !== 0x60 /* ` */ ) {
return false ;
}
// scan marker length
mem = pos ;
pos = state . skipChars ( pos , marker ) ;
len = pos - mem ;
if ( len < 3 ) { return false ; }
params = state . src . slice ( pos , max ) . trim ( ) ;
if ( params . indexOf ( '`' ) >= 0 ) { return false ; }
// Since start is found, we can report success here in validation mode
if ( silent ) { return true ; }
// search end of block
nextLine = startLine ;
for ( ; ; ) {
nextLine ++ ;
if ( nextLine >= endLine ) {
// unclosed block should be autoclosed by end of document.
// also block seems to be autoclosed by end of parent
break ;
}
pos = mem = state . bMarks [ nextLine ] + state . tShift [ nextLine ] ;
max = state . eMarks [ nextLine ] ;
if ( pos < max && state . tShift [ nextLine ] < state . blkIndent ) {
// non-empty line with negative indent should stop the list:
// - ```
// test
break ;
}
if ( state . src . charCodeAt ( pos ) !== marker ) { continue ; }
if ( state . tShift [ nextLine ] - state . blkIndent >= 4 ) {
// closing fence should be indented less than 4 spaces
continue ;
}
pos = state . skipChars ( pos , marker ) ;
// closing code fence must be at least as long as the opening one
if ( pos - mem < len ) { continue ; }
// make sure tail has spaces only
pos = state . skipSpaces ( pos ) ;
if ( pos < max ) { continue ; }
haveEndMarker = true ;
// found!
break ;
}
// If a fence has heading spaces, they should be removed from its inner block
len = state . tShift [ startLine ] ;
state . line = nextLine + ( haveEndMarker ? 1 : 0 ) ;
state . tokens . push ( {
type : 'fence' ,
params : params ,
content : state . getLines ( startLine + 1 , nextLine , len , true ) ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
return true ;
} ;
} , { } ] , 24 : [ function ( require , module , exports ) {
// Process footnote reference list
'use strict' ;
module . exports = function footnote ( state , startLine , endLine , silent ) {
var oldBMark , oldTShift , oldParentType , pos , label ,
start = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
max = state . eMarks [ startLine ] ;
// line should be at least 5 chars - "[^x]:"
if ( start + 4 > max ) { return false ; }
if ( state . src . charCodeAt ( start ) !== 0x5B /* [ */ ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x5E /* ^ */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
for ( pos = start + 2 ; pos < max ; pos ++ ) {
if ( state . src . charCodeAt ( pos ) === 0x20 ) { return false ; }
if ( state . src . charCodeAt ( pos ) === 0x5D /* ] */ ) {
break ;
}
}
if ( pos === start + 2 ) { return false ; } // no empty footnote labels
if ( pos + 1 >= max || state . src . charCodeAt ( ++ pos ) !== 0x3A /* : */ ) { return false ; }
if ( silent ) { return true ; }
pos ++ ;
if ( ! state . env . footnotes ) { state . env . footnotes = { } ; }
if ( ! state . env . footnotes . refs ) { state . env . footnotes . refs = { } ; }
label = state . src . slice ( start + 2 , pos - 2 ) ;
state . env . footnotes . refs [ ':' + label ] = - 1 ;
state . tokens . push ( {
type : 'footnote_reference_open' ,
label : label ,
level : state . level ++
} ) ;
oldBMark = state . bMarks [ startLine ] ;
oldTShift = state . tShift [ startLine ] ;
oldParentType = state . parentType ;
state . tShift [ startLine ] = state . skipSpaces ( pos ) - pos ;
state . bMarks [ startLine ] = pos ;
state . blkIndent += 4 ;
state . parentType = 'footnote' ;
if ( state . tShift [ startLine ] < state . blkIndent ) {
state . tShift [ startLine ] += state . blkIndent ;
state . bMarks [ startLine ] -= state . blkIndent ;
}
state . parser . tokenize ( state , startLine , endLine , true ) ;
state . parentType = oldParentType ;
state . blkIndent -= 4 ;
state . tShift [ startLine ] = oldTShift ;
state . bMarks [ startLine ] = oldBMark ;
state . tokens . push ( {
type : 'footnote_reference_close' ,
level : -- state . level
} ) ;
return true ;
} ;
} , { } ] , 25 : [ function ( require , module , exports ) {
// heading (#, ##, ...)
'use strict' ;
module . exports = function heading ( state , startLine , endLine , silent ) {
var ch , level , tmp ,
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
max = state . eMarks [ startLine ] ;
if ( pos >= max ) { return false ; }
ch = state . src . charCodeAt ( pos ) ;
if ( ch !== 0x23 /* # */ || pos >= max ) { return false ; }
// count heading level
level = 1 ;
ch = state . src . charCodeAt ( ++ pos ) ;
while ( ch === 0x23 /* # */ && pos < max && level <= 6 ) {
level ++ ;
ch = state . src . charCodeAt ( ++ pos ) ;
}
if ( level > 6 || ( pos < max && ch !== 0x20 /* space */ ) ) { return false ; }
if ( silent ) { return true ; }
// Let's cut tails like ' ### ' from the end of string
max = state . skipCharsBack ( max , 0x20 , pos ) ; // space
tmp = state . skipCharsBack ( max , 0x23 , pos ) ; // #
if ( tmp > pos && state . src . charCodeAt ( tmp - 1 ) === 0x20 /* space */ ) {
max = tmp ;
}
state . line = startLine + 1 ;
state . tokens . push ( { type : 'heading_open' ,
hLevel : level ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
// only if header is not empty
if ( pos < max ) {
state . tokens . push ( {
type : 'inline' ,
content : state . src . slice ( pos , max ) . trim ( ) ,
level : state . level + 1 ,
lines : [ startLine , state . line ] ,
children : [ ]
} ) ;
}
state . tokens . push ( { type : 'heading_close' , hLevel : level , level : state . level } ) ;
return true ;
} ;
} , { } ] , 26 : [ function ( require , module , exports ) {
// Horizontal rule
'use strict' ;
module . exports = function hr ( state , startLine , endLine , silent ) {
var marker , cnt , ch ,
pos = state . bMarks [ startLine ] ,
max = state . eMarks [ startLine ] ;
pos += state . tShift [ startLine ] ;
if ( pos > max ) { return false ; }
marker = state . src . charCodeAt ( pos ++ ) ;
// Check hr marker
if ( marker !== 0x2A /* * */ &&
marker !== 0x2D /* - */ &&
marker !== 0x5F /* _ */ ) {
return false ;
}
// markers can be mixed with spaces, but there should be at least 3 one
cnt = 1 ;
while ( pos < max ) {
ch = state . src . charCodeAt ( pos ++ ) ;
if ( ch !== marker && ch !== 0x20 /* space */ ) { return false ; }
if ( ch === marker ) { cnt ++ ; }
}
if ( cnt < 3 ) { return false ; }
if ( silent ) { return true ; }
state . line = startLine + 1 ;
state . tokens . push ( {
type : 'hr' ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
return true ;
} ;
} , { } ] , 27 : [ function ( require , module , exports ) {
// HTML block
'use strict' ;
var block _names = require ( '../common/html_blocks' ) ;
var HTML _TAG _OPEN _RE = /^<([a-zA-Z]{1,15})[\s\/>]/ ;
var HTML _TAG _CLOSE _RE = /^<\/([a-zA-Z]{1,15})[\s>]/ ;
function isLetter ( ch ) {
/*eslint no-bitwise:0*/
var lc = ch | 0x20 ; // to lower case
return ( lc >= 0x61 /* a */ ) && ( lc <= 0x7a /* z */ ) ;
}
module . exports = function htmlblock ( state , startLine , endLine , silent ) {
var ch , match , nextLine ,
pos = state . bMarks [ startLine ] ,
max = state . eMarks [ startLine ] ,
shift = state . tShift [ startLine ] ;
pos += shift ;
if ( ! state . options . html ) { return false ; }
if ( shift > 3 || pos + 2 >= max ) { return false ; }
if ( state . src . charCodeAt ( pos ) !== 0x3C /* < */ ) { return false ; }
ch = state . src . charCodeAt ( pos + 1 ) ;
if ( ch === 0x21 /* ! */ || ch === 0x3F /* ? */ ) {
// Directive start / comment start / processing instruction start
if ( silent ) { return true ; }
} else if ( ch === 0x2F /* / */ || isLetter ( ch ) ) {
// Probably start or end of tag
if ( ch === 0x2F /* \ */ ) {
// closing tag
match = state . src . slice ( pos , max ) . match ( HTML _TAG _CLOSE _RE ) ;
if ( ! match ) { return false ; }
} else {
// opening tag
match = state . src . slice ( pos , max ) . match ( HTML _TAG _OPEN _RE ) ;
if ( ! match ) { return false ; }
}
// Make sure tag name is valid
if ( block _names [ match [ 1 ] . toLowerCase ( ) ] !== true ) { return false ; }
if ( silent ) { return true ; }
} else {
return false ;
}
// If we are here - we detected HTML block.
// Let's roll down till empty line (block end).
nextLine = startLine + 1 ;
while ( nextLine < state . lineMax && ! state . isEmpty ( nextLine ) ) {
nextLine ++ ;
}
state . line = nextLine ;
state . tokens . push ( {
type : 'htmlblock' ,
level : state . level ,
lines : [ startLine , state . line ] ,
content : state . getLines ( startLine , nextLine , 0 , true )
} ) ;
return true ;
} ;
} , { "../common/html_blocks" : 2 } ] , 28 : [ function ( require , module , exports ) {
// lheading (---, ===)
'use strict' ;
module . exports = function lheading ( state , startLine , endLine /*, silent*/ ) {
var marker , pos , max ,
next = startLine + 1 ;
if ( next >= endLine ) { return false ; }
if ( state . tShift [ next ] < state . blkIndent ) { return false ; }
// Scan next line
if ( state . tShift [ next ] - state . blkIndent > 3 ) { return false ; }
pos = state . bMarks [ next ] + state . tShift [ next ] ;
max = state . eMarks [ next ] ;
if ( pos >= max ) { return false ; }
marker = state . src . charCodeAt ( pos ) ;
if ( marker !== 0x2D /* - */ && marker !== 0x3D /* = */ ) { return false ; }
pos = state . skipChars ( pos , marker ) ;
pos = state . skipSpaces ( pos ) ;
if ( pos < max ) { return false ; }
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ;
state . line = next + 1 ;
state . tokens . push ( {
type : 'heading_open' ,
hLevel : marker === 0x3D /* = */ ? 1 : 2 ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
state . tokens . push ( {
type : 'inline' ,
content : state . src . slice ( pos , state . eMarks [ startLine ] ) . trim ( ) ,
level : state . level + 1 ,
lines : [ startLine , state . line - 1 ] ,
children : [ ]
} ) ;
state . tokens . push ( {
type : 'heading_close' ,
hLevel : marker === 0x3D /* = */ ? 1 : 2 ,
level : state . level
} ) ;
return true ;
} ;
} , { } ] , 29 : [ function ( require , module , exports ) {
// Lists
'use strict' ;
// Search `[-+*][\n ]`, returns next pos arter marker on success
// or -1 on fail.
function skipBulletListMarker ( state , startLine ) {
var marker , pos , max ;
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ;
max = state . eMarks [ startLine ] ;
if ( pos >= max ) { return - 1 ; }
marker = state . src . charCodeAt ( pos ++ ) ;
// Check bullet
if ( marker !== 0x2A /* * */ &&
marker !== 0x2D /* - */ &&
marker !== 0x2B /* + */ ) {
return - 1 ;
}
if ( pos < max && state . src . charCodeAt ( pos ) !== 0x20 ) {
// " 1.test " - is not a list item
return - 1 ;
}
return pos ;
}
// Search `\d+[.)][\n ]`, returns next pos arter marker on success
// or -1 on fail.
function skipOrderedListMarker ( state , startLine ) {
var ch ,
pos = state . bMarks [ startLine ] + state . tShift [ startLine ] ,
max = state . eMarks [ startLine ] ;
if ( pos + 1 >= max ) { return - 1 ; }
ch = state . src . charCodeAt ( pos ++ ) ;
if ( ch < 0x30 /* 0 */ || ch > 0x39 /* 9 */ ) { return - 1 ; }
for ( ; ; ) {
// EOL -> fail
if ( pos >= max ) { return - 1 ; }
ch = state . src . charCodeAt ( pos ++ ) ;
if ( ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */ ) {
continue ;
}
// found valid marker
if ( ch === 0x29 /* ) */ || ch === 0x2e /* . */ ) {
break ;
}
return - 1 ;
}
if ( pos < max && state . src . charCodeAt ( pos ) !== 0x20 /* space */ ) {
// " 1.test " - is not a list item
return - 1 ;
}
return pos ;
}
function markTightParagraphs ( state , idx ) {
var i , l ,
level = state . level + 2 ;
for ( i = idx + 2 , l = state . tokens . length - 2 ; i < l ; i ++ ) {
if ( state . tokens [ i ] . level === level && state . tokens [ i ] . type === 'paragraph_open' ) {
state . tokens [ i + 2 ] . tight = true ;
state . tokens [ i ] . tight = true ;
i += 2 ;
}
}
}
module . exports = function list ( state , startLine , endLine , silent ) {
var nextLine ,
indent ,
oldTShift ,
oldIndent ,
oldTight ,
oldParentType ,
start ,
posAfterMarker ,
max ,
indentAfterMarker ,
markerValue ,
markerCharCode ,
isOrdered ,
contentStart ,
listTokIdx ,
prevEmptyEnd ,
listLines ,
itemLines ,
tight = true ,
terminatorRules ,
i , l , terminate ;
// Detect list type and position after marker
if ( ( posAfterMarker = skipOrderedListMarker ( state , startLine ) ) >= 0 ) {
isOrdered = true ;
} else if ( ( posAfterMarker = skipBulletListMarker ( state , startLine ) ) >= 0 ) {
isOrdered = false ;
} else {
return false ;
}
if ( state . level >= state . options . maxNesting ) { return false ; }
// We should terminate list on style change. Remember first one to compare.
markerCharCode = state . src . charCodeAt ( posAfterMarker - 1 ) ;
// For validation mode we can terminate immediately
if ( silent ) { return true ; }
// Start list
listTokIdx = state . tokens . length ;
if ( isOrdered ) {
start = state . bMarks [ startLine ] + state . tShift [ startLine ] ;
markerValue = Number ( state . src . substr ( start , posAfterMarker - start - 1 ) ) ;
state . tokens . push ( {
type : 'ordered_list_open' ,
order : markerValue ,
lines : listLines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
} else {
state . tokens . push ( {
type : 'bullet_list_open' ,
lines : listLines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
}
//
// Iterate list items
//
nextLine = startLine ;
prevEmptyEnd = false ;
terminatorRules = state . parser . ruler . getRules ( 'list' ) ;
while ( nextLine < endLine ) {
contentStart = state . skipSpaces ( posAfterMarker ) ;
max = state . eMarks [ nextLine ] ;
if ( contentStart >= max ) {
// trimming space in "- \n 3" case, indent is 1 here
indentAfterMarker = 1 ;
} else {
indentAfterMarker = contentStart - posAfterMarker ;
}
// If we have more than 4 spaces, the indent is 1
// (the rest is just indented code block)
if ( indentAfterMarker > 4 ) { indentAfterMarker = 1 ; }
// If indent is less than 1, assume that it's one, example:
// "-\n test"
if ( indentAfterMarker < 1 ) { indentAfterMarker = 1 ; }
// " - test"
// ^^^^^ - calculating total length of this thing
indent = ( posAfterMarker - state . bMarks [ nextLine ] ) + indentAfterMarker ;
// Run subparser & write tokens
state . tokens . push ( {
type : 'list_item_open' ,
lines : itemLines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
oldIndent = state . blkIndent ;
oldTight = state . tight ;
oldTShift = state . tShift [ startLine ] ;
oldParentType = state . parentType ;
state . tShift [ startLine ] = contentStart - state . bMarks [ startLine ] ;
state . blkIndent = indent ;
state . tight = true ;
state . parentType = 'list' ;
state . parser . tokenize ( state , startLine , endLine , true ) ;
// If any of list item is tight, mark list as tight
if ( ! state . tight || prevEmptyEnd ) {
tight = false ;
}
// Item become loose if finish with empty line,
// but we should filter last element, because it means list finish
prevEmptyEnd = ( state . line - startLine ) > 1 && state . isEmpty ( state . line - 1 ) ;
state . blkIndent = oldIndent ;
state . tShift [ startLine ] = oldTShift ;
state . tight = oldTight ;
state . parentType = oldParentType ;
state . tokens . push ( {
type : 'list_item_close' ,
level : -- state . level
} ) ;
nextLine = startLine = state . line ;
itemLines [ 1 ] = nextLine ;
contentStart = state . bMarks [ startLine ] ;
if ( nextLine >= endLine ) { break ; }
if ( state . isEmpty ( nextLine ) ) {
break ;
}
//
// Try to check if list is terminated or continued.
//
if ( state . tShift [ nextLine ] < state . blkIndent ) { break ; }
// fail if terminating block found
terminate = false ;
for ( i = 0 , l = terminatorRules . length ; i < l ; i ++ ) {
if ( terminatorRules [ i ] ( state , nextLine , endLine , true ) ) {
terminate = true ;
break ;
}
}
if ( terminate ) { break ; }
// fail if list has another type
if ( isOrdered ) {
posAfterMarker = skipOrderedListMarker ( state , nextLine ) ;
if ( posAfterMarker < 0 ) { break ; }
} else {
posAfterMarker = skipBulletListMarker ( state , nextLine ) ;
if ( posAfterMarker < 0 ) { break ; }
}
if ( markerCharCode !== state . src . charCodeAt ( posAfterMarker - 1 ) ) { break ; }
}
// Finilize list
state . tokens . push ( {
type : isOrdered ? 'ordered_list_close' : 'bullet_list_close' ,
level : -- state . level
} ) ;
listLines [ 1 ] = nextLine ;
state . line = nextLine ;
// mark paragraphs tight if needed
if ( tight ) {
markTightParagraphs ( state , listTokIdx ) ;
}
return true ;
} ;
} , { } ] , 30 : [ function ( require , module , exports ) {
// Paragraph
'use strict' ;
module . exports = function paragraph ( state , startLine /*, endLine*/ ) {
var endLine , content , terminate , i , l ,
nextLine = startLine + 1 ,
terminatorRules ;
endLine = state . lineMax ;
// jump line-by-line until empty one or EOF
if ( nextLine < endLine && ! state . isEmpty ( nextLine ) ) {
terminatorRules = state . parser . ruler . getRules ( 'paragraph' ) ;
for ( ; nextLine < endLine && ! state . isEmpty ( nextLine ) ; nextLine ++ ) {
// this would be a code block normally, but after paragraph
// it's considered a lazy continuation regardless of what's there
if ( state . tShift [ nextLine ] - state . blkIndent > 3 ) { continue ; }
// Some tags can terminate paragraph without empty line.
terminate = false ;
for ( i = 0 , l = terminatorRules . length ; i < l ; i ++ ) {
if ( terminatorRules [ i ] ( state , nextLine , endLine , true ) ) {
terminate = true ;
break ;
}
}
if ( terminate ) { break ; }
}
}
content = state . getLines ( startLine , nextLine , state . blkIndent , false ) . trim ( ) ;
state . line = nextLine ;
if ( content . length ) {
state . tokens . push ( {
type : 'paragraph_open' ,
tight : false ,
lines : [ startLine , state . line ] ,
level : state . level
} ) ;
state . tokens . push ( {
type : 'inline' ,
content : content ,
level : state . level + 1 ,
lines : [ startLine , state . line ] ,
children : [ ]
} ) ;
state . tokens . push ( {
type : 'paragraph_close' ,
tight : false ,
level : state . level
} ) ;
}
return true ;
} ;
} , { } ] , 31 : [ function ( require , module , exports ) {
// Parser state class
'use strict' ;
function StateBlock ( src , parser , options , env , tokens ) {
var ch , s , start , pos , len , indent , indent _found ;
this . src = src ;
// Shortcuts to simplify nested calls
this . parser = parser ;
this . options = options ;
this . env = env ;
//
// Internal state vartiables
//
this . tokens = tokens ;
this . bMarks = [ ] ; // line begin offsets for fast jumps
this . eMarks = [ ] ; // line end offsets for fast jumps
this . tShift = [ ] ; // indent for each line
// block parser variables
this . blkIndent = 0 ; // required block content indent
// (for example, if we are in list)
this . line = 0 ; // line index in src
this . lineMax = 0 ; // lines count
this . tight = false ; // loose/tight mode for lists
this . parentType = 'root' ; // if `list`, block parser stops on two newlines
this . ddIndent = - 1 ; // indent of the current dd block (-1 if there isn't any)
this . level = 0 ;
// renderer
this . result = '' ;
// Create caches
// Generate markers.
s = this . src ;
indent = 0 ;
indent _found = false ;
for ( start = pos = indent = 0 , len = s . length ; pos < len ; pos ++ ) {
ch = s . charCodeAt ( pos ) ;
if ( ! indent _found ) {
if ( ch === 0x20 /* space */ ) {
indent ++ ;
continue ;
} else {
indent _found = true ;
}
}
if ( ch === 0x0A || pos === len - 1 ) {
if ( ch !== 0x0A ) { pos ++ ; }
this . bMarks . push ( start ) ;
this . eMarks . push ( pos ) ;
this . tShift . push ( indent ) ;
indent _found = false ;
indent = 0 ;
start = pos + 1 ;
}
}
// Push fake entry to simplify cache bounds checks
this . bMarks . push ( s . length ) ;
this . eMarks . push ( s . length ) ;
this . tShift . push ( 0 ) ;
this . lineMax = this . bMarks . length - 1 ; // don't count last fake line
}
StateBlock . prototype . isEmpty = function isEmpty ( line ) {
return this . bMarks [ line ] + this . tShift [ line ] >= this . eMarks [ line ] ;
} ;
StateBlock . prototype . skipEmptyLines = function skipEmptyLines ( from ) {
for ( var max = this . lineMax ; from < max ; from ++ ) {
if ( this . bMarks [ from ] + this . tShift [ from ] < this . eMarks [ from ] ) {
break ;
}
}
return from ;
} ;
// Skip spaces from given position.
StateBlock . prototype . skipSpaces = function skipSpaces ( pos ) {
for ( var max = this . src . length ; pos < max ; pos ++ ) {
if ( this . src . charCodeAt ( pos ) !== 0x20 /* space */ ) { break ; }
}
return pos ;
} ;
// Skip char codes from given position
StateBlock . prototype . skipChars = function skipChars ( pos , code ) {
for ( var max = this . src . length ; pos < max ; pos ++ ) {
if ( this . src . charCodeAt ( pos ) !== code ) { break ; }
}
return pos ;
} ;
// Skip char codes reverse from given position - 1
StateBlock . prototype . skipCharsBack = function skipCharsBack ( pos , code , min ) {
if ( pos <= min ) { return pos ; }
while ( pos > min ) {
if ( code !== this . src . charCodeAt ( -- pos ) ) { return pos + 1 ; }
}
return pos ;
} ;
2016-01-22 20:47:26 -05:00
function isSpace ( code ) {
switch ( code ) {
case 0x09 :
case 0x20 :
return true ;
}
return false ;
}
2015-05-04 03:53:29 -04:00
// cut lines range from source.
StateBlock . prototype . getLines = function getLines ( begin , end , indent , keepLastLF ) {
2016-01-22 20:47:26 -05:00
var i , lineIndent , ch , first , last , queue , lineStart ,
2015-05-04 03:53:29 -04:00
line = begin ;
if ( begin >= end ) {
return '' ;
}
queue = new Array ( end - begin ) ;
for ( i = 0 ; line < end ; line ++ , i ++ ) {
2016-01-22 20:47:26 -05:00
lineIndent = 0 ;
lineStart = first = this . bMarks [ line ] ;
2015-05-04 03:53:29 -04:00
if ( line + 1 < end || keepLastLF ) {
// No need for bounds check because we have fake entry on tail.
last = this . eMarks [ line ] + 1 ;
} else {
last = this . eMarks [ line ] ;
}
2016-01-22 20:47:26 -05:00
while ( first < last && lineIndent < indent ) {
ch = this . src . charCodeAt ( first ) ;
if ( isSpace ( ch ) ) {
if ( ch === 0x09 ) {
lineIndent += 4 - lineIndent % 4 ;
} else {
lineIndent ++ ;
}
} else if ( first - lineStart < this . tShift [ line ] ) {
// patched tShift masked characters to look like spaces (blockquotes, list markers)
lineIndent ++ ;
} else {
break ;
}
first ++ ;
}
2015-05-04 03:53:29 -04:00
queue [ i ] = this . src . slice ( first , last ) ;
}
return queue . join ( '' ) ;
} ;
module . exports = StateBlock ;
} , { } ] , 32 : [ function ( require , module , exports ) {
// GFM table, non-standard
'use strict' ;
function getLine ( state , line ) {
var pos = state . bMarks [ line ] + state . blkIndent ,
max = state . eMarks [ line ] ;
return state . src . substr ( pos , max - pos ) ;
}
module . exports = function table ( state , startLine , endLine , silent ) {
var ch , lineText , pos , i , nextLine , rows ,
aligns , t , tableLines , tbodyLines ;
// should have at least three lines
if ( startLine + 2 > endLine ) { return false ; }
nextLine = startLine + 1 ;
if ( state . tShift [ nextLine ] < state . blkIndent ) { return false ; }
// first character of the second line should be '|' or '-'
pos = state . bMarks [ nextLine ] + state . tShift [ nextLine ] ;
if ( pos >= state . eMarks [ nextLine ] ) { return false ; }
ch = state . src . charCodeAt ( pos ) ;
if ( ch !== 0x7C /* | */ && ch !== 0x2D /* - */ && ch !== 0x3A /* : */ ) { return false ; }
lineText = getLine ( state , startLine + 1 ) ;
if ( ! /^[-:| ]+$/ . test ( lineText ) ) { return false ; }
rows = lineText . split ( '|' ) ;
if ( rows <= 2 ) { return false ; }
aligns = [ ] ;
for ( i = 0 ; i < rows . length ; i ++ ) {
t = rows [ i ] . trim ( ) ;
if ( ! t ) {
// allow empty columns before and after table, but not in between columns;
// e.g. allow ` |---| `, disallow ` ---||--- `
if ( i === 0 || i === rows . length - 1 ) {
continue ;
} else {
return false ;
}
}
if ( ! /^:?-+:?$/ . test ( t ) ) { return false ; }
if ( t . charCodeAt ( t . length - 1 ) === 0x3A /* : */ ) {
aligns . push ( t . charCodeAt ( 0 ) === 0x3A /* : */ ? 'center' : 'right' ) ;
} else if ( t . charCodeAt ( 0 ) === 0x3A /* : */ ) {
aligns . push ( 'left' ) ;
} else {
aligns . push ( '' ) ;
}
}
lineText = getLine ( state , startLine ) . trim ( ) ;
if ( lineText . indexOf ( '|' ) === - 1 ) { return false ; }
rows = lineText . replace ( /^\||\|$/g , '' ) . split ( '|' ) ;
if ( aligns . length !== rows . length ) { return false ; }
if ( silent ) { return true ; }
state . tokens . push ( {
type : 'table_open' ,
lines : tableLines = [ startLine , 0 ] ,
level : state . level ++
} ) ;
state . tokens . push ( {
type : 'thead_open' ,
lines : [ startLine , startLine + 1 ] ,
level : state . level ++
} ) ;
state . tokens . push ( {
type : 'tr_open' ,
lines : [ startLine , startLine + 1 ] ,
level : state . level ++
} ) ;
for ( i = 0 ; i < rows . length ; i ++ ) {
state . tokens . push ( {
type : 'th_open' ,
align : aligns [ i ] ,
lines : [ startLine , startLine + 1 ] ,
level : state . level ++
} ) ;
state . tokens . push ( {
type : 'inline' ,
content : rows [ i ] . trim ( ) ,
lines : [ startLine , startLine + 1 ] ,
level : state . level ,
children : [ ]
} ) ;
state . tokens . push ( { type : 'th_close' , level : -- state . level } ) ;
}
state . tokens . push ( { type : 'tr_close' , level : -- state . level } ) ;
state . tokens . push ( { type : 'thead_close' , level : -- state . level } ) ;
state . tokens . push ( {
type : 'tbody_open' ,
lines : tbodyLines = [ startLine + 2 , 0 ] ,
level : state . level ++
} ) ;
for ( nextLine = startLine + 2 ; nextLine < endLine ; nextLine ++ ) {
if ( state . tShift [ nextLine ] < state . blkIndent ) { break ; }
lineText = getLine ( state , nextLine ) . trim ( ) ;
if ( lineText . indexOf ( '|' ) === - 1 ) { break ; }
rows = lineText . replace ( /^\||\|$/g , '' ) . split ( '|' ) ;
state . tokens . push ( { type : 'tr_open' , level : state . level ++ } ) ;
for ( i = 0 ; i < rows . length ; i ++ ) {
state . tokens . push ( { type : 'td_open' , align : aligns [ i ] , level : state . level ++ } ) ;
state . tokens . push ( {
type : 'inline' ,
content : rows [ i ] . replace ( /^\|? *| *\|?$/g , '' ) ,
level : state . level ,
children : [ ]
} ) ;
state . tokens . push ( { type : 'td_close' , level : -- state . level } ) ;
}
state . tokens . push ( { type : 'tr_close' , level : -- state . level } ) ;
}
state . tokens . push ( { type : 'tbody_close' , level : -- state . level } ) ;
state . tokens . push ( { type : 'table_close' , level : -- state . level } ) ;
tableLines [ 1 ] = tbodyLines [ 1 ] = nextLine ;
state . line = nextLine ;
return true ;
} ;
} , { } ] , 33 : [ function ( require , module , exports ) {
// Parse abbreviation definitions, i.e. `*[abbr]: description`
//
'use strict' ;
var StateInline = require ( '../rules_inline/state_inline' ) ;
var parseLinkLabel = require ( '../helpers/parse_link_label' ) ;
function parseAbbr ( str , parserInline , options , env ) {
var state , labelEnd , pos , max , label , title ;
if ( str . charCodeAt ( 0 ) !== 0x2A /* * */ ) { return - 1 ; }
if ( str . charCodeAt ( 1 ) !== 0x5B /* [ */ ) { return - 1 ; }
if ( str . indexOf ( ']:' ) === - 1 ) { return - 1 ; }
state = new StateInline ( str , parserInline , options , env , [ ] ) ;
labelEnd = parseLinkLabel ( state , 1 ) ;
if ( labelEnd < 0 || str . charCodeAt ( labelEnd + 1 ) !== 0x3A /* : */ ) { return - 1 ; }
max = state . posMax ;
// abbr title is always one line, so looking for ending "\n" here
for ( pos = labelEnd + 2 ; pos < max ; pos ++ ) {
if ( state . src . charCodeAt ( pos ) === 0x0A ) { break ; }
}
label = str . slice ( 2 , labelEnd ) ;
title = str . slice ( labelEnd + 2 , pos ) . trim ( ) ;
if ( title . length === 0 ) { return - 1 ; }
if ( ! env . abbreviations ) { env . abbreviations = { } ; }
// prepend ':' to avoid conflict with Object.prototype members
if ( typeof env . abbreviations [ ':' + label ] === 'undefined' ) {
env . abbreviations [ ':' + label ] = title ;
}
return pos ;
}
module . exports = function abbr ( state ) {
var tokens = state . tokens , i , l , content , pos ;
if ( state . inlineMode ) {
return ;
}
// Parse inlines
for ( i = 1 , l = tokens . length - 1 ; i < l ; i ++ ) {
if ( tokens [ i - 1 ] . type === 'paragraph_open' &&
tokens [ i ] . type === 'inline' &&
tokens [ i + 1 ] . type === 'paragraph_close' ) {
content = tokens [ i ] . content ;
while ( content . length ) {
pos = parseAbbr ( content , state . inline , state . options , state . env ) ;
if ( pos < 0 ) { break ; }
content = content . slice ( pos ) . trim ( ) ;
}
tokens [ i ] . content = content ;
if ( ! content . length ) {
tokens [ i - 1 ] . tight = true ;
tokens [ i + 1 ] . tight = true ;
}
}
}
} ;
} , { "../helpers/parse_link_label" : 12 , "../rules_inline/state_inline" : 55 } ] , 34 : [ function ( require , module , exports ) {
// Enclose abbreviations in <abbr> tags
//
'use strict' ;
var PUNCT _CHARS = ' \n()[]\'".,!?-' ;
// from Google closure library
// http://closure-library.googlecode.com/git-history/docs/local_closure_goog_string_string.js.source.html#line1021
function regEscape ( s ) {
return s . replace ( /([-()\[\]{}+?*.$\^|,:#<!\\])/g , '\\$1' ) ;
}
module . exports = function abbr2 ( state ) {
var i , j , l , tokens , token , text , nodes , pos , level , reg , m , regText ,
blockTokens = state . tokens ;
if ( ! state . env . abbreviations ) { return ; }
if ( ! state . env . abbrRegExp ) {
regText = '(^|[' + PUNCT _CHARS . split ( '' ) . map ( regEscape ) . join ( '' ) + '])'
+ '(' + Object . keys ( state . env . abbreviations ) . map ( function ( x ) {
return x . substr ( 1 ) ;
} ) . sort ( function ( a , b ) {
return b . length - a . length ;
} ) . map ( regEscape ) . join ( '|' ) + ')'
+ '($|[' + PUNCT _CHARS . split ( '' ) . map ( regEscape ) . join ( '' ) + '])' ;
state . env . abbrRegExp = new RegExp ( regText , 'g' ) ;
}
reg = state . env . abbrRegExp ;
for ( j = 0 , l = blockTokens . length ; j < l ; j ++ ) {
if ( blockTokens [ j ] . type !== 'inline' ) { continue ; }
tokens = blockTokens [ j ] . children ;
// We scan from the end, to keep position when new tags added.
for ( i = tokens . length - 1 ; i >= 0 ; i -- ) {
token = tokens [ i ] ;
if ( token . type !== 'text' ) { continue ; }
pos = 0 ;
text = token . content ;
reg . lastIndex = 0 ;
level = token . level ;
nodes = [ ] ;
while ( ( m = reg . exec ( text ) ) ) {
if ( reg . lastIndex > pos ) {
nodes . push ( {
type : 'text' ,
content : text . slice ( pos , m . index + m [ 1 ] . length ) ,
level : level
} ) ;
}
nodes . push ( {
type : 'abbr_open' ,
title : state . env . abbreviations [ ':' + m [ 2 ] ] ,
level : level ++
} ) ;
nodes . push ( {
type : 'text' ,
content : m [ 2 ] ,
level : level
} ) ;
nodes . push ( {
type : 'abbr_close' ,
level : -- level
} ) ;
pos = reg . lastIndex - m [ 3 ] . length ;
}
if ( ! nodes . length ) { continue ; }
if ( pos < text . length ) {
nodes . push ( {
type : 'text' ,
content : text . slice ( pos ) ,
level : level
} ) ;
}
// replace current node
blockTokens [ j ] . children = tokens = [ ] . concat ( tokens . slice ( 0 , i ) , nodes , tokens . slice ( i + 1 ) ) ;
}
}
} ;
} , { } ] , 35 : [ function ( require , module , exports ) {
'use strict' ;
module . exports = function block ( state ) {
if ( state . inlineMode ) {
state . tokens . push ( {
type : 'inline' ,
content : state . src . replace ( /\n/g , ' ' ) . trim ( ) ,
level : 0 ,
lines : [ 0 , 1 ] ,
children : [ ]
} ) ;
} else {
state . block . parse ( state . src , state . options , state . env , state . tokens ) ;
}
} ;
} , { } ] , 36 : [ function ( require , module , exports ) {
'use strict' ;
module . exports = function footnote _block ( state ) {
var i , l , j , t , lastParagraph , list , tokens , current , currentLabel ,
level = 0 ,
insideRef = false ,
refTokens = { } ;
if ( ! state . env . footnotes ) { return ; }
state . tokens = state . tokens . filter ( function ( tok ) {
if ( tok . type === 'footnote_reference_open' ) {
insideRef = true ;
current = [ ] ;
currentLabel = tok . label ;
return false ;
}
if ( tok . type === 'footnote_reference_close' ) {
insideRef = false ;
// prepend ':' to avoid conflict with Object.prototype members
refTokens [ ':' + currentLabel ] = current ;
return false ;
}
if ( insideRef ) { current . push ( tok ) ; }
return ! insideRef ;
} ) ;
if ( ! state . env . footnotes . list ) { return ; }
list = state . env . footnotes . list ;
state . tokens . push ( {
type : 'footnote_block_open' ,
level : level ++
} ) ;
for ( i = 0 , l = list . length ; i < l ; i ++ ) {
state . tokens . push ( {
type : 'footnote_open' ,
id : i ,
level : level ++
} ) ;
if ( list [ i ] . tokens ) {
tokens = [ ] ;
tokens . push ( {
type : 'paragraph_open' ,
tight : false ,
level : level ++
} ) ;
tokens . push ( {
type : 'inline' ,
content : '' ,
level : level ,
children : list [ i ] . tokens
} ) ;
tokens . push ( {
type : 'paragraph_close' ,
tight : false ,
level : -- level
} ) ;
} else if ( list [ i ] . label ) {
tokens = refTokens [ ':' + list [ i ] . label ] ;
}
state . tokens = state . tokens . concat ( tokens ) ;
if ( state . tokens [ state . tokens . length - 1 ] . type === 'paragraph_close' ) {
lastParagraph = state . tokens . pop ( ) ;
} else {
lastParagraph = null ;
}
t = list [ i ] . count > 0 ? list [ i ] . count : 1 ;
for ( j = 0 ; j < t ; j ++ ) {
state . tokens . push ( {
type : 'footnote_anchor' ,
id : i ,
subId : j ,
level : level
} ) ;
}
if ( lastParagraph ) {
state . tokens . push ( lastParagraph ) ;
}
state . tokens . push ( {
type : 'footnote_close' ,
level : -- level
} ) ;
}
state . tokens . push ( {
type : 'footnote_block_close' ,
level : -- level
} ) ;
} ;
} , { } ] , 37 : [ function ( require , module , exports ) {
'use strict' ;
module . exports = function inline ( state ) {
var tokens = state . tokens , tok , i , l ;
// Parse inlines
for ( i = 0 , l = tokens . length ; i < l ; i ++ ) {
tok = tokens [ i ] ;
if ( tok . type === 'inline' ) {
state . inline . parse ( tok . content , state . options , state . env , tok . children ) ;
}
}
} ;
} , { } ] , 38 : [ function ( require , module , exports ) {
// Replace link-like texts with link nodes.
//
// Currently restricted by `inline.validateLink()` to http/https/ftp
//
'use strict' ;
var Autolinker = require ( 'autolinker' ) ;
var LINK _SCAN _RE = /www|@|\:\/\// ;
function isLinkOpen ( str ) {
return /^<a[>\s]/i . test ( str ) ;
}
function isLinkClose ( str ) {
return /^<\/a\s*>/i . test ( str ) ;
}
// Stupid fabric to avoid singletons, for thread safety.
// Required for engines like Nashorn.
//
function createLinkifier ( ) {
var links = [ ] ;
var autolinker = new Autolinker ( {
stripPrefix : false ,
url : true ,
email : true ,
twitter : false ,
replaceFn : function ( autolinker , match ) {
// Only collect matched strings but don't change anything.
switch ( match . getType ( ) ) {
/*eslint default-case:0*/
case 'url' :
links . push ( {
text : match . matchedText ,
url : match . getUrl ( )
} ) ;
break ;
case 'email' :
links . push ( {
text : match . matchedText ,
// normalize email protocol
url : 'mailto:' + match . getEmail ( ) . replace ( /^mailto:/i , '' )
} ) ;
break ;
}
return false ;
}
} ) ;
return {
links : links ,
autolinker : autolinker
} ;
}
module . exports = function linkify ( state ) {
var i , j , l , tokens , token , text , nodes , ln , pos , level , htmlLinkLevel ,
blockTokens = state . tokens ,
linkifier = null , links , autolinker ;
if ( ! state . options . linkify ) { return ; }
for ( j = 0 , l = blockTokens . length ; j < l ; j ++ ) {
if ( blockTokens [ j ] . type !== 'inline' ) { continue ; }
tokens = blockTokens [ j ] . children ;
htmlLinkLevel = 0 ;
// We scan from the end, to keep position when new tags added.
// Use reversed logic in links start/end match
for ( i = tokens . length - 1 ; i >= 0 ; i -- ) {
token = tokens [ i ] ;
// Skip content of markdown links
if ( token . type === 'link_close' ) {
i -- ;
while ( tokens [ i ] . level !== token . level && tokens [ i ] . type !== 'link_open' ) {
i -- ;
}
continue ;
}
// Skip content of html tag links
if ( token . type === 'htmltag' ) {
if ( isLinkOpen ( token . content ) && htmlLinkLevel > 0 ) {
htmlLinkLevel -- ;
}
if ( isLinkClose ( token . content ) ) {
htmlLinkLevel ++ ;
}
}
if ( htmlLinkLevel > 0 ) { continue ; }
if ( token . type === 'text' && LINK _SCAN _RE . test ( token . content ) ) {
// Init linkifier in lazy manner, only if required.
if ( ! linkifier ) {
linkifier = createLinkifier ( ) ;
links = linkifier . links ;
autolinker = linkifier . autolinker ;
}
text = token . content ;
links . length = 0 ;
autolinker . link ( text ) ;
if ( ! links . length ) { continue ; }
// Now split string to nodes
nodes = [ ] ;
level = token . level ;
for ( ln = 0 ; ln < links . length ; ln ++ ) {
if ( ! state . inline . validateLink ( links [ ln ] . url ) ) { continue ; }
pos = text . indexOf ( links [ ln ] . text ) ;
if ( pos ) {
level = level ;
nodes . push ( {
type : 'text' ,
content : text . slice ( 0 , pos ) ,
level : level
} ) ;
}
nodes . push ( {
type : 'link_open' ,
href : links [ ln ] . url ,
title : '' ,
level : level ++
} ) ;
nodes . push ( {
type : 'text' ,
content : links [ ln ] . text ,
level : level
} ) ;
nodes . push ( {
type : 'link_close' ,
level : -- level
} ) ;
text = text . slice ( pos + links [ ln ] . text . length ) ;
}
if ( text . length ) {
nodes . push ( {
type : 'text' ,
content : text ,
level : level
} ) ;
}
// replace current node
blockTokens [ j ] . children = tokens = [ ] . concat ( tokens . slice ( 0 , i ) , nodes , tokens . slice ( i + 1 ) ) ;
}
}
}
} ;
} , { "autolinker" : 59 } ] , 39 : [ function ( require , module , exports ) {
'use strict' ;
var StateInline = require ( '../rules_inline/state_inline' ) ;
var parseLinkLabel = require ( '../helpers/parse_link_label' ) ;
var parseLinkDestination = require ( '../helpers/parse_link_destination' ) ;
var parseLinkTitle = require ( '../helpers/parse_link_title' ) ;
var normalizeReference = require ( '../helpers/normalize_reference' ) ;
function parseReference ( str , parser , options , env ) {
var state , labelEnd , pos , max , code , start , href , title , label ;
if ( str . charCodeAt ( 0 ) !== 0x5B /* [ */ ) { return - 1 ; }
if ( str . indexOf ( ']:' ) === - 1 ) { return - 1 ; }
state = new StateInline ( str , parser , options , env , [ ] ) ;
labelEnd = parseLinkLabel ( state , 0 ) ;
if ( labelEnd < 0 || str . charCodeAt ( labelEnd + 1 ) !== 0x3A /* : */ ) { return - 1 ; }
max = state . posMax ;
// [label]: destination 'title'
// ^^^ skip optional whitespace here
for ( pos = labelEnd + 2 ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
// [label]: destination 'title'
// ^^^^^^^^^^^ parse this
if ( ! parseLinkDestination ( state , pos ) ) { return - 1 ; }
href = state . linkContent ;
pos = state . pos ;
// [label]: destination 'title'
// ^^^ skipping those spaces
start = pos ;
for ( pos = pos + 1 ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
// [label]: destination 'title'
// ^^^^^^^ parse this
if ( pos < max && start !== pos && parseLinkTitle ( state , pos ) ) {
title = state . linkContent ;
pos = state . pos ;
} else {
title = '' ;
pos = start ;
}
// ensure that the end of the line is empty
while ( pos < max && state . src . charCodeAt ( pos ) === 0x20 /* space */ ) { pos ++ ; }
if ( pos < max && state . src . charCodeAt ( pos ) !== 0x0A ) { return - 1 ; }
label = normalizeReference ( str . slice ( 1 , labelEnd ) ) ;
if ( typeof env . references [ label ] === 'undefined' ) {
env . references [ label ] = { title : title , href : href } ;
}
return pos ;
}
module . exports = function references ( state ) {
var tokens = state . tokens , i , l , content , pos ;
state . env . references = state . env . references || { } ;
if ( state . inlineMode ) {
return ;
}
// Scan definitions in paragraph inlines
for ( i = 1 , l = tokens . length - 1 ; i < l ; i ++ ) {
if ( tokens [ i ] . type === 'inline' &&
tokens [ i - 1 ] . type === 'paragraph_open' &&
tokens [ i + 1 ] . type === 'paragraph_close' ) {
content = tokens [ i ] . content ;
while ( content . length ) {
pos = parseReference ( content , state . inline , state . options , state . env ) ;
if ( pos < 0 ) { break ; }
content = content . slice ( pos ) . trim ( ) ;
}
tokens [ i ] . content = content ;
if ( ! content . length ) {
tokens [ i - 1 ] . tight = true ;
tokens [ i + 1 ] . tight = true ;
}
}
}
} ;
} , { "../helpers/normalize_reference" : 10 , "../helpers/parse_link_destination" : 11 , "../helpers/parse_link_label" : 12 , "../helpers/parse_link_title" : 13 , "../rules_inline/state_inline" : 55 } ] , 40 : [ function ( require , module , exports ) {
// Simple typographyc replacements
//
'use strict' ;
// TODO:
// - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾
// - miltiplication 2 x 4 -> 2 × 4
var RARE _RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/ ;
var SCOPED _ABBR _RE = /\((c|tm|r|p)\)/ig ;
var SCOPED _ABBR = {
'c' : '©' ,
'r' : '®' ,
'p' : '§' ,
'tm' : '™'
} ;
function replaceScopedAbbr ( str ) {
if ( str . indexOf ( '(' ) < 0 ) { return str ; }
return str . replace ( SCOPED _ABBR _RE , function ( match , name ) {
return SCOPED _ABBR [ name . toLowerCase ( ) ] ;
} ) ;
}
module . exports = function replace ( state ) {
var i , token , text , inlineTokens , blkIdx ;
if ( ! state . options . typographer ) { return ; }
for ( blkIdx = state . tokens . length - 1 ; blkIdx >= 0 ; blkIdx -- ) {
if ( state . tokens [ blkIdx ] . type !== 'inline' ) { continue ; }
inlineTokens = state . tokens [ blkIdx ] . children ;
for ( i = inlineTokens . length - 1 ; i >= 0 ; i -- ) {
token = inlineTokens [ i ] ;
if ( token . type === 'text' ) {
text = token . content ;
text = replaceScopedAbbr ( text ) ;
if ( RARE _RE . test ( text ) ) {
text = text . replace ( /\+-/g , '±' )
// .., ..., ....... -> …
// but ?..... & !..... -> ?.. & !..
. replace ( /\.{2,}/g , '…' ) . replace ( /([?!])…/g , '$1..' )
. replace ( /([?!]){4,}/g , '$1$1$1' ) . replace ( /,{2,}/g , ',' )
// em-dash
. replace ( /(^|[^-])---([^-]|$)/mg , '$1\u2014$2' )
// en-dash
. replace ( /(^|\s)--(\s|$)/mg , '$1\u2013$2' )
. replace ( /(^|[^-\s])--([^-\s]|$)/mg , '$1\u2013$2' ) ;
}
token . content = text ;
}
}
}
} ;
} , { } ] , 41 : [ function ( require , module , exports ) {
// Convert straight quotation marks to typographic ones
//
'use strict' ;
var QUOTE _TEST _RE = /['"]/ ;
var QUOTE _RE = /['"]/g ;
var PUNCT _RE = /[-\s()\[\]]/ ;
var APOSTROPHE = '’ ' ;
// This function returns true if the character at `pos`
// could be inside a word.
function isLetter ( str , pos ) {
if ( pos < 0 || pos >= str . length ) { return false ; }
return ! PUNCT _RE . test ( str [ pos ] ) ;
}
function replaceAt ( str , index , ch ) {
return str . substr ( 0 , index ) + ch + str . substr ( index + 1 ) ;
}
module . exports = function smartquotes ( state ) {
/*eslint max-depth:0*/
var i , token , text , t , pos , max , thisLevel , lastSpace , nextSpace , item ,
canOpen , canClose , j , isSingle , blkIdx , tokens ,
stack ;
if ( ! state . options . typographer ) { return ; }
stack = [ ] ;
for ( blkIdx = state . tokens . length - 1 ; blkIdx >= 0 ; blkIdx -- ) {
if ( state . tokens [ blkIdx ] . type !== 'inline' ) { continue ; }
tokens = state . tokens [ blkIdx ] . children ;
stack . length = 0 ;
for ( i = 0 ; i < tokens . length ; i ++ ) {
token = tokens [ i ] ;
if ( token . type !== 'text' || QUOTE _TEST _RE . test ( token . text ) ) { continue ; }
thisLevel = tokens [ i ] . level ;
for ( j = stack . length - 1 ; j >= 0 ; j -- ) {
if ( stack [ j ] . level <= thisLevel ) { break ; }
}
stack . length = j + 1 ;
text = token . content ;
pos = 0 ;
max = text . length ;
/*eslint no-labels:0,block-scoped-var:0*/
OUTER :
while ( pos < max ) {
QUOTE _RE . lastIndex = pos ;
t = QUOTE _RE . exec ( text ) ;
if ( ! t ) { break ; }
lastSpace = ! isLetter ( text , t . index - 1 ) ;
pos = t . index + 1 ;
isSingle = ( t [ 0 ] === "'" ) ;
nextSpace = ! isLetter ( text , pos ) ;
if ( ! nextSpace && ! lastSpace ) {
// middle of word
if ( isSingle ) {
token . content = replaceAt ( token . content , t . index , APOSTROPHE ) ;
}
continue ;
}
canOpen = ! nextSpace ;
canClose = ! lastSpace ;
if ( canClose ) {
// this could be a closing quote, rewind the stack to get a match
for ( j = stack . length - 1 ; j >= 0 ; j -- ) {
item = stack [ j ] ;
if ( stack [ j ] . level < thisLevel ) { break ; }
if ( item . single === isSingle && stack [ j ] . level === thisLevel ) {
item = stack [ j ] ;
if ( isSingle ) {
tokens [ item . token ] . content = replaceAt ( tokens [ item . token ] . content , item . pos , state . options . quotes [ 2 ] ) ;
token . content = replaceAt ( token . content , t . index , state . options . quotes [ 3 ] ) ;
} else {
tokens [ item . token ] . content = replaceAt ( tokens [ item . token ] . content , item . pos , state . options . quotes [ 0 ] ) ;
token . content = replaceAt ( token . content , t . index , state . options . quotes [ 1 ] ) ;
}
stack . length = j ;
continue OUTER ;
}
}
}
if ( canOpen ) {
stack . push ( {
token : i ,
pos : t . index ,
single : isSingle ,
level : thisLevel
} ) ;
} else if ( canClose && isSingle ) {
token . content = replaceAt ( token . content , t . index , APOSTROPHE ) ;
}
}
}
}
} ;
} , { } ] , 42 : [ function ( require , module , exports ) {
// Process autolinks '<protocol:...>'
'use strict' ;
var url _schemas = require ( '../common/url_schemas' ) ;
var normalizeLink = require ( '../helpers/normalize_link' ) ;
/*eslint max-len:0*/
var EMAIL _RE = /^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/ ;
var AUTOLINK _RE = /^<([a-zA-Z.\-]{1,25}):([^<>\x00-\x20]*)>/ ;
module . exports = function autolink ( state , silent ) {
var tail , linkMatch , emailMatch , url , fullUrl , pos = state . pos ;
if ( state . src . charCodeAt ( pos ) !== 0x3C /* < */ ) { return false ; }
tail = state . src . slice ( pos ) ;
if ( tail . indexOf ( '>' ) < 0 ) { return false ; }
linkMatch = tail . match ( AUTOLINK _RE ) ;
if ( linkMatch ) {
if ( url _schemas . indexOf ( linkMatch [ 1 ] . toLowerCase ( ) ) < 0 ) { return false ; }
url = linkMatch [ 0 ] . slice ( 1 , - 1 ) ;
fullUrl = normalizeLink ( url ) ;
if ( ! state . parser . validateLink ( url ) ) { return false ; }
if ( ! silent ) {
state . push ( {
type : 'link_open' ,
href : fullUrl ,
level : state . level
} ) ;
state . push ( {
type : 'text' ,
content : url ,
level : state . level + 1
} ) ;
state . push ( { type : 'link_close' , level : state . level } ) ;
}
state . pos += linkMatch [ 0 ] . length ;
return true ;
}
emailMatch = tail . match ( EMAIL _RE ) ;
if ( emailMatch ) {
url = emailMatch [ 0 ] . slice ( 1 , - 1 ) ;
fullUrl = normalizeLink ( 'mailto:' + url ) ;
if ( ! state . parser . validateLink ( fullUrl ) ) { return false ; }
if ( ! silent ) {
state . push ( {
type : 'link_open' ,
href : fullUrl ,
level : state . level
} ) ;
state . push ( {
type : 'text' ,
content : url ,
level : state . level + 1
} ) ;
state . push ( { type : 'link_close' , level : state . level } ) ;
}
state . pos += emailMatch [ 0 ] . length ;
return true ;
}
return false ;
} ;
} , { "../common/url_schemas" : 4 , "../helpers/normalize_link" : 9 } ] , 43 : [ function ( require , module , exports ) {
// Parse backticks
'use strict' ;
module . exports = function backticks ( state , silent ) {
var start , max , marker , matchStart , matchEnd ,
pos = state . pos ,
ch = state . src . charCodeAt ( pos ) ;
if ( ch !== 0x60 /* ` */ ) { return false ; }
start = pos ;
pos ++ ;
max = state . posMax ;
while ( pos < max && state . src . charCodeAt ( pos ) === 0x60 /* ` */ ) { pos ++ ; }
marker = state . src . slice ( start , pos ) ;
matchStart = matchEnd = pos ;
while ( ( matchStart = state . src . indexOf ( '`' , matchEnd ) ) !== - 1 ) {
matchEnd = matchStart + 1 ;
while ( matchEnd < max && state . src . charCodeAt ( matchEnd ) === 0x60 /* ` */ ) { matchEnd ++ ; }
if ( matchEnd - matchStart === marker . length ) {
if ( ! silent ) {
state . push ( {
type : 'code' ,
content : state . src . slice ( pos , matchStart )
. replace ( /[ \n]+/g , ' ' )
. trim ( ) ,
block : false ,
level : state . level
} ) ;
}
state . pos = matchEnd ;
return true ;
}
}
if ( ! silent ) { state . pending += marker ; }
state . pos += marker . length ;
return true ;
} ;
} , { } ] , 44 : [ function ( require , module , exports ) {
// Process ~~deleted text~~
'use strict' ;
module . exports = function del ( state , silent ) {
var found ,
pos ,
stack ,
max = state . posMax ,
start = state . pos ,
lastChar ,
nextChar ;
if ( state . src . charCodeAt ( start ) !== 0x7E /* ~ */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
if ( start + 4 >= max ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x7E /* ~ */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
lastChar = start > 0 ? state . src . charCodeAt ( start - 1 ) : - 1 ;
nextChar = state . src . charCodeAt ( start + 2 ) ;
if ( lastChar === 0x7E /* ~ */ ) { return false ; }
if ( nextChar === 0x7E /* ~ */ ) { return false ; }
if ( nextChar === 0x20 || nextChar === 0x0A ) { return false ; }
pos = start + 2 ;
while ( pos < max && state . src . charCodeAt ( pos ) === 0x7E /* ~ */ ) { pos ++ ; }
if ( pos > start + 3 ) {
// sequence of 4+ markers taking as literal, same as in a emphasis
state . pos += pos - start ;
if ( ! silent ) { state . pending += state . src . slice ( start , pos ) ; }
return true ;
}
state . pos = start + 2 ;
stack = 1 ;
while ( state . pos + 1 < max ) {
if ( state . src . charCodeAt ( state . pos ) === 0x7E /* ~ */ ) {
if ( state . src . charCodeAt ( state . pos + 1 ) === 0x7E /* ~ */ ) {
lastChar = state . src . charCodeAt ( state . pos - 1 ) ;
nextChar = state . pos + 2 < max ? state . src . charCodeAt ( state . pos + 2 ) : - 1 ;
if ( nextChar !== 0x7E /* ~ */ && lastChar !== 0x7E /* ~ */ ) {
if ( lastChar !== 0x20 && lastChar !== 0x0A ) {
// closing '~~'
stack -- ;
} else if ( nextChar !== 0x20 && nextChar !== 0x0A ) {
// opening '~~'
stack ++ ;
} // else {
// // standalone ' ~~ ' indented with spaces
// }
if ( stack <= 0 ) {
found = true ;
break ;
}
}
}
}
state . parser . skipToken ( state ) ;
}
if ( ! found ) {
// parser failed to find ending tag, so it's not valid emphasis
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + 2 ;
if ( ! silent ) {
state . push ( { type : 'del_open' , level : state . level ++ } ) ;
state . parser . tokenize ( state ) ;
state . push ( { type : 'del_close' , level : -- state . level } ) ;
}
state . pos = state . posMax + 2 ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 45 : [ function ( require , module , exports ) {
// Process *this* and _that_
'use strict' ;
function isAlphaNum ( code ) {
return ( code >= 0x30 /* 0 */ && code <= 0x39 /* 9 */ ) ||
( code >= 0x41 /* A */ && code <= 0x5A /* Z */ ) ||
( code >= 0x61 /* a */ && code <= 0x7A /* z */ ) ;
}
// parse sequence of emphasis markers,
// "start" should point at a valid marker
function scanDelims ( state , start ) {
var pos = start , lastChar , nextChar , count ,
can _open = true ,
can _close = true ,
max = state . posMax ,
marker = state . src . charCodeAt ( start ) ;
lastChar = start > 0 ? state . src . charCodeAt ( start - 1 ) : - 1 ;
while ( pos < max && state . src . charCodeAt ( pos ) === marker ) { pos ++ ; }
if ( pos >= max ) { can _open = false ; }
count = pos - start ;
if ( count >= 4 ) {
// sequence of four or more unescaped markers can't start/end an emphasis
can _open = can _close = false ;
} else {
nextChar = pos < max ? state . src . charCodeAt ( pos ) : - 1 ;
// check whitespace conditions
if ( nextChar === 0x20 || nextChar === 0x0A ) { can _open = false ; }
if ( lastChar === 0x20 || lastChar === 0x0A ) { can _close = false ; }
if ( marker === 0x5F /* _ */ ) {
// check if we aren't inside the word
if ( isAlphaNum ( lastChar ) ) { can _open = false ; }
if ( isAlphaNum ( nextChar ) ) { can _close = false ; }
}
}
return {
can _open : can _open ,
can _close : can _close ,
delims : count
} ;
}
module . exports = function emphasis ( state , silent ) {
var startCount ,
count ,
found ,
oldCount ,
newCount ,
stack ,
res ,
max = state . posMax ,
start = state . pos ,
marker = state . src . charCodeAt ( start ) ;
if ( marker !== 0x5F /* _ */ && marker !== 0x2A /* * */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
res = scanDelims ( state , start ) ;
startCount = res . delims ;
if ( ! res . can _open ) {
state . pos += startCount ;
if ( ! silent ) { state . pending += state . src . slice ( start , state . pos ) ; }
return true ;
}
if ( state . level >= state . options . maxNesting ) { return false ; }
state . pos = start + startCount ;
stack = [ startCount ] ;
while ( state . pos < max ) {
if ( state . src . charCodeAt ( state . pos ) === marker ) {
res = scanDelims ( state , state . pos ) ;
count = res . delims ;
if ( res . can _close ) {
oldCount = stack . pop ( ) ;
newCount = count ;
while ( oldCount !== newCount ) {
if ( newCount < oldCount ) {
stack . push ( oldCount - newCount ) ;
break ;
}
// assert(newCount > oldCount)
newCount -= oldCount ;
if ( stack . length === 0 ) { break ; }
state . pos += oldCount ;
oldCount = stack . pop ( ) ;
}
if ( stack . length === 0 ) {
startCount = oldCount ;
found = true ;
break ;
}
state . pos += count ;
continue ;
}
if ( res . can _open ) { stack . push ( count ) ; }
state . pos += count ;
continue ;
}
state . parser . skipToken ( state ) ;
}
if ( ! found ) {
// parser failed to find ending tag, so it's not valid emphasis
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + startCount ;
if ( ! silent ) {
if ( startCount === 2 || startCount === 3 ) {
state . push ( { type : 'strong_open' , level : state . level ++ } ) ;
}
if ( startCount === 1 || startCount === 3 ) {
state . push ( { type : 'em_open' , level : state . level ++ } ) ;
}
state . parser . tokenize ( state ) ;
if ( startCount === 1 || startCount === 3 ) {
state . push ( { type : 'em_close' , level : -- state . level } ) ;
}
if ( startCount === 2 || startCount === 3 ) {
state . push ( { type : 'strong_close' , level : -- state . level } ) ;
}
}
state . pos = state . posMax + startCount ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 46 : [ function ( require , module , exports ) {
// Process html entity - {, ¯, ", ...
'use strict' ;
var entities = require ( '../common/entities' ) ;
var has = require ( '../common/utils' ) . has ;
var isValidEntityCode = require ( '../common/utils' ) . isValidEntityCode ;
var fromCodePoint = require ( '../common/utils' ) . fromCodePoint ;
var DIGITAL _RE = /^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i ;
var NAMED _RE = /^&([a-z][a-z0-9]{1,31});/i ;
module . exports = function entity ( state , silent ) {
var ch , code , match , pos = state . pos , max = state . posMax ;
if ( state . src . charCodeAt ( pos ) !== 0x26 /* & */ ) { return false ; }
if ( pos + 1 < max ) {
ch = state . src . charCodeAt ( pos + 1 ) ;
if ( ch === 0x23 /* # */ ) {
match = state . src . slice ( pos ) . match ( DIGITAL _RE ) ;
if ( match ) {
if ( ! silent ) {
code = match [ 1 ] [ 0 ] . toLowerCase ( ) === 'x' ? parseInt ( match [ 1 ] . slice ( 1 ) , 16 ) : parseInt ( match [ 1 ] , 10 ) ;
state . pending += isValidEntityCode ( code ) ? fromCodePoint ( code ) : fromCodePoint ( 0xFFFD ) ;
}
state . pos += match [ 0 ] . length ;
return true ;
}
} else {
match = state . src . slice ( pos ) . match ( NAMED _RE ) ;
if ( match ) {
if ( has ( entities , match [ 1 ] ) ) {
if ( ! silent ) { state . pending += entities [ match [ 1 ] ] ; }
state . pos += match [ 0 ] . length ;
return true ;
}
}
}
}
if ( ! silent ) { state . pending += '&' ; }
state . pos ++ ;
return true ;
} ;
} , { "../common/entities" : 1 , "../common/utils" : 5 } ] , 47 : [ function ( require , module , exports ) {
// Proceess escaped chars and hardbreaks
'use strict' ;
var ESCAPED = [ ] ;
for ( var i = 0 ; i < 256 ; i ++ ) { ESCAPED . push ( 0 ) ; }
'\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-'
. split ( '' ) . forEach ( function ( ch ) { ESCAPED [ ch . charCodeAt ( 0 ) ] = 1 ; } ) ;
module . exports = function escape ( state , silent ) {
var ch , pos = state . pos , max = state . posMax ;
if ( state . src . charCodeAt ( pos ) !== 0x5C /* \ */ ) { return false ; }
pos ++ ;
if ( pos < max ) {
ch = state . src . charCodeAt ( pos ) ;
if ( ch < 256 && ESCAPED [ ch ] !== 0 ) {
if ( ! silent ) { state . pending += state . src [ pos ] ; }
state . pos += 2 ;
return true ;
}
if ( ch === 0x0A ) {
if ( ! silent ) {
state . push ( {
type : 'hardbreak' ,
level : state . level
} ) ;
}
pos ++ ;
// skip leading whitespaces from next line
while ( pos < max && state . src . charCodeAt ( pos ) === 0x20 ) { pos ++ ; }
state . pos = pos ;
return true ;
}
}
if ( ! silent ) { state . pending += '\\' ; }
state . pos ++ ;
return true ;
} ;
} , { } ] , 48 : [ function ( require , module , exports ) {
// Process inline footnotes (^[...])
'use strict' ;
var parseLinkLabel = require ( '../helpers/parse_link_label' ) ;
module . exports = function footnote _inline ( state , silent ) {
var labelStart ,
labelEnd ,
footnoteId ,
oldLength ,
max = state . posMax ,
start = state . pos ;
if ( start + 2 >= max ) { return false ; }
if ( state . src . charCodeAt ( start ) !== 0x5E /* ^ */ ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x5B /* [ */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
labelStart = start + 2 ;
labelEnd = parseLinkLabel ( state , start + 1 ) ;
// parser failed to find ']', so it's not a valid note
if ( labelEnd < 0 ) { return false ; }
// We found the end of the link, and know for a fact it's a valid link;
// so all that's left to do is to call tokenizer.
//
if ( ! silent ) {
if ( ! state . env . footnotes ) { state . env . footnotes = { } ; }
if ( ! state . env . footnotes . list ) { state . env . footnotes . list = [ ] ; }
footnoteId = state . env . footnotes . list . length ;
state . pos = labelStart ;
state . posMax = labelEnd ;
state . push ( {
type : 'footnote_ref' ,
id : footnoteId ,
level : state . level
} ) ;
state . linkLevel ++ ;
oldLength = state . tokens . length ;
state . parser . tokenize ( state ) ;
state . env . footnotes . list [ footnoteId ] = { tokens : state . tokens . splice ( oldLength ) } ;
state . linkLevel -- ;
}
state . pos = labelEnd + 1 ;
state . posMax = max ;
return true ;
} ;
} , { "../helpers/parse_link_label" : 12 } ] , 49 : [ function ( require , module , exports ) {
// Process footnote references ([^...])
'use strict' ;
module . exports = function footnote _ref ( state , silent ) {
var label ,
pos ,
footnoteId ,
footnoteSubId ,
max = state . posMax ,
start = state . pos ;
// should be at least 4 chars - "[^x]"
if ( start + 3 > max ) { return false ; }
if ( ! state . env . footnotes || ! state . env . footnotes . refs ) { return false ; }
if ( state . src . charCodeAt ( start ) !== 0x5B /* [ */ ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x5E /* ^ */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
for ( pos = start + 2 ; pos < max ; pos ++ ) {
if ( state . src . charCodeAt ( pos ) === 0x20 ) { return false ; }
if ( state . src . charCodeAt ( pos ) === 0x0A ) { return false ; }
if ( state . src . charCodeAt ( pos ) === 0x5D /* ] */ ) {
break ;
}
}
if ( pos === start + 2 ) { return false ; } // no empty footnote labels
if ( pos >= max ) { return false ; }
pos ++ ;
label = state . src . slice ( start + 2 , pos - 1 ) ;
if ( typeof state . env . footnotes . refs [ ':' + label ] === 'undefined' ) { return false ; }
if ( ! silent ) {
if ( ! state . env . footnotes . list ) { state . env . footnotes . list = [ ] ; }
if ( state . env . footnotes . refs [ ':' + label ] < 0 ) {
footnoteId = state . env . footnotes . list . length ;
state . env . footnotes . list [ footnoteId ] = { label : label , count : 0 } ;
state . env . footnotes . refs [ ':' + label ] = footnoteId ;
} else {
footnoteId = state . env . footnotes . refs [ ':' + label ] ;
}
footnoteSubId = state . env . footnotes . list [ footnoteId ] . count ;
state . env . footnotes . list [ footnoteId ] . count ++ ;
state . push ( {
type : 'footnote_ref' ,
id : footnoteId ,
subId : footnoteSubId ,
level : state . level
} ) ;
}
state . pos = pos ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 50 : [ function ( require , module , exports ) {
// Process html tags
'use strict' ;
var HTML _TAG _RE = require ( '../common/html_re' ) . HTML _TAG _RE ;
function isLetter ( ch ) {
/*eslint no-bitwise:0*/
var lc = ch | 0x20 ; // to lower case
return ( lc >= 0x61 /* a */ ) && ( lc <= 0x7a /* z */ ) ;
}
module . exports = function htmltag ( state , silent ) {
var ch , match , max , pos = state . pos ;
if ( ! state . options . html ) { return false ; }
// Check start
max = state . posMax ;
if ( state . src . charCodeAt ( pos ) !== 0x3C /* < */ ||
pos + 2 >= max ) {
return false ;
}
// Quick fail on second char
ch = state . src . charCodeAt ( pos + 1 ) ;
if ( ch !== 0x21 /* ! */ &&
ch !== 0x3F /* ? */ &&
ch !== 0x2F /* / */ &&
! isLetter ( ch ) ) {
return false ;
}
match = state . src . slice ( pos ) . match ( HTML _TAG _RE ) ;
if ( ! match ) { return false ; }
if ( ! silent ) {
state . push ( {
type : 'htmltag' ,
content : state . src . slice ( pos , pos + match [ 0 ] . length ) ,
level : state . level
} ) ;
}
state . pos += match [ 0 ] . length ;
return true ;
} ;
} , { "../common/html_re" : 3 } ] , 51 : [ function ( require , module , exports ) {
// Process ++inserted text++
'use strict' ;
module . exports = function ins ( state , silent ) {
var found ,
pos ,
stack ,
max = state . posMax ,
start = state . pos ,
lastChar ,
nextChar ;
if ( state . src . charCodeAt ( start ) !== 0x2B /* + */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
if ( start + 4 >= max ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x2B /* + */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
lastChar = start > 0 ? state . src . charCodeAt ( start - 1 ) : - 1 ;
nextChar = state . src . charCodeAt ( start + 2 ) ;
if ( lastChar === 0x2B /* + */ ) { return false ; }
if ( nextChar === 0x2B /* + */ ) { return false ; }
if ( nextChar === 0x20 || nextChar === 0x0A ) { return false ; }
pos = start + 2 ;
while ( pos < max && state . src . charCodeAt ( pos ) === 0x2B /* + */ ) { pos ++ ; }
if ( pos !== start + 2 ) {
// sequence of 3+ markers taking as literal, same as in a emphasis
state . pos += pos - start ;
if ( ! silent ) { state . pending += state . src . slice ( start , pos ) ; }
return true ;
}
state . pos = start + 2 ;
stack = 1 ;
while ( state . pos + 1 < max ) {
if ( state . src . charCodeAt ( state . pos ) === 0x2B /* + */ ) {
if ( state . src . charCodeAt ( state . pos + 1 ) === 0x2B /* + */ ) {
lastChar = state . src . charCodeAt ( state . pos - 1 ) ;
nextChar = state . pos + 2 < max ? state . src . charCodeAt ( state . pos + 2 ) : - 1 ;
if ( nextChar !== 0x2B /* + */ && lastChar !== 0x2B /* + */ ) {
if ( lastChar !== 0x20 && lastChar !== 0x0A ) {
// closing '++'
stack -- ;
} else if ( nextChar !== 0x20 && nextChar !== 0x0A ) {
// opening '++'
stack ++ ;
} // else {
// // standalone ' ++ ' indented with spaces
// }
if ( stack <= 0 ) {
found = true ;
break ;
}
}
}
}
state . parser . skipToken ( state ) ;
}
if ( ! found ) {
// parser failed to find ending tag, so it's not valid emphasis
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + 2 ;
if ( ! silent ) {
state . push ( { type : 'ins_open' , level : state . level ++ } ) ;
state . parser . tokenize ( state ) ;
state . push ( { type : 'ins_close' , level : -- state . level } ) ;
}
state . pos = state . posMax + 2 ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 52 : [ function ( require , module , exports ) {
// Process [links](<to> "stuff")
'use strict' ;
var parseLinkLabel = require ( '../helpers/parse_link_label' ) ;
var parseLinkDestination = require ( '../helpers/parse_link_destination' ) ;
var parseLinkTitle = require ( '../helpers/parse_link_title' ) ;
var normalizeReference = require ( '../helpers/normalize_reference' ) ;
module . exports = function links ( state , silent ) {
var labelStart ,
labelEnd ,
label ,
href ,
title ,
pos ,
ref ,
code ,
isImage = false ,
oldPos = state . pos ,
max = state . posMax ,
start = state . pos ,
marker = state . src . charCodeAt ( start ) ;
if ( marker === 0x21 /* ! */ ) {
isImage = true ;
marker = state . src . charCodeAt ( ++ start ) ;
}
if ( marker !== 0x5B /* [ */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
labelStart = start + 1 ;
labelEnd = parseLinkLabel ( state , start ) ;
// parser failed to find ']', so it's not a valid link
if ( labelEnd < 0 ) { return false ; }
pos = labelEnd + 1 ;
if ( pos < max && state . src . charCodeAt ( pos ) === 0x28 /* ( */ ) {
//
// Inline link
//
// [link]( <href> "title" )
// ^^ skipping these spaces
pos ++ ;
for ( ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
if ( pos >= max ) { return false ; }
// [link]( <href> "title" )
// ^^^^^^ parsing link destination
start = pos ;
if ( parseLinkDestination ( state , pos ) ) {
href = state . linkContent ;
pos = state . pos ;
} else {
href = '' ;
}
// [link]( <href> "title" )
// ^^ skipping these spaces
start = pos ;
for ( ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
// [link]( <href> "title" )
// ^^^^^^^ parsing link title
if ( pos < max && start !== pos && parseLinkTitle ( state , pos ) ) {
title = state . linkContent ;
pos = state . pos ;
// [link]( <href> "title" )
// ^^ skipping these spaces
for ( ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
} else {
title = '' ;
}
if ( pos >= max || state . src . charCodeAt ( pos ) !== 0x29 /* ) */ ) {
state . pos = oldPos ;
return false ;
}
pos ++ ;
} else {
//
// Link reference
//
// do not allow nested reference links
if ( state . linkLevel > 0 ) { return false ; }
// [foo] [bar]
// ^^ optional whitespace (can include newlines)
for ( ; pos < max ; pos ++ ) {
code = state . src . charCodeAt ( pos ) ;
if ( code !== 0x20 && code !== 0x0A ) { break ; }
}
if ( pos < max && state . src . charCodeAt ( pos ) === 0x5B /* [ */ ) {
start = pos + 1 ;
pos = parseLinkLabel ( state , pos ) ;
if ( pos >= 0 ) {
label = state . src . slice ( start , pos ++ ) ;
} else {
pos = start - 1 ;
}
}
// covers label === '' and label === undefined
// (collapsed reference link and shortcut reference link respectively)
if ( ! label ) { label = state . src . slice ( labelStart , labelEnd ) ; }
ref = state . env . references [ normalizeReference ( label ) ] ;
if ( ! ref ) {
state . pos = oldPos ;
return false ;
}
href = ref . href ;
title = ref . title ;
}
//
// We found the end of the link, and know for a fact it's a valid link;
// so all that's left to do is to call tokenizer.
//
if ( ! silent ) {
state . pos = labelStart ;
state . posMax = labelEnd ;
if ( isImage ) {
state . push ( {
type : 'image' ,
src : href ,
title : title ,
alt : state . src . substr ( labelStart , labelEnd - labelStart ) ,
level : state . level
} ) ;
} else {
state . push ( {
type : 'link_open' ,
href : href ,
title : title ,
level : state . level ++
} ) ;
state . linkLevel ++ ;
state . parser . tokenize ( state ) ;
state . linkLevel -- ;
state . push ( { type : 'link_close' , level : -- state . level } ) ;
}
}
state . pos = pos ;
state . posMax = max ;
return true ;
} ;
} , { "../helpers/normalize_reference" : 10 , "../helpers/parse_link_destination" : 11 , "../helpers/parse_link_label" : 12 , "../helpers/parse_link_title" : 13 } ] , 53 : [ function ( require , module , exports ) {
// Process ==highlighted text==
'use strict' ;
module . exports = function del ( state , silent ) {
var found ,
pos ,
stack ,
max = state . posMax ,
start = state . pos ,
lastChar ,
nextChar ;
if ( state . src . charCodeAt ( start ) !== 0x3D /* = */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
if ( start + 4 >= max ) { return false ; }
if ( state . src . charCodeAt ( start + 1 ) !== 0x3D /* = */ ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
lastChar = start > 0 ? state . src . charCodeAt ( start - 1 ) : - 1 ;
nextChar = state . src . charCodeAt ( start + 2 ) ;
if ( lastChar === 0x3D /* = */ ) { return false ; }
if ( nextChar === 0x3D /* = */ ) { return false ; }
if ( nextChar === 0x20 || nextChar === 0x0A ) { return false ; }
pos = start + 2 ;
while ( pos < max && state . src . charCodeAt ( pos ) === 0x3D /* = */ ) { pos ++ ; }
if ( pos !== start + 2 ) {
// sequence of 3+ markers taking as literal, same as in a emphasis
state . pos += pos - start ;
if ( ! silent ) { state . pending += state . src . slice ( start , pos ) ; }
return true ;
}
state . pos = start + 2 ;
stack = 1 ;
while ( state . pos + 1 < max ) {
if ( state . src . charCodeAt ( state . pos ) === 0x3D /* = */ ) {
if ( state . src . charCodeAt ( state . pos + 1 ) === 0x3D /* = */ ) {
lastChar = state . src . charCodeAt ( state . pos - 1 ) ;
nextChar = state . pos + 2 < max ? state . src . charCodeAt ( state . pos + 2 ) : - 1 ;
if ( nextChar !== 0x3D /* = */ && lastChar !== 0x3D /* = */ ) {
if ( lastChar !== 0x20 && lastChar !== 0x0A ) {
// closing '=='
stack -- ;
} else if ( nextChar !== 0x20 && nextChar !== 0x0A ) {
// opening '=='
stack ++ ;
} // else {
// // standalone ' == ' indented with spaces
// }
if ( stack <= 0 ) {
found = true ;
break ;
}
}
}
}
state . parser . skipToken ( state ) ;
}
if ( ! found ) {
// parser failed to find ending tag, so it's not valid emphasis
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + 2 ;
if ( ! silent ) {
state . push ( { type : 'mark_open' , level : state . level ++ } ) ;
state . parser . tokenize ( state ) ;
state . push ( { type : 'mark_close' , level : -- state . level } ) ;
}
state . pos = state . posMax + 2 ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 54 : [ function ( require , module , exports ) {
// Proceess '\n'
'use strict' ;
module . exports = function newline ( state , silent ) {
var pmax , max , pos = state . pos ;
if ( state . src . charCodeAt ( pos ) !== 0x0A /* \n */ ) { return false ; }
pmax = state . pending . length - 1 ;
max = state . posMax ;
// ' \n' -> hardbreak
// Lookup in pending chars is bad practice! Don't copy to other rules!
// Pending string is stored in concat mode, indexed lookups will cause
// convertion to flat mode.
if ( ! silent ) {
if ( pmax >= 0 && state . pending . charCodeAt ( pmax ) === 0x20 ) {
if ( pmax >= 1 && state . pending . charCodeAt ( pmax - 1 ) === 0x20 ) {
state . pending = state . pending . replace ( / +$/ , '' ) ;
state . push ( {
type : 'hardbreak' ,
level : state . level
} ) ;
} else {
state . pending = state . pending . slice ( 0 , - 1 ) ;
state . push ( {
type : 'softbreak' ,
level : state . level
} ) ;
}
} else {
state . push ( {
type : 'softbreak' ,
level : state . level
} ) ;
}
}
pos ++ ;
// skip heading spaces for next line
while ( pos < max && state . src . charCodeAt ( pos ) === 0x20 ) { pos ++ ; }
state . pos = pos ;
return true ;
} ;
} , { } ] , 55 : [ function ( require , module , exports ) {
// Inline parser state
'use strict' ;
function StateInline ( src , parserInline , options , env , outTokens ) {
this . src = src ;
this . env = env ;
this . options = options ;
this . parser = parserInline ;
this . tokens = outTokens ;
this . pos = 0 ;
this . posMax = this . src . length ;
this . level = 0 ;
this . pending = '' ;
this . pendingLevel = 0 ;
this . cache = [ ] ; // Stores { start: end } pairs. Useful for backtrack
// optimization of pairs parse (emphasis, strikes).
// Link parser state vars
this . isInLabel = false ; // Set true when seek link label - we should disable
// "paired" rules (emphasis, strikes) to not skip
// tailing `]`
this . linkLevel = 0 ; // Increment for each nesting link. Used to prevent
// nesting in definitions
this . linkContent = '' ; // Temporary storage for link url
this . labelUnmatchedScopes = 0 ; // Track unpaired `[` for link labels
// (backtrack optimization)
}
// Flush pending text
//
StateInline . prototype . pushPending = function ( ) {
this . tokens . push ( {
type : 'text' ,
content : this . pending ,
level : this . pendingLevel
} ) ;
this . pending = '' ;
} ;
// Push new token to "stream".
// If pending text exists - flush it as text token
//
StateInline . prototype . push = function ( token ) {
if ( this . pending ) {
this . pushPending ( ) ;
}
this . tokens . push ( token ) ;
this . pendingLevel = this . level ;
} ;
// Store value to cache.
// !!! Implementation has parser-specific optimizations
// !!! keys MUST be integer, >= 0; values MUST be integer, > 0
//
StateInline . prototype . cacheSet = function ( key , val ) {
for ( var i = this . cache . length ; i <= key ; i ++ ) {
this . cache . push ( 0 ) ;
}
this . cache [ key ] = val ;
} ;
// Get cache value
//
StateInline . prototype . cacheGet = function ( key ) {
return key < this . cache . length ? this . cache [ key ] : 0 ;
} ;
module . exports = StateInline ;
} , { } ] , 56 : [ function ( require , module , exports ) {
// Process ~subscript~
'use strict' ;
// same as UNESCAPE_MD_RE plus a space
var UNESCAPE _RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g ;
module . exports = function sub ( state , silent ) {
var found ,
content ,
max = state . posMax ,
start = state . pos ;
if ( state . src . charCodeAt ( start ) !== 0x7E /* ~ */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
if ( start + 2 >= max ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
state . pos = start + 1 ;
while ( state . pos < max ) {
if ( state . src . charCodeAt ( state . pos ) === 0x7E /* ~ */ ) {
found = true ;
break ;
}
state . parser . skipToken ( state ) ;
}
if ( ! found || start + 1 === state . pos ) {
state . pos = start ;
return false ;
}
content = state . src . slice ( start + 1 , state . pos ) ;
// don't allow unescaped spaces/newlines inside
if ( content . match ( /(^|[^\\])(\\\\)*\s/ ) ) {
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + 1 ;
if ( ! silent ) {
state . push ( {
type : 'sub' ,
level : state . level ,
content : content . replace ( UNESCAPE _RE , '$1' )
} ) ;
}
state . pos = state . posMax + 1 ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 57 : [ function ( require , module , exports ) {
// Process ^superscript^
'use strict' ;
// same as UNESCAPE_MD_RE plus a space
var UNESCAPE _RE = /\\([ \\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g ;
module . exports = function sup ( state , silent ) {
var found ,
content ,
max = state . posMax ,
start = state . pos ;
if ( state . src . charCodeAt ( start ) !== 0x5E /* ^ */ ) { return false ; }
if ( silent ) { return false ; } // don't run any pairs in validation mode
if ( start + 2 >= max ) { return false ; }
if ( state . level >= state . options . maxNesting ) { return false ; }
state . pos = start + 1 ;
while ( state . pos < max ) {
if ( state . src . charCodeAt ( state . pos ) === 0x5E /* ^ */ ) {
found = true ;
break ;
}
state . parser . skipToken ( state ) ;
}
if ( ! found || start + 1 === state . pos ) {
state . pos = start ;
return false ;
}
content = state . src . slice ( start + 1 , state . pos ) ;
// don't allow unescaped spaces/newlines inside
if ( content . match ( /(^|[^\\])(\\\\)*\s/ ) ) {
state . pos = start ;
return false ;
}
// found!
state . posMax = state . pos ;
state . pos = start + 1 ;
if ( ! silent ) {
state . push ( {
type : 'sup' ,
level : state . level ,
content : content . replace ( UNESCAPE _RE , '$1' )
} ) ;
}
state . pos = state . posMax + 1 ;
state . posMax = max ;
return true ;
} ;
} , { } ] , 58 : [ function ( require , module , exports ) {
// Skip text characters for text token, place those to pending buffer
// and increment current pos
'use strict' ;
// Rule to skip pure text
// '{}$%@~+=:' reserved for extentions
function isTerminatorChar ( ch ) {
switch ( ch ) {
case 0x0A /* \n */ :
case 0x5C /* \ */ :
case 0x60 /* ` */ :
case 0x2A /* * */ :
case 0x5F /* _ */ :
case 0x5E /* ^ */ :
case 0x5B /* [ */ :
case 0x5D /* ] */ :
case 0x21 /* ! */ :
case 0x26 /* & */ :
case 0x3C /* < */ :
case 0x3E /* > */ :
case 0x7B /* { */ :
case 0x7D /* } */ :
case 0x24 /* $ */ :
case 0x25 /* % */ :
case 0x40 /* @ */ :
case 0x7E /* ~ */ :
case 0x2B /* + */ :
case 0x3D /* = */ :
case 0x3A /* : */ :
return true ;
default :
return false ;
}
}
module . exports = function text ( state , silent ) {
var pos = state . pos ;
while ( pos < state . posMax && ! isTerminatorChar ( state . src . charCodeAt ( pos ) ) ) {
pos ++ ;
}
if ( pos === state . pos ) { return false ; }
if ( ! silent ) { state . pending += state . src . slice ( state . pos , pos ) ; }
state . pos = pos ;
return true ;
} ;
} , { } ] , 59 : [ function ( require , module , exports ) {
( function ( root , factory ) {
if ( typeof define === 'function' && define . amd ) {
// AMD. Register as an anonymous module.
define ( [ ] , function ( ) {
return ( root . returnExportsGlobal = factory ( ) ) ;
} ) ;
} else if ( typeof exports === 'object' ) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like enviroments that support module.exports,
// like Node.
module . exports = factory ( ) ;
} else {
root [ 'Autolinker' ] = factory ( ) ;
}
} ( this , function ( ) {
/ * !
* Autolinker . js
* 0.15 . 0
*
* Copyright ( c ) 2014 Gregory Jacobs < greg @ greg - jacobs . com >
* MIT Licensed . http : //www.opensource.org/licenses/mit-license.php
*
* https : //github.com/gregjacobs/Autolinker.js
* /
/ * *
* @ class Autolinker
* @ extends Object
*
* Utility class used to process a given string of text , and wrap the URLs , email addresses , and Twitter handles in
* the appropriate anchor ( & lt ; a & gt ; ) tags to turn them into links .
*
* Any of the configuration options may be provided in an Object ( map ) provided to the Autolinker constructor , which
* will configure how the { @ link # link link ( ) } method will process the links .
*
* For example :
*
* var autolinker = new Autolinker ( {
* newWindow : false ,
* truncate : 30
* } ) ;
*
* var html = autolinker . link ( "Joe went to www.yahoo.com" ) ;
* // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
*
*
* The { @ link # static - link static link ( ) } method may also be used to inline options into a single call , which may
* be more convenient for one - off uses . For example :
*
* var html = Autolinker . link ( "Joe went to www.yahoo.com" , {
* newWindow : false ,
* truncate : 30
* } ) ;
* // produces: 'Joe went to <a href="http://www.yahoo.com">yahoo.com</a>'
*
*
* # # Custom Replacements of Links
*
* If the configuration options do not provide enough flexibility , a { @ link # replaceFn } may be provided to fully customize
* the output of Autolinker . This function is called once for each URL / Email / Twitter handle match that is encountered .
*
* For example :
*
* var input = "..." ; // string with URLs, Email Addresses, and Twitter Handles
*
* var linkedText = Autolinker . link ( input , {
* replaceFn : function ( autolinker , match ) {
* console . log ( "href = " , match . getAnchorHref ( ) ) ;
* console . log ( "text = " , match . getAnchorText ( ) ) ;
*
* switch ( match . getType ( ) ) {
* case 'url' :
* console . log ( "url: " , match . getUrl ( ) ) ;
*
* if ( match . getUrl ( ) . indexOf ( 'mysite.com' ) === - 1 ) {
* var tag = autolinker . getTagBuilder ( ) . build ( match ) ; // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes
* tag . setAttr ( 'rel' , 'nofollow' ) ;
* tag . addClass ( 'external-link' ) ;
*
* return tag ;
*
* } else {
* return true ; // let Autolinker perform its normal anchor tag replacement
* }
*
* case 'email' :
* var email = match . getEmail ( ) ;
* console . log ( "email: " , email ) ;
*
* if ( email === "my@own.address" ) {
* return false ; // don't auto-link this particular email address; leave as-is
* } else {
* return ; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`)
* }
*
* case 'twitter' :
* var twitterHandle = match . getTwitterHandle ( ) ;
* console . log ( twitterHandle ) ;
*
* return '<a href="http://newplace.to.link.twitter.handles.to/">' + twitterHandle + '</a>' ;
* }
* }
* } ) ;
*
*
* The function may return the following values :
*
* - ` true ` ( Boolean ) : Allow Autolinker to replace the match as it normally would .
* - ` false ` ( Boolean ) : Do not replace the current match at all - leave as - is .
* - Any String : If a string is returned from the function , the string will be used directly as the replacement HTML for
* the match .
* - An { @ link Autolinker . HtmlTag } instance , which can be used to build / modify an HTML tag before writing out its HTML text .
*
* @ constructor
* @ param { Object } [ config ] The configuration options for the Autolinker instance , specified in an Object ( map ) .
* /
var Autolinker = function ( cfg ) {
Autolinker . Util . assign ( this , cfg ) ; // assign the properties of `cfg` onto the Autolinker instance. Prototype properties will be used for missing configs.
this . matchValidator = new Autolinker . MatchValidator ( ) ;
} ;
Autolinker . prototype = {
constructor : Autolinker , // fix constructor property
/ * *
* @ cfg { Boolean } urls
*
* ` true ` if miscellaneous URLs should be automatically linked , ` false ` if they should not be .
* /
urls : true ,
/ * *
* @ cfg { Boolean } email
*
* ` true ` if email addresses should be automatically linked , ` false ` if they should not be .
* /
email : true ,
/ * *
* @ cfg { Boolean } twitter
*
* ` true ` if Twitter handles ( "@example" ) should be automatically linked , ` false ` if they should not be .
* /
twitter : true ,
/ * *
* @ cfg { Boolean } newWindow
*
* ` true ` if the links should open in a new window , ` false ` otherwise .
* /
newWindow : true ,
/ * *
* @ cfg { Boolean } stripPrefix
*
* ` true ` if 'http://' or 'https://' and / or the 'www.' should be stripped from the beginning of URL links ' text ,
* ` false ` otherwise .
* /
stripPrefix : true ,
/ * *
* @ cfg { Number } truncate
*
* A number for how many characters long URLs / emails / twitter handles should be truncated to inside the text of
* a link . If the URL / email / twitter is over this number of characters , it will be truncated to this length by
* adding a two period ellipsis ( '..' ) to the end of the string .
*
* For example : A url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated to 25 characters might look
* something like this : 'yahoo.com/some/long/pat..'
* /
/ * *
* @ cfg { String } className
*
* A CSS class name to add to the generated links . This class will be added to all links , as well as this class
* plus url / email / twitter suffixes for styling url / email / twitter links differently .
*
* For example , if this config is provided as "myLink" , then :
*
* - URL links will have the CSS classes : "myLink myLink-url"
* - Email links will have the CSS classes : "myLink myLink-email" , and
* - Twitter links will have the CSS classes : "myLink myLink-twitter"
* /
className : "" ,
/ * *
* @ cfg { Function } replaceFn
*
* A function to individually process each URL / Email / Twitter match found in the input string .
*
* See the class ' s description for usage .
*
* This function is called with the following parameters :
*
* @ cfg { Autolinker } replaceFn . autolinker The Autolinker instance , which may be used to retrieve child objects from ( such
* as the instance ' s { @ link # getTagBuilder tag builder } ) .
* @ cfg { Autolinker . match . Match } replaceFn . match The Match instance which can be used to retrieve information about the
* { @ link Autolinker . match . Url URL } / { @ link Autolinker . match . Email email } / { @ link Autolinker . match . Twitter Twitter }
* match that the ` replaceFn ` is currently processing .
* /
/ * *
* @ private
* @ property { RegExp } htmlCharacterEntitiesRegex
*
* The regular expression that matches common HTML character entities .
*
* Ignoring & amp ; as it could be part of a query string -- handling it separately .
* /
htmlCharacterEntitiesRegex : /( | |<|<|>|>)/gi ,
/ * *
* @ private
* @ property { RegExp } matcherRegex
*
* The regular expression that matches URLs , email addresses , and Twitter handles .
*
* This regular expression has the following capturing groups :
*
* 1. Group that is used to determine if there is a Twitter handle match ( i . e . \ @ someTwitterUser ) . Simply check for its
* existence to determine if there is a Twitter handle match . The next couple of capturing groups give information
* about the Twitter handle match .
* 2. The whitespace character before the \ @ sign in a Twitter handle . This is needed because there are no lookbehinds in
* JS regular expressions , and can be used to reconstruct the original string in a replace ( ) .
* 3. The Twitter handle itself in a Twitter match . If the match is '@someTwitterUser' , the handle is 'someTwitterUser' .
* 4. Group that matches an email address . Used to determine if the match is an email address , as well as holding the full
* address . Ex : 'me@my.com'
* 5. Group that matches a URL in the input text . Ex : 'http://google.com' , 'www.google.com' , or just 'google.com' .
* This also includes a path , url parameters , or hash anchors . Ex : google . com / path / to / file ? q1 = 1 & q2 = 2 # myAnchor
* 6. Group that matches a protocol URL ( i . e . 'http://google.com' ) . This is used to match protocol URLs with just a single
* word , like 'http://localhost' , where we won 't double check that the domain name has at least one ' . ' in it .
* 7. A protocol - relative ( '//' ) match for the case of a 'www.' prefixed URL . Will be an empty string if it is not a
* protocol - relative match . We need to know the character before the '//' in order to determine if it is a valid match
* or the // was in a string we don't want to auto-link.
* 8. A protocol - relative ( '//' ) match for the case of a known TLD prefixed URL . Will be an empty string if it is not a
* protocol - relative match . See # 6 for more info .
* /
matcherRegex : ( function ( ) {
var twitterRegex = /(^|[^\w])@(\w{1,15})/ , // For matching a twitter handle. Ex: @gregory_jacobs
emailRegex = /(?:[\-;:&=\+\$,\w\.]+@)/ , // something@ for email addresses (a.k.a. local-part)
protocolRegex = /(?:[A-Za-z][-.+A-Za-z0-9]+:(?![A-Za-z][-.+A-Za-z0-9]+:\/\/)(?!\d+\/?)(?:\/\/)?)/ , // match protocol, allow in format "http://" or "mailto:". However, do not match the first part of something like 'link:http://www.google.com' (i.e. don't match "link:"). Also, make sure we don't interpret 'google.com:8000' as if 'google.com' was a protocol here (i.e. ignore a trailing port number in this regex)
wwwRegex = /(?:www\.)/ , // starting with 'www.'
domainNameRegex = /[A-Za-z0-9\.\-]*[A-Za-z0-9\-]/ , // anything looking at all like a domain, non-unicode domains, not ending in a period
tldRegex = /\.(?:international|construction|contractors|enterprises|photography|productions|foundation|immobilien|industries|management|properties|technology|christmas|community|directory|education|equipment|institute|marketing|solutions|vacations|bargains|boutique|builders|catering|cleaning|clothing|computer|democrat|diamonds|graphics|holdings|lighting|partners|plumbing|supplies|training|ventures|academy|careers|company|cruises|domains|exposed|flights|florist|gallery|guitars|holiday|kitchen|neustar|okinawa|recipes|rentals|reviews|shiksha|singles|support|systems|agency|berlin|camera|center|coffee|condos|dating|estate|events|expert|futbol|kaufen|luxury|maison|monash|museum|nagoya|photos|repair|report|social|supply|tattoo|tienda|travel|viajes|villas|vision|voting|voyage|actor|build|cards|cheap|codes|dance|email|glass|house|mango|ninja|parts|photo|shoes|solar|today|tokyo|tools|watch|works|aero|arpa|asia|best|bike|blue|buzz|camp|club|cool|coop|farm|fish|gift|guru|info|jobs|kiwi|kred|land|limo|link|menu|mobi|moda|name|pics|pink|post|qpon|rich|ruhr|sexy|tips|vote|voto|wang|wien|wiki|zone|bar|bid|biz|cab|cat|ceo|com|edu|gov|int|kim|mil|net|onl|org|pro|pub|red|tel|uno|wed|xxx|xyz|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cw|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sx|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)\b/ , // match our known top level domains (TLDs)
// Allow optional path, query string, and hash anchor, not ending in the following characters: "?!:,.;"
// http://blog.codinghorror.com/the-problem-with-urls/
urlSuffixRegex = /[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]?!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|'$*\[\]]/ ;
return new RegExp ( [
'(' , // *** Capturing group $1, which can be used to check for a twitter handle match. Use group $3 for the actual twitter handle though. $2 may be used to reconstruct the original string in a replace()
// *** Capturing group $2, which matches the whitespace character before the '@' sign (needed because of no lookbehinds), and
// *** Capturing group $3, which matches the actual twitter handle
twitterRegex . source ,
')' ,
'|' ,
'(' , // *** Capturing group $4, which is used to determine an email match
emailRegex . source ,
domainNameRegex . source ,
tldRegex . source ,
')' ,
'|' ,
'(' , // *** Capturing group $5, which is used to match a URL
'(?:' , // parens to cover match for protocol (optional), and domain
'(' , // *** Capturing group $6, for a protocol-prefixed url (ex: http://google.com)
protocolRegex . source ,
domainNameRegex . source ,
')' ,
'|' ,
'(?:' , // non-capturing paren for a 'www.' prefixed url (ex: www.google.com)
'(.?//)?' , // *** Capturing group $7 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
wwwRegex . source ,
domainNameRegex . source ,
')' ,
'|' ,
'(?:' , // non-capturing paren for known a TLD url (ex: google.com)
'(.?//)?' , // *** Capturing group $8 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character
domainNameRegex . source ,
tldRegex . source ,
')' ,
')' ,
'(?:' + urlSuffixRegex . source + ')?' , // match for path, query string, and/or hash anchor - optional
')'
] . join ( "" ) , 'gi' ) ;
} ) ( ) ,
/ * *
* @ private
* @ property { RegExp } charBeforeProtocolRelMatchRegex
*
* The regular expression used to retrieve the character before a protocol - relative URL match .
*
* This is used in conjunction with the { @ link # matcherRegex } , which needs to grab the character before a protocol - relative
* '//' due to the lack of a negative look - behind in JavaScript regular expressions . The character before the match is stripped
* from the URL .
* /
charBeforeProtocolRelMatchRegex : /^(.)?\/\// ,
/ * *
* @ private
* @ property { Autolinker . MatchValidator } matchValidator
*
* The MatchValidator object , used to filter out any false positives from the { @ link # matcherRegex } . See
* { @ link Autolinker . MatchValidator } for details .
* /
/ * *
* @ private
* @ property { Autolinker . HtmlParser } htmlParser
*
* The HtmlParser instance used to skip over HTML tags , while finding text nodes to process . This is lazily instantiated
* in the { @ link # getHtmlParser } method .
* /
/ * *
* @ private
* @ property { Autolinker . AnchorTagBuilder } tagBuilder
*
* The AnchorTagBuilder instance used to build the URL / email / Twitter replacement anchor tags . This is lazily instantiated
* in the { @ link # getTagBuilder } method .
* /
/ * *
* Automatically links URLs , email addresses , and Twitter handles found in the given chunk of HTML .
* Does not link URLs found within HTML tags .
*
* For instance , if given the text : ` You should go to http://www.yahoo.com ` , then the result
* will be ` You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a> `
*
* This method finds the text around any HTML elements in the input ` textOrHtml ` , which will be the text that is processed .
* Any original HTML elements will be left as - is , as well as the text that is already wrapped in anchor ( & lt ; a & gt ; ) tags .
*
* @ param { String } textOrHtml The HTML or text to link URLs , email addresses , and Twitter handles within ( depending on if
* the { @ link # urls } , { @ link # email } , and { @ link # twitter } options are enabled ) .
* @ return { String } The HTML , with URLs / emails / Twitter handles automatically linked .
* /
link : function ( textOrHtml ) {
var me = this , // for closure
htmlParser = this . getHtmlParser ( ) ,
htmlCharacterEntitiesRegex = this . htmlCharacterEntitiesRegex ,
anchorTagStackCount = 0 , // used to only process text around anchor tags, and any inner text/html they may have
resultHtml = [ ] ;
htmlParser . parse ( textOrHtml , {
// Process HTML nodes in the input `textOrHtml`
processHtmlNode : function ( tagText , tagName , isClosingTag ) {
if ( tagName === 'a' ) {
if ( ! isClosingTag ) { // it's the start <a> tag
anchorTagStackCount ++ ;
} else { // it's the end </a> tag
anchorTagStackCount = Math . max ( anchorTagStackCount - 1 , 0 ) ; // attempt to handle extraneous </a> tags by making sure the stack count never goes below 0
}
}
resultHtml . push ( tagText ) ; // now add the text of the tag itself verbatim
} ,
// Process text nodes in the input `textOrHtml`
processTextNode : function ( text ) {
if ( anchorTagStackCount === 0 ) {
// If we're not within an <a> tag, process the text node
var unescapedText = Autolinker . Util . splitAndCapture ( text , htmlCharacterEntitiesRegex ) ; // split at HTML entities, but include the HTML entities in the results array
for ( var i = 0 , len = unescapedText . length ; i < len ; i ++ ) {
var textToProcess = unescapedText [ i ] ,
processedTextNode = me . processTextNode ( textToProcess ) ;
resultHtml . push ( processedTextNode ) ;
}
} else {
// `text` is within an <a> tag, simply append the text - we do not want to autolink anything
// already within an <a>...</a> tag
resultHtml . push ( text ) ;
}
}
} ) ;
return resultHtml . join ( "" ) ;
} ,
/ * *
* Lazily instantiates and returns the { @ link # htmlParser } instance for this Autolinker instance .
*
* @ protected
* @ return { Autolinker . HtmlParser }
* /
getHtmlParser : function ( ) {
var htmlParser = this . htmlParser ;
if ( ! htmlParser ) {
htmlParser = this . htmlParser = new Autolinker . HtmlParser ( ) ;
}
return htmlParser ;
} ,
/ * *
* Returns the { @ link # tagBuilder } instance for this Autolinker instance , lazily instantiating it
* if it does not yet exist .
*
* This method may be used in a { @ link # replaceFn } to generate the { @ link Autolinker . HtmlTag HtmlTag } instance that
* Autolinker would normally generate , and then allow for modifications before returning it . For example :
*
* var html = Autolinker . link ( "Test google.com" , {
* replaceFn : function ( autolinker , match ) {
* var tag = autolinker . getTagBuilder ( ) . build ( match ) ; // returns an {@link Autolinker.HtmlTag} instance
* tag . setAttr ( 'rel' , 'nofollow' ) ;
*
* return tag ;
* }
* } ) ;
*
* // generated html:
* // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
*
* @ return { Autolinker . AnchorTagBuilder }
* /
getTagBuilder : function ( ) {
var tagBuilder = this . tagBuilder ;
if ( ! tagBuilder ) {
tagBuilder = this . tagBuilder = new Autolinker . AnchorTagBuilder ( {
newWindow : this . newWindow ,
truncate : this . truncate ,
className : this . className
} ) ;
}
return tagBuilder ;
} ,
/ * *
* Process the text that lies inbetween HTML tags . This method does the actual wrapping of URLs with
* anchor tags .
*
* @ private
* @ param { String } text The text to auto - link .
* @ return { String } The text with anchor tags auto - filled .
* /
processTextNode : function ( text ) {
var me = this ; // for closure
return text . replace ( this . matcherRegex , function ( matchStr , $1 , $2 , $3 , $4 , $5 , $6 , $7 , $8 ) {
var matchDescObj = me . processCandidateMatch ( matchStr , $1 , $2 , $3 , $4 , $5 , $6 , $7 , $8 ) ; // match description object
// Return out with no changes for match types that are disabled (url, email, twitter), or for matches that are
// invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS).
if ( ! matchDescObj ) {
return matchStr ;
} else {
// Generate the replacement text for the match
var matchReturnVal = me . createMatchReturnVal ( matchDescObj . match , matchDescObj . matchStr ) ;
return matchDescObj . prefixStr + matchReturnVal + matchDescObj . suffixStr ;
}
} ) ;
} ,
/ * *
* Processes a candidate match from the { @ link # matcherRegex } .
*
* Not all matches found by the regex are actual URL / email / Twitter matches , as determined by the { @ link # matchValidator } . In
* this case , the method returns ` null ` . Otherwise , a valid Object with ` prefixStr ` , ` match ` , and ` suffixStr ` is returned .
*
* @ private
* @ param { String } matchStr The full match that was found by the { @ link # matcherRegex } .
* @ param { String } twitterMatch The matched text of a Twitter handle , if the match is a Twitter match .
* @ param { String } twitterHandlePrefixWhitespaceChar The whitespace char before the @ sign in a Twitter handle match . This
* is needed because of no lookbehinds in JS regexes , and is need to re - include the character for the anchor tag replacement .
* @ param { String } twitterHandle The actual Twitter user ( i . e the word after the @ sign in a Twitter match ) .
* @ param { String } emailAddressMatch The matched email address for an email address match .
* @ param { String } urlMatch The matched URL string for a URL match .
* @ param { String } protocolUrlMatch The match URL string for a protocol match . Ex : 'http://yahoo.com' . This is used to match
* something like 'http://localhost' , where we won 't double check that the domain name has at least one ' . ' in it .
* @ param { String } wwwProtocolRelativeMatch The '//' for a protocol - relative match from a 'www' url , with the character that
* comes before the '//' .
* @ param { String } tldProtocolRelativeMatch The '//' for a protocol - relative match from a TLD ( top level domain ) match , with
* the character that comes before the '//' .
*
* @ return { Object } A "match description object" . This will be ` null ` if the match was invalid , or if a match type is disabled .
* Otherwise , this will be an Object ( map ) with the following properties :
* @ return { String } return . prefixStr The char ( s ) that should be prepended to the replacement string . These are char ( s ) that
* were needed to be included from the regex match that were ignored by processing code , and should be re - inserted into
* the replacement stream .
* @ return { String } return . suffixStr The char ( s ) that should be appended to the replacement string . These are char ( s ) that
* were needed to be included from the regex match that were ignored by processing code , and should be re - inserted into
* the replacement stream .
* @ return { String } return . matchStr The ` matchStr ` , fixed up to remove characters that are no longer needed ( which have been
* added to ` prefixStr ` and ` suffixStr ` ) .
* @ return { Autolinker . match . Match } return . match The Match object that represents the match that was found .
* /
processCandidateMatch : function (
matchStr , twitterMatch , twitterHandlePrefixWhitespaceChar , twitterHandle ,
emailAddressMatch , urlMatch , protocolUrlMatch , wwwProtocolRelativeMatch , tldProtocolRelativeMatch
) {
var protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch ,
match , // Will be an Autolinker.match.Match object
prefixStr = "" , // A string to use to prefix the anchor tag that is created. This is needed for the Twitter handle match
suffixStr = "" ; // A string to suffix the anchor tag that is created. This is used if there is a trailing parenthesis that should not be auto-linked.
// Return out with `null` for match types that are disabled (url, email, twitter), or for matches that are
// invalid (false positives from the matcherRegex, which can't use look-behinds since they are unavailable in JS).
if (
( twitterMatch && ! this . twitter ) || ( emailAddressMatch && ! this . email ) || ( urlMatch && ! this . urls ) ||
! this . matchValidator . isValidMatch ( urlMatch , protocolUrlMatch , protocolRelativeMatch )
) {
return null ;
}
// Handle a closing parenthesis at the end of the match, and exclude it if there is not a matching open parenthesis
// in the match itself.
if ( this . matchHasUnbalancedClosingParen ( matchStr ) ) {
matchStr = matchStr . substr ( 0 , matchStr . length - 1 ) ; // remove the trailing ")"
suffixStr = ")" ; // this will be added after the generated <a> tag
}
if ( emailAddressMatch ) {
match = new Autolinker . match . Email ( { matchedText : matchStr , email : emailAddressMatch } ) ;
} else if ( twitterMatch ) {
// fix up the `matchStr` if there was a preceding whitespace char, which was needed to determine the match
// itself (since there are no look-behinds in JS regexes)
if ( twitterHandlePrefixWhitespaceChar ) {
prefixStr = twitterHandlePrefixWhitespaceChar ;
matchStr = matchStr . slice ( 1 ) ; // remove the prefixed whitespace char from the match
}
match = new Autolinker . match . Twitter ( { matchedText : matchStr , twitterHandle : twitterHandle } ) ;
} else { // url match
// If it's a protocol-relative '//' match, remove the character before the '//' (which the matcherRegex needed
// to match due to the lack of a negative look-behind in JavaScript regular expressions)
if ( protocolRelativeMatch ) {
var charBeforeMatch = protocolRelativeMatch . match ( this . charBeforeProtocolRelMatchRegex ) [ 1 ] || "" ;
if ( charBeforeMatch ) { // fix up the `matchStr` if there was a preceding char before a protocol-relative match, which was needed to determine the match itself (since there are no look-behinds in JS regexes)
prefixStr = charBeforeMatch ;
matchStr = matchStr . slice ( 1 ) ; // remove the prefixed char from the match
}
}
match = new Autolinker . match . Url ( {
matchedText : matchStr ,
url : matchStr ,
protocolUrlMatch : ! ! protocolUrlMatch ,
protocolRelativeMatch : ! ! protocolRelativeMatch ,
stripPrefix : this . stripPrefix
} ) ;
}
return {
prefixStr : prefixStr ,
suffixStr : suffixStr ,
matchStr : matchStr ,
match : match
} ;
} ,
/ * *
* Determines if a match found has an unmatched closing parenthesis . If so , this parenthesis will be removed
* from the match itself , and appended after the generated anchor tag in { @ link # processTextNode } .
*
* A match may have an extra closing parenthesis at the end of the match because the regular expression must include parenthesis
* for URLs such as "wikipedia.com/something_(disambiguation)" , which should be auto - linked .
*
* However , an extra parenthesis * will * be included when the URL itself is wrapped in parenthesis , such as in the case of
* "(wikipedia.com/something_(disambiguation))" . In this case , the last closing parenthesis should * not * be part of the URL
* itself , and this method will return ` true ` .
*
* @ private
* @ param { String } matchStr The full match string from the { @ link # matcherRegex } .
* @ return { Boolean } ` true ` if there is an unbalanced closing parenthesis at the end of the ` matchStr ` , ` false ` otherwise .
* /
matchHasUnbalancedClosingParen : function ( matchStr ) {
var lastChar = matchStr . charAt ( matchStr . length - 1 ) ;
if ( lastChar === ')' ) {
var openParensMatch = matchStr . match ( /\(/g ) ,
closeParensMatch = matchStr . match ( /\)/g ) ,
numOpenParens = ( openParensMatch && openParensMatch . length ) || 0 ,
numCloseParens = ( closeParensMatch && closeParensMatch . length ) || 0 ;
if ( numOpenParens < numCloseParens ) {
return true ;
}
}
return false ;
} ,
/ * *
* Creates the return string value for a given match in the input string , for the { @ link # processTextNode } method .
*
* This method handles the { @ link # replaceFn } , if one was provided .
*
* @ private
* @ param { Autolinker . match . Match } match The Match object that represents the match .
* @ param { String } matchStr The original match string , after having been preprocessed to fix match edge cases ( see
* the ` prefixStr ` and ` suffixStr ` vars in { @ link # processTextNode } .
* @ return { String } The string that the ` match ` should be replaced with . This is usually the anchor tag string , but
* may be the ` matchStr ` itself if the match is not to be replaced .
* /
createMatchReturnVal : function ( match , matchStr ) {
// Handle a custom `replaceFn` being provided
var replaceFnResult ;
if ( this . replaceFn ) {
replaceFnResult = this . replaceFn . call ( this , this , match ) ; // Autolinker instance is the context, and the first arg
}
if ( typeof replaceFnResult === 'string' ) {
return replaceFnResult ; // `replaceFn` returned a string, use that
} else if ( replaceFnResult === false ) {
return matchStr ; // no replacement for the match
} else if ( replaceFnResult instanceof Autolinker . HtmlTag ) {
return replaceFnResult . toString ( ) ;
} else { // replaceFnResult === true, or no/unknown return value from function
// Perform Autolinker's default anchor tag generation
var tagBuilder = this . getTagBuilder ( ) ,
anchorTag = tagBuilder . build ( match ) ; // returns an Autolinker.HtmlTag instance
return anchorTag . toString ( ) ;
}
}
} ;
/ * *
* Automatically links URLs , email addresses , and Twitter handles found in the given chunk of HTML .
* Does not link URLs found within HTML tags .
*
* For instance , if given the text : ` You should go to http://www.yahoo.com ` , then the result
* will be ` You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a> `
*
* Example :
*
* var linkedText = Autolinker . link ( "Go to google.com" , { newWindow : false } ) ;
* // Produces: "Go to <a href="http://google.com">google.com</a>"
*
* @ static
* @ param { String } textOrHtml The HTML or text to find URLs , email addresses , and Twitter handles within ( depending on if
* the { @ link # urls } , { @ link # email } , and { @ link # twitter } options are enabled ) .
* @ param { Object } [ options ] Any of the configuration options for the Autolinker class , specified in an Object ( map ) .
* See the class description for an example call .
* @ return { String } The HTML text , with URLs automatically linked
* /
Autolinker . link = function ( textOrHtml , options ) {
var autolinker = new Autolinker ( options ) ;
return autolinker . link ( textOrHtml ) ;
} ;
// Namespace for `match` classes
Autolinker . match = { } ;
/*global Autolinker */
/*jshint eqnull:true, boss:true */
/ * *
* @ class Autolinker . Util
* @ singleton
*
* A few utility methods for Autolinker .
* /
Autolinker . Util = {
/ * *
* @ property { Function } abstractMethod
*
* A function object which represents an abstract method .
* /
abstractMethod : function ( ) { throw "abstract" ; } ,
/ * *
* Assigns ( shallow copies ) the properties of ` src ` onto ` dest ` .
*
* @ param { Object } dest The destination object .
* @ param { Object } src The source object .
* @ return { Object } The destination object ( ` dest ` )
* /
assign : function ( dest , src ) {
for ( var prop in src ) {
if ( src . hasOwnProperty ( prop ) ) {
dest [ prop ] = src [ prop ] ;
}
}
return dest ;
} ,
/ * *
* Extends ` superclass ` to create a new subclass , adding the ` protoProps ` to the new subclass ' s prototype .
*
* @ param { Function } superclass The constructor function for the superclass .
* @ param { Object } protoProps The methods / properties to add to the subclass ' s prototype . This may contain the
* special property ` constructor ` , which will be used as the new subclass ' s constructor function .
* @ return { Function } The new subclass function .
* /
extend : function ( superclass , protoProps ) {
var superclassProto = superclass . prototype ;
var F = function ( ) { } ;
F . prototype = superclassProto ;
var subclass ;
if ( protoProps . hasOwnProperty ( 'constructor' ) ) {
subclass = protoProps . constructor ;
} else {
subclass = function ( ) { superclassProto . constructor . apply ( this , arguments ) ; } ;
}
var subclassProto = subclass . prototype = new F ( ) ; // set up prototype chain
subclassProto . constructor = subclass ; // fix constructor property
subclassProto . superclass = superclassProto ;
delete protoProps . constructor ; // don't re-assign constructor property to the prototype, since a new function may have been created (`subclass`), which is now already there
Autolinker . Util . assign ( subclassProto , protoProps ) ;
return subclass ;
} ,
/ * *
* Truncates the ` str ` at ` len - ellipsisChars.length ` , and adds the ` ellipsisChars ` to the
* end of the string ( by default , two periods : '..' ) . If the ` str ` length does not exceed
* ` len ` , the string will be returned unchanged .
*
* @ param { String } str The string to truncate and add an ellipsis to .
* @ param { Number } truncateLen The length to truncate the string at .
* @ param { String } [ ellipsisChars = . . ] The ellipsis character ( s ) to add to the end of ` str `
* when truncated . Defaults to '..'
* /
ellipsis : function ( str , truncateLen , ellipsisChars ) {
if ( str . length > truncateLen ) {
ellipsisChars = ( ellipsisChars == null ) ? '..' : ellipsisChars ;
str = str . substring ( 0 , truncateLen - ellipsisChars . length ) + ellipsisChars ;
}
return str ;
} ,
/ * *
* Supports ` Array.prototype.indexOf() ` functionality for old IE ( IE8 and below ) .
*
* @ param { Array } arr The array to find an element of .
* @ param { * } element The element to find in the array , and return the index of .
* @ return { Number } The index of the ` element ` , or - 1 if it was not found .
* /
indexOf : function ( arr , element ) {
if ( Array . prototype . indexOf ) {
return arr . indexOf ( element ) ;
} else {
for ( var i = 0 , len = arr . length ; i < len ; i ++ ) {
if ( arr [ i ] === element ) return i ;
}
return - 1 ;
}
} ,
/ * *
* Performs the functionality of what modern browsers do when ` String.prototype.split() ` is called
* with a regular expression that contains capturing parenthesis .
*
* For example :
*
* // Modern browsers:
* "a,b,c" . split ( /(,)/ ) ; // --> [ 'a', ',', 'b', ',', 'c' ]
*
* // Old IE (including IE8):
* "a,b,c" . split ( /(,)/ ) ; // --> [ 'a', 'b', 'c' ]
*
* This method emulates the functionality of modern browsers for the old IE case .
*
* @ param { String } str The string to split .
* @ param { RegExp } splitRegex The regular expression to split the input ` str ` on . The splitting
* character ( s ) will be spliced into the array , as in the "modern browsers" example in the
* description of this method .
* Note # 1 : the supplied regular expression * * must * * have the 'g' flag specified .
* Note # 2 : for simplicity ' s sake , the regular expression does not need
* to contain capturing parenthesis - it will be assumed that any match has them .
* @ return { String [ ] } The split array of strings , with the splitting character ( s ) included .
* /
splitAndCapture : function ( str , splitRegex ) {
if ( ! splitRegex . global ) throw new Error ( "`splitRegex` must have the 'g' flag set" ) ;
var result = [ ] ,
lastIdx = 0 ,
match ;
while ( match = splitRegex . exec ( str ) ) {
result . push ( str . substring ( lastIdx , match . index ) ) ;
result . push ( match [ 0 ] ) ; // push the splitting char(s)
lastIdx = match . index + match [ 0 ] . length ;
}
result . push ( str . substring ( lastIdx ) ) ;
return result ;
}
} ;
/*global Autolinker */
/ * *
* @ private
* @ class Autolinker . HtmlParser
* @ extends Object
*
* An HTML parser implementation which simply walks an HTML string and calls the provided visitor functions to process
* HTML and text nodes .
*
* Autolinker uses this to only link URLs / emails / Twitter handles within text nodes , basically ignoring HTML tags .
* /
Autolinker . HtmlParser = Autolinker . Util . extend ( Object , {
/ * *
* @ private
* @ property { RegExp } htmlRegex
*
* The regular expression used to pull out HTML tags from a string . Handles namespaced HTML tags and
* attribute names , as specified by http : //www.w3.org/TR/html-markup/syntax.html.
*
* Capturing groups :
*
* 1. The "!DOCTYPE" tag name , if a tag is a & lt ; ! DOCTYPE & gt ; tag .
* 2. If it is an end tag , this group will have the '/' .
* 3. The tag name for all tags ( other than the & lt ; ! DOCTYPE & gt ; tag )
* /
htmlRegex : ( function ( ) {
var tagNameRegex = /[0-9a-zA-Z][0-9a-zA-Z:]*/ ,
attrNameRegex = /[^\s\0"'>\/=\x01-\x1F\x7F]+/ , // the unicode range accounts for excluding control chars, and the delete char
attrValueRegex = /(?:".*?"|'.*?'|[^'"=<>`\s]+)/ , // double quoted, single quoted, or unquoted attribute values
nameEqualsValueRegex = attrNameRegex . source + '(?:\\s*=\\s*' + attrValueRegex . source + ')?' ; // optional '=[value]'
return new RegExp ( [
// for <!DOCTYPE> tag. Ex: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
'(?:' ,
'<(!DOCTYPE)' , // *** Capturing Group 1 - If it's a doctype tag
// Zero or more attributes following the tag name
'(?:' ,
'\\s+' , // one or more whitespace chars before an attribute
// Either:
// A. attr="value", or
// B. "value" alone (To cover example doctype tag: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">)
'(?:' , nameEqualsValueRegex , '|' , attrValueRegex . source + ')' ,
')*' ,
'>' ,
')' ,
'|' ,
// All other HTML tags (i.e. tags that are not <!DOCTYPE>)
'(?:' ,
'<(/)?' , // Beginning of a tag. Either '<' for a start tag, or '</' for an end tag.
// *** Capturing Group 2: The slash or an empty string. Slash ('/') for end tag, empty string for start or self-closing tag.
// *** Capturing Group 3 - The tag name
'(' + tagNameRegex . source + ')' ,
// Zero or more attributes following the tag name
'(?:' ,
'\\s+' , // one or more whitespace chars before an attribute
nameEqualsValueRegex , // attr="value" (with optional ="value" part)
')*' ,
'\\s*/?' , // any trailing spaces and optional '/' before the closing '>'
'>' ,
')'
] . join ( "" ) , 'gi' ) ;
} ) ( ) ,
/ * *
* Walks an HTML string , calling the ` options.processHtmlNode ` function for each HTML tag that is encountered , and calling
* the ` options.processTextNode ` function when each text around HTML tags is encountered .
*
* @ param { String } html The HTML to parse .
* @ param { Object } [ options ] An Object ( map ) which may contain the following properties :
*
* @ param { Function } [ options . processHtmlNode ] A visitor function which allows processing of an encountered HTML node .
* This function is called with the following arguments :
* @ param { String } [ options . processHtmlNode . tagText ] The HTML tag text that was found .
* @ param { String } [ options . processHtmlNode . tagName ] The tag name for the HTML tag that was found . Ex : 'a' for an anchor tag .
* @ param { String } [ options . processHtmlNode . isClosingTag ] ` true ` if the tag is a closing tag ( ex : & lt ; / a & g t ; ) , ` f a l s e ` o t h e r w i s e .
*
* @ param { Function } [ options . processTextNode ] A visitor function which allows processing of an encountered text node .
* This function is called with the following arguments :
* @ param { String } [ options . processTextNode . text ] The text node that was matched .
* /
parse : function ( html , options ) {
options = options || { } ;
var processHtmlNodeVisitor = options . processHtmlNode || function ( ) { } ,
processTextNodeVisitor = options . processTextNode || function ( ) { } ,
htmlRegex = this . htmlRegex ,
currentResult ,
lastIndex = 0 ;
// Loop over the HTML string, ignoring HTML tags, and processing the text that lies between them,
// wrapping the URLs in anchor tags
while ( ( currentResult = htmlRegex . exec ( html ) ) !== null ) {
var tagText = currentResult [ 0 ] ,
tagName = currentResult [ 1 ] || currentResult [ 3 ] , // The <!DOCTYPE> tag (ex: "!DOCTYPE"), or another tag (ex: "a")
isClosingTag = ! ! currentResult [ 2 ] ,
inBetweenTagsText = html . substring ( lastIndex , currentResult . index ) ;
if ( inBetweenTagsText ) {
processTextNodeVisitor ( inBetweenTagsText ) ;
}
processHtmlNodeVisitor ( tagText , tagName . toLowerCase ( ) , isClosingTag ) ;
lastIndex = currentResult . index + tagText . length ;
}
// Process any remaining text after the last HTML element. Will process all of the text if there were no HTML elements.
if ( lastIndex < html . length ) {
var text = html . substring ( lastIndex ) ;
if ( text ) {
processTextNodeVisitor ( text ) ;
}
}
}
} ) ;
/*global Autolinker */
/*jshint boss:true */
/ * *
* @ class Autolinker . HtmlTag
* @ extends Object
*
* Represents an HTML tag , which can be used to easily build / modify HTML tags programmatically .
*
* Autolinker uses this abstraction to create HTML tags , and then write them out as strings . You may also use
* this class in your code , especially within a { @ link Autolinker # replaceFn replaceFn } .
*
* # # Examples
*
* Example instantiation :
*
* var tag = new Autolinker . HtmlTag ( {
* tagName : 'a' ,
* attrs : { 'href' : 'http://google.com' , 'class' : 'external-link' } ,
* innerHtml : 'Google'
* } ) ;
*
* tag . toString ( ) ; // <a href="http://google.com" class="external-link">Google</a>
*
* // Individual accessor methods
* tag . getTagName ( ) ; // 'a'
* tag . getAttr ( 'href' ) ; // 'http://google.com'
* tag . hasClass ( 'external-link' ) ; // true
*
*
* Using mutator methods ( which may be used in combination with instantiation config properties ) :
*
* var tag = new Autolinker . HtmlTag ( ) ;
* tag . setTagName ( 'a' ) ;
* tag . setAttr ( 'href' , 'http://google.com' ) ;
* tag . addClass ( 'external-link' ) ;
* tag . setInnerHtml ( 'Google' ) ;
*
* tag . getTagName ( ) ; // 'a'
* tag . getAttr ( 'href' ) ; // 'http://google.com'
* tag . hasClass ( 'external-link' ) ; // true
*
* tag . toString ( ) ; // <a href="http://google.com" class="external-link">Google</a>
*
*
* # # Example use within a { @ link Autolinker # replaceFn replaceFn }
*
* var html = Autolinker . link ( "Test google.com" , {
* replaceFn : function ( autolinker , match ) {
* var tag = autolinker . getTagBuilder ( ) . build ( match ) ; // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text
* tag . setAttr ( 'rel' , 'nofollow' ) ;
*
* return tag ;
* }
* } ) ;
*
* // generated html:
* // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
*
*
* # # Example use with a new tag for the replacement
*
* var html = Autolinker . link ( "Test google.com" , {
* replaceFn : function ( autolinker , match ) {
* var tag = new Autolinker . HtmlTag ( {
* tagName : 'button' ,
* attrs : { 'title' : 'Load URL: ' + match . getAnchorHref ( ) } ,
* innerHtml : 'Load URL: ' + match . getAnchorText ( )
* } ) ;
*
* return tag ;
* }
* } ) ;
*
* // generated html:
* // Test <button title="Load URL: http://google.com">Load URL: google.com</button>
* /
Autolinker . HtmlTag = Autolinker . Util . extend ( Object , {
/ * *
* @ cfg { String } tagName
*
* The tag name . Ex : 'a' , 'button' , etc .
*
* Not required at instantiation time , but should be set using { @ link # setTagName } before { @ link # toString }
* is executed .
* /
/ * *
* @ cfg { Object . < String , String > } attrs
*
* An key / value Object ( map ) of attributes to create the tag with . The keys are the attribute names , and the
* values are the attribute values .
* /
/ * *
* @ cfg { String } innerHtml
*
* The inner HTML for the tag .
*
* Note the camel case name on ` innerHtml ` . Acronyms are camelCased in this utility ( such as not to run into the acronym
* naming inconsistency that the DOM developers created with ` XMLHttpRequest ` ) . You may alternatively use { @ link # innerHTML }
* if you prefer , but this one is recommended .
* /
/ * *
* @ cfg { String } innerHTML
*
* Alias of { @ link # innerHtml } , accepted for consistency with the browser DOM api , but prefer the camelCased version
* for acronym names .
* /
/ * *
* @ protected
* @ property { RegExp } whitespaceRegex
*
* Regular expression used to match whitespace in a string of CSS classes .
* /
whitespaceRegex : /\s+/ ,
/ * *
* @ constructor
* @ param { Object } [ cfg ] The configuration properties for this class , in an Object ( map )
* /
constructor : function ( cfg ) {
Autolinker . Util . assign ( this , cfg ) ;
this . innerHtml = this . innerHtml || this . innerHTML ; // accept either the camelCased form or the fully capitalized acronym
} ,
/ * *
* Sets the tag name that will be used to generate the tag with .
*
* @ param { String } tagName
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
setTagName : function ( tagName ) {
this . tagName = tagName ;
return this ;
} ,
/ * *
* Retrieves the tag name .
*
* @ return { String }
* /
getTagName : function ( ) {
return this . tagName || "" ;
} ,
/ * *
* Sets an attribute on the HtmlTag .
*
* @ param { String } attrName The attribute name to set .
* @ param { String } attrValue The attribute value to set .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
setAttr : function ( attrName , attrValue ) {
var tagAttrs = this . getAttrs ( ) ;
tagAttrs [ attrName ] = attrValue ;
return this ;
} ,
/ * *
* Retrieves an attribute from the HtmlTag . If the attribute does not exist , returns ` undefined ` .
*
* @ param { String } name The attribute name to retrieve .
* @ return { String } The attribute ' s value , or ` undefined ` if it does not exist on the HtmlTag .
* /
getAttr : function ( attrName ) {
return this . getAttrs ( ) [ attrName ] ;
} ,
/ * *
* Sets one or more attributes on the HtmlTag .
*
* @ param { Object . < String , String > } attrs A key / value Object ( map ) of the attributes to set .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
setAttrs : function ( attrs ) {
var tagAttrs = this . getAttrs ( ) ;
Autolinker . Util . assign ( tagAttrs , attrs ) ;
return this ;
} ,
/ * *
* Retrieves the attributes Object ( map ) for the HtmlTag .
*
* @ return { Object . < String , String > } A key / value object of the attributes for the HtmlTag .
* /
getAttrs : function ( ) {
return this . attrs || ( this . attrs = { } ) ;
} ,
/ * *
* Sets the provided ` cssClass ` , overwriting any current CSS classes on the HtmlTag .
*
* @ param { String } cssClass One or more space - separated CSS classes to set ( overwrite ) .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
setClass : function ( cssClass ) {
return this . setAttr ( 'class' , cssClass ) ;
} ,
/ * *
* Convenience method to add one or more CSS classes to the HtmlTag . Will not add duplicate CSS classes .
*
* @ param { String } cssClass One or more space - separated CSS classes to add .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
addClass : function ( cssClass ) {
var classAttr = this . getClass ( ) ,
whitespaceRegex = this . whitespaceRegex ,
indexOf = Autolinker . Util . indexOf , // to support IE8 and below
classes = ( ! classAttr ) ? [ ] : classAttr . split ( whitespaceRegex ) ,
newClasses = cssClass . split ( whitespaceRegex ) ,
newClass ;
while ( newClass = newClasses . shift ( ) ) {
if ( indexOf ( classes , newClass ) === - 1 ) {
classes . push ( newClass ) ;
}
}
this . getAttrs ( ) [ 'class' ] = classes . join ( " " ) ;
return this ;
} ,
/ * *
* Convenience method to remove one or more CSS classes from the HtmlTag .
*
* @ param { String } cssClass One or more space - separated CSS classes to remove .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
removeClass : function ( cssClass ) {
var classAttr = this . getClass ( ) ,
whitespaceRegex = this . whitespaceRegex ,
indexOf = Autolinker . Util . indexOf , // to support IE8 and below
classes = ( ! classAttr ) ? [ ] : classAttr . split ( whitespaceRegex ) ,
removeClasses = cssClass . split ( whitespaceRegex ) ,
removeClass ;
while ( classes . length && ( removeClass = removeClasses . shift ( ) ) ) {
var idx = indexOf ( classes , removeClass ) ;
if ( idx !== - 1 ) {
classes . splice ( idx , 1 ) ;
}
}
this . getAttrs ( ) [ 'class' ] = classes . join ( " " ) ;
return this ;
} ,
/ * *
* Convenience method to retrieve the CSS class ( es ) for the HtmlTag , which will each be separated by spaces when
* there are multiple .
*
* @ return { String }
* /
getClass : function ( ) {
return this . getAttrs ( ) [ 'class' ] || "" ;
} ,
/ * *
* Convenience method to check if the tag has a CSS class or not .
*
* @ param { String } cssClass The CSS class to check for .
* @ return { Boolean } ` true ` if the HtmlTag has the CSS class , ` false ` otherwise .
* /
hasClass : function ( cssClass ) {
return ( ' ' + this . getClass ( ) + ' ' ) . indexOf ( ' ' + cssClass + ' ' ) !== - 1 ;
} ,
/ * *
* Sets the inner HTML for the tag .
*
* @ param { String } html The inner HTML to set .
* @ return { Autolinker . HtmlTag } This HtmlTag instance , so that method calls may be chained .
* /
setInnerHtml : function ( html ) {
this . innerHtml = html ;
return this ;
} ,
/ * *
* Retrieves the inner HTML for the tag .
*
* @ return { String }
* /
getInnerHtml : function ( ) {
return this . innerHtml || "" ;
} ,
/ * *
* Override of superclass method used to generate the HTML string for the tag .
*
* @ return { String }
* /
toString : function ( ) {
var tagName = this . getTagName ( ) ,
attrsStr = this . buildAttrsStr ( ) ;
attrsStr = ( attrsStr ) ? ' ' + attrsStr : '' ; // prepend a space if there are actually attributes
return [ '<' , tagName , attrsStr , '>' , this . getInnerHtml ( ) , '</' , tagName , '>' ] . join ( "" ) ;
} ,
/ * *
* Support method for { @ link # toString } , returns the string space - separated key = "value" pairs , used to populate
* the stringified HtmlTag .
*
* @ protected
* @ return { String } Example return : ` attr1="value1" attr2="value2" `
* /
buildAttrsStr : function ( ) {
if ( ! this . attrs ) return "" ; // no `attrs` Object (map) has been set, return empty string
var attrs = this . getAttrs ( ) ,
attrsArr = [ ] ;
for ( var prop in attrs ) {
if ( attrs . hasOwnProperty ( prop ) ) {
attrsArr . push ( prop + '="' + attrs [ prop ] + '"' ) ;
}
}
return attrsArr . join ( " " ) ;
}
} ) ;
/*global Autolinker */
/*jshint scripturl:true */
/ * *
* @ private
* @ class Autolinker . MatchValidator
* @ extends Object
*
* Used by Autolinker to filter out false positives from the { @ link Autolinker # matcherRegex } .
*
* Due to the limitations of regular expressions ( including the missing feature of look - behinds in JS regular expressions ) ,
* we cannot always determine the validity of a given match . This class applies a bit of additional logic to filter out any
* false positives that have been matched by the { @ link Autolinker # matcherRegex } .
* /
Autolinker . MatchValidator = Autolinker . Util . extend ( Object , {
/ * *
* @ private
* @ property { RegExp } invalidProtocolRelMatchRegex
*
* The regular expression used to check a potential protocol - relative URL match , coming from the
* { @ link Autolinker # matcherRegex } . A protocol - relative URL is , for example , "//yahoo.com"
*
* This regular expression checks to see if there is a word character before the '//' match in order to determine if
* we should actually autolink a protocol - relative URL . This is needed because there is no negative look - behind in
* JavaScript regular expressions .
*
* For instance , we want to autolink something like "Go to: //google.com" , but we don ' t want to autolink something
* like "abc//google.com"
* /
invalidProtocolRelMatchRegex : /^[\w]\/\// ,
/ * *
* Regex to test for a full protocol , with the two trailing slashes . Ex : 'http://'
*
* @ private
* @ property { RegExp } hasFullProtocolRegex
* /
hasFullProtocolRegex : /^[A-Za-z][-.+A-Za-z0-9]+:\/\// ,
/ * *
* Regex to find the URI scheme , such as 'mailto:' .
*
* This is used to filter out 'javascript:' and 'vbscript:' schemes .
*
* @ private
* @ property { RegExp } uriSchemeRegex
* /
uriSchemeRegex : /^[A-Za-z][-.+A-Za-z0-9]+:/ ,
/ * *
* Regex to determine if at least one word char exists after the protocol ( i . e . after the ':' )
*
* @ private
* @ property { RegExp } hasWordCharAfterProtocolRegex
* /
hasWordCharAfterProtocolRegex : /:[^\s]*?[A-Za-z]/ ,
/ * *
* Determines if a given match found by { @ link Autolinker # processTextNode } is valid . Will return ` false ` for :
*
* 1 ) URL matches which do not have at least have one period ( '.' ) in the domain name ( effectively skipping over
* matches like "abc:def" ) . However , URL matches with a protocol will be allowed ( ex : 'http://localhost' )
* 2 ) URL matches which do not have at least one word character in the domain name ( effectively skipping over
* matches like "git:1.0" ) .
* 3 ) A protocol - relative url match ( a URL beginning with '//' ) whose previous character is a word character
* ( effectively skipping over strings like "abc//google.com" )
*
* Otherwise , returns ` true ` .
*
* @ param { String } urlMatch The matched URL , if there was one . Will be an empty string if the match is not a URL match .
* @ param { String } protocolUrlMatch The match URL string for a protocol match . Ex : 'http://yahoo.com' . This is used to match
* something like 'http://localhost' , where we won 't double check that the domain name has at least one ' . ' in it .
* @ param { String } protocolRelativeMatch The protocol - relative string for a URL match ( i . e . '//' ) , possibly with a preceding
* character ( ex , a space , such as : ' //' , or a letter , such as : 'a//' ) . The match is invalid if there is a word character
* preceding the '//' .
* @ return { Boolean } ` true ` if the match given is valid and should be processed , or ` false ` if the match is invalid and / or
* should just not be processed .
* /
isValidMatch : function ( urlMatch , protocolUrlMatch , protocolRelativeMatch ) {
if (
( protocolUrlMatch && ! this . isValidUriScheme ( protocolUrlMatch ) ) ||
this . urlMatchDoesNotHaveProtocolOrDot ( urlMatch , protocolUrlMatch ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL, *unless* it was a full protocol match (like 'http://localhost')
this . urlMatchDoesNotHaveAtLeastOneWordChar ( urlMatch , protocolUrlMatch ) || // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0"
this . isInvalidProtocolRelativeMatch ( protocolRelativeMatch ) // A protocol-relative match which has a word character in front of it (so we can skip something like "abc//google.com")
) {
return false ;
}
return true ;
} ,
/ * *
* Determines if the URI scheme is a valid scheme to be autolinked . Returns ` false ` if the scheme is
* 'javascript:' or 'vbscript:'
*
* @ private
* @ param { String } uriSchemeMatch The match URL string for a full URI scheme match . Ex : 'http://yahoo.com'
* or 'mailto:a@a.com' .
* @ return { Boolean } ` true ` if the scheme is a valid one , ` false ` otherwise .
* /
isValidUriScheme : function ( uriSchemeMatch ) {
var uriScheme = uriSchemeMatch . match ( this . uriSchemeRegex ) [ 0 ] ;
return ( uriScheme !== 'javascript:' && uriScheme !== 'vbscript:' ) ;
} ,
/ * *
* Determines if a URL match does not have either :
*
* a ) a full protocol ( i . e . 'http://' ) , or
* b ) at least one dot ( '.' ) in the domain name ( for a non - full - protocol match ) .
*
* Either situation is considered an invalid URL ( ex : 'git:d' does not have either the '://' part , or at least one dot
* in the domain name . If the match was 'git:abc.com' , we would consider this valid . )
*
* @ private
* @ param { String } urlMatch The matched URL , if there was one . Will be an empty string if the match is not a URL match .
* @ param { String } protocolUrlMatch The match URL string for a protocol match . Ex : 'http://yahoo.com' . This is used to match
* something like 'http://localhost' , where we won 't double check that the domain name has at least one ' . ' in it .
* @ return { Boolean } ` true ` if the URL match does not have a full protocol , or at least one dot ( '.' ) in a non - full - protocol
* match .
* /
urlMatchDoesNotHaveProtocolOrDot : function ( urlMatch , protocolUrlMatch ) {
return ( ! ! urlMatch && ( ! protocolUrlMatch || ! this . hasFullProtocolRegex . test ( protocolUrlMatch ) ) && urlMatch . indexOf ( '.' ) === - 1 ) ;
} ,
/ * *
* Determines if a URL match does not have at least one word character after the protocol ( i . e . in the domain name ) .
*
* At least one letter character must exist in the domain name after a protocol match . Ex : skip over something
* like "git:1.0"
*
* @ private
* @ param { String } urlMatch The matched URL , if there was one . Will be an empty string if the match is not a URL match .
* @ param { String } protocolUrlMatch The match URL string for a protocol match . Ex : 'http://yahoo.com' . This is used to
* know whether or not we have a protocol in the URL string , in order to check for a word character after the protocol
* separator ( ':' ) .
* @ return { Boolean } ` true ` if the URL match does not have at least one word character in it after the protocol , ` false `
* otherwise .
* /
urlMatchDoesNotHaveAtLeastOneWordChar : function ( urlMatch , protocolUrlMatch ) {
if ( urlMatch && protocolUrlMatch ) {
return ! this . hasWordCharAfterProtocolRegex . test ( urlMatch ) ;
} else {
return false ;
}
} ,
/ * *
* Determines if a protocol - relative match is an invalid one . This method returns ` true ` if there is a ` protocolRelativeMatch ` ,
* and that match contains a word character before the '//' ( i . e . it must contain whitespace or nothing before the '//' in
* order to be considered valid ) .
*
* @ private
* @ param { String } protocolRelativeMatch The protocol - relative string for a URL match ( i . e . '//' ) , possibly with a preceding
* character ( ex , a space , such as : ' //' , or a letter , such as : 'a//' ) . The match is invalid if there is a word character
* preceding the '//' .
* @ return { Boolean } ` true ` if it is an invalid protocol - relative match , ` false ` otherwise .
* /
isInvalidProtocolRelativeMatch : function ( protocolRelativeMatch ) {
return ( ! ! protocolRelativeMatch && this . invalidProtocolRelMatchRegex . test ( protocolRelativeMatch ) ) ;
}
} ) ;
/*global Autolinker */
/*jshint sub:true */
/ * *
* @ protected
* @ class Autolinker . AnchorTagBuilder
* @ extends Object
*
* Builds anchor ( & lt ; a & gt ; ) tags for the Autolinker utility when a match is found .
*
* Normally this class is instantiated , configured , and used internally by an { @ link Autolinker } instance , but may
* actually be retrieved in a { @ link Autolinker # replaceFn replaceFn } to create { @ link Autolinker . HtmlTag HtmlTag } instances
* which may be modified before returning from the { @ link Autolinker # replaceFn replaceFn } . For example :
*
* var html = Autolinker . link ( "Test google.com" , {
* replaceFn : function ( autolinker , match ) {
* var tag = autolinker . getTagBuilder ( ) . build ( match ) ; // returns an {@link Autolinker.HtmlTag} instance
* tag . setAttr ( 'rel' , 'nofollow' ) ;
*
* return tag ;
* }
* } ) ;
*
* // generated html:
* // Test <a href="http://google.com" target="_blank" rel="nofollow">google.com</a>
* /
Autolinker . AnchorTagBuilder = Autolinker . Util . extend ( Object , {
/ * *
* @ cfg { Boolean } newWindow
* @ inheritdoc Autolinker # newWindow
* /
/ * *
* @ cfg { Number } truncate
* @ inheritdoc Autolinker # truncate
* /
/ * *
* @ cfg { String } className
* @ inheritdoc Autolinker # className
* /
/ * *
* @ constructor
* @ param { Object } [ cfg ] The configuration options for the AnchorTagBuilder instance , specified in an Object ( map ) .
* /
constructor : function ( cfg ) {
Autolinker . Util . assign ( this , cfg ) ;
} ,
/ * *
* Generates the actual anchor ( & lt ; a & gt ; ) tag to use in place of the matched URL / email / Twitter text ,
* via its ` match ` object .
*
* @ param { Autolinker . match . Match } match The Match instance to generate an anchor tag from .
* @ return { Autolinker . HtmlTag } The HtmlTag instance for the anchor tag .
* /
build : function ( match ) {
var tag = new Autolinker . HtmlTag ( {
tagName : 'a' ,
attrs : this . createAttrs ( match . getType ( ) , match . getAnchorHref ( ) ) ,
innerHtml : this . processAnchorText ( match . getAnchorText ( ) )
} ) ;
return tag ;
} ,
/ * *
* Creates the Object ( map ) of the HTML attributes for the anchor ( & lt ; a & gt ; ) tag being generated .
*
* @ protected
* @ param { "url" / "email" / "twitter" } matchType The type of match that an anchor tag is being generated for .
* @ param { String } href The href for the anchor tag .
* @ return { Object } A key / value Object ( map ) of the anchor tag ' s attributes .
* /
createAttrs : function ( matchType , anchorHref ) {
var attrs = {
'href' : anchorHref // we'll always have the `href` attribute
} ;
var cssClass = this . createCssClass ( matchType ) ;
if ( cssClass ) {
attrs [ 'class' ] = cssClass ;
}
if ( this . newWindow ) {
attrs [ 'target' ] = "_blank" ;
}
return attrs ;
} ,
/ * *
* Creates the CSS class that will be used for a given anchor tag , based on the ` matchType ` and the { @ link # className }
* config .
*
* @ private
* @ param { "url" / "email" / "twitter" } matchType The type of match that an anchor tag is being generated for .
* @ return { String } The CSS class string for the link . Example return : "myLink myLink-url" . If no { @ link # className }
* was configured , returns an empty string .
* /
createCssClass : function ( matchType ) {
var className = this . className ;
if ( ! className )
return "" ;
else
return className + " " + className + "-" + matchType ; // ex: "myLink myLink-url", "myLink myLink-email", or "myLink myLink-twitter"
} ,
/ * *
* Processes the ` anchorText ` by truncating the text according to the { @ link # truncate } config .
*
* @ private
* @ param { String } anchorText The anchor tag ' s text ( i . e . what will be displayed ) .
* @ return { String } The processed ` anchorText ` .
* /
processAnchorText : function ( anchorText ) {
anchorText = this . doTruncate ( anchorText ) ;
return anchorText ;
} ,
/ * *
* Performs the truncation of the ` anchorText ` , if the ` anchorText ` is longer than the { @ link # truncate } option .
* Truncates the text to 2 characters fewer than the { @ link # truncate } option , and adds ".." to the end .
*
* @ private
* @ param { String } text The anchor tag ' s text ( i . e . what will be displayed ) .
* @ return { String } The truncated anchor text .
* /
doTruncate : function ( anchorText ) {
return Autolinker . Util . ellipsis ( anchorText , this . truncate || Number . POSITIVE _INFINITY ) ;
}
} ) ;
/*global Autolinker */
/ * *
* @ abstract
* @ class Autolinker . match . Match
*
* Represents a match found in an input string which should be Autolinked . A Match object is what is provided in a
* { @ link Autolinker # replaceFn replaceFn } , and may be used to query for details about the match .
*
* For example :
*
* var input = "..." ; // string with URLs, Email Addresses, and Twitter Handles
*
* var linkedText = Autolinker . link ( input , {
* replaceFn : function ( autolinker , match ) {
* console . log ( "href = " , match . getAnchorHref ( ) ) ;
* console . log ( "text = " , match . getAnchorText ( ) ) ;
*
* switch ( match . getType ( ) ) {
* case 'url' :
* console . log ( "url: " , match . getUrl ( ) ) ;
*
* case 'email' :
* console . log ( "email: " , match . getEmail ( ) ) ;
*
* case 'twitter' :
* console . log ( "twitter: " , match . getTwitterHandle ( ) ) ;
* }
* }
* } ) ;
*
* See the { @ link Autolinker } class for more details on using the { @ link Autolinker # replaceFn replaceFn } .
* /
Autolinker . match . Match = Autolinker . Util . extend ( Object , {
/ * *
* @ cfg { String } matchedText ( required )
*
* The original text that was matched .
* /
/ * *
* @ constructor
* @ param { Object } cfg The configuration properties for the Match instance , specified in an Object ( map ) .
* /
constructor : function ( cfg ) {
Autolinker . Util . assign ( this , cfg ) ;
} ,
/ * *
* Returns a string name for the type of match that this class represents .
*
* @ abstract
* @ return { String }
* /
getType : Autolinker . Util . abstractMethod ,
/ * *
* Returns the original text that was matched .
*
* @ return { String }
* /
getMatchedText : function ( ) {
return this . matchedText ;
} ,
/ * *
* Returns the anchor href that should be generated for the match .
*
* @ abstract
* @ return { String }
* /
getAnchorHref : Autolinker . Util . abstractMethod ,
/ * *
* Returns the anchor text that should be generated for the match .
*
* @ abstract
* @ return { String }
* /
getAnchorText : Autolinker . Util . abstractMethod
} ) ;
/*global Autolinker */
/ * *
* @ class Autolinker . match . Email
* @ extends Autolinker . match . Match
*
* Represents a Email match found in an input string which should be Autolinked .
*
* See this class ' s superclass ( { @ link Autolinker . match . Match } ) for more details .
* /
Autolinker . match . Email = Autolinker . Util . extend ( Autolinker . match . Match , {
/ * *
* @ cfg { String } email ( required )
*
* The email address that was matched .
* /
/ * *
* Returns a string name for the type of match that this class represents .
*
* @ return { String }
* /
getType : function ( ) {
return 'email' ;
} ,
/ * *
* Returns the email address that was matched .
*
* @ return { String }
* /
getEmail : function ( ) {
return this . email ;
} ,
/ * *
* Returns the anchor href that should be generated for the match .
*
* @ return { String }
* /
getAnchorHref : function ( ) {
return 'mailto:' + this . email ;
} ,
/ * *
* Returns the anchor text that should be generated for the match .
*
* @ return { String }
* /
getAnchorText : function ( ) {
return this . email ;
}
} ) ;
/*global Autolinker */
/ * *
* @ class Autolinker . match . Twitter
* @ extends Autolinker . match . Match
*
* Represents a Twitter match found in an input string which should be Autolinked .
*
* See this class ' s superclass ( { @ link Autolinker . match . Match } ) for more details .
* /
Autolinker . match . Twitter = Autolinker . Util . extend ( Autolinker . match . Match , {
/ * *
* @ cfg { String } twitterHandle ( required )
*
* The Twitter handle that was matched .
* /
/ * *
* Returns the type of match that this class represents .
*
* @ return { String }
* /
getType : function ( ) {
return 'twitter' ;
} ,
/ * *
* Returns a string name for the type of match that this class represents .
*
* @ return { String }
* /
getTwitterHandle : function ( ) {
return this . twitterHandle ;
} ,
/ * *
* Returns the anchor href that should be generated for the match .
*
* @ return { String }
* /
getAnchorHref : function ( ) {
return 'https://twitter.com/' + this . twitterHandle ;
} ,
/ * *
* Returns the anchor text that should be generated for the match .
*
* @ return { String }
* /
getAnchorText : function ( ) {
return '@' + this . twitterHandle ;
}
} ) ;
/*global Autolinker */
/ * *
* @ class Autolinker . match . Url
* @ extends Autolinker . match . Match
*
* Represents a Url match found in an input string which should be Autolinked .
*
* See this class ' s superclass ( { @ link Autolinker . match . Match } ) for more details .
* /
Autolinker . match . Url = Autolinker . Util . extend ( Autolinker . match . Match , {
/ * *
* @ cfg { String } url ( required )
*
* The url that was matched .
* /
/ * *
* @ cfg { Boolean } protocolUrlMatch ( required )
*
* ` true ` if the URL is a match which already has a protocol ( i . e . 'http://' ) , ` false ` if the match was from a 'www' or
* known TLD match .
* /
/ * *
* @ cfg { Boolean } protocolRelativeMatch ( required )
*
* ` true ` if the URL is a protocol - relative match . A protocol - relative match is a URL that starts with '//' ,
* and will be either http : // or https:// based on the protocol that the site is loaded under.
* /
/ * *
* @ cfg { Boolean } stripPrefix ( required )
* @ inheritdoc Autolinker # stripPrefix
* /
/ * *
* @ private
* @ property { RegExp } urlPrefixRegex
*
* A regular expression used to remove the 'http://' or 'https://' and / or the 'www.' from URLs .
* /
urlPrefixRegex : /^(https?:\/\/)?(www\.)?/i ,
/ * *
* @ private
* @ property { RegExp } protocolRelativeRegex
*
* The regular expression used to remove the protocol - relative '//' from the { @ link # url } string , for purposes
* of { @ link # getAnchorText } . A protocol - relative URL is , for example , "//yahoo.com"
* /
protocolRelativeRegex : /^\/\// ,
/ * *
* @ private
* @ property { Boolean } protocolPrepended
*
* Will be set to ` true ` if the 'http://' protocol has been prepended to the { @ link # url } ( because the
* { @ link # url } did not have a protocol )
* /
protocolPrepended : false ,
/ * *
* Returns a string name for the type of match that this class represents .
*
* @ return { String }
* /
getType : function ( ) {
return 'url' ;
} ,
/ * *
* Returns the url that was matched , assuming the protocol to be 'http://' if the original
* match was missing a protocol .
*
* @ return { String }
* /
getUrl : function ( ) {
var url = this . url ;
// if the url string doesn't begin with a protocol, assume 'http://'
if ( ! this . protocolRelativeMatch && ! this . protocolUrlMatch && ! this . protocolPrepended ) {
url = this . url = 'http://' + url ;
this . protocolPrepended = true ;
}
return url ;
} ,
/ * *
* Returns the anchor href that should be generated for the match .
*
* @ return { String }
* /
getAnchorHref : function ( ) {
var url = this . getUrl ( ) ;
return url . replace ( /&/g , '&' ) ; // any &'s in the URL should be converted back to '&' if they were displayed as & in the source html
} ,
/ * *
* Returns the anchor text that should be generated for the match .
*
* @ return { String }
* /
getAnchorText : function ( ) {
var anchorText = this . getUrl ( ) ;
if ( this . protocolRelativeMatch ) {
// Strip off any protocol-relative '//' from the anchor text
anchorText = this . stripProtocolRelativePrefix ( anchorText ) ;
}
if ( this . stripPrefix ) {
anchorText = this . stripUrlPrefix ( anchorText ) ;
}
anchorText = this . removeTrailingSlash ( anchorText ) ; // remove trailing slash, if there is one
return anchorText ;
} ,
// ---------------------------------------
// Utility Functionality
/ * *
* Strips the URL prefix ( such as "http://" or "https://" ) from the given text .
*
* @ private
* @ param { String } text The text of the anchor that is being generated , for which to strip off the
* url prefix ( such as stripping off "http://" )
* @ return { String } The ` anchorText ` , with the prefix stripped .
* /
stripUrlPrefix : function ( text ) {
return text . replace ( this . urlPrefixRegex , '' ) ;
} ,
/ * *
* Strips any protocol - relative '//' from the anchor text .
*
* @ private
* @ param { String } text The text of the anchor that is being generated , for which to strip off the
* protocol - relative prefix ( such as stripping off "//" )
* @ return { String } The ` anchorText ` , with the protocol - relative prefix stripped .
* /
stripProtocolRelativePrefix : function ( text ) {
return text . replace ( this . protocolRelativeRegex , '' ) ;
} ,
/ * *
* Removes any trailing slash from the given ` anchorText ` , in preparation for the text to be displayed .
*
* @ private
* @ param { String } anchorText The text of the anchor that is being generated , for which to remove any trailing
* slash ( '/' ) that may exist .
* @ return { String } The ` anchorText ` , with the trailing slash removed .
* /
removeTrailingSlash : function ( anchorText ) {
if ( anchorText . charAt ( anchorText . length - 1 ) === '/' ) {
anchorText = anchorText . slice ( 0 , - 1 ) ;
}
return anchorText ;
}
} ) ;
return Autolinker ;
} ) ) ;
} , { } ] , "/" : [ function ( require , module , exports ) {
'use strict' ;
module . exports = require ( './lib/' ) ;
} , { "./lib/" : 14 } ] } , { } , [ ] ) ( "/" )
} ) ;